diff --git a/.gitignore b/.gitignore index 4f6d201a..aabb8cee 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,8 @@ VISION_KEY .vs/slnx.sqlite .vs/VSWorkspaceState.json **/.vscode/* +**/.idea/* +**/rider.* **/*.csproj.user src/app/bin/Debug/net6.0-windows/* src/app/bin/Release/net6.0-windows/* @@ -50,6 +52,9 @@ src/maui/bin/Release/net6.0-windows/* src/maui/obj/* src/maui/obj/Debug/net6.0-windows/* src/maui/obj/Release/net6.0-windows/* +src/samples/**/obj/** +src/samples/**/bin/** +src/samples/**/.vs/** src/win32_native/keyboard_hook/*.vcxproj.user src/win32_native/keyboard_hook/x64/** src/win32_setup/Debug/* diff --git a/src/cs/Command/Command.cs b/src/cs/Command/Command.cs index 884304ca..b58baeb3 100644 --- a/src/cs/Command/Command.cs +++ b/src/cs/Command/Command.cs @@ -1,56 +1,61 @@ -namespace macaroni; +using System; +using System.Collections.Generic; +using System.Linq; +using YamlDotNet.RepresentationModel; -internal class Command : ICommand, INotifyCondition, ILoadedFromYamlFile +namespace macaroni { - public string Id { get { return GetId(); }} + internal class Command : ICommand, INotifyCondition, ILoadedFromYamlFile + { + public string Id { get { return GetId(); } } - public string? Name { get; internal set; } - public IEnumerable? Examples { get; internal set; } + public string? Name { get; internal set; } + public IEnumerable? Examples { get; internal set; } - public IConditionCollection? Conditions { get; internal set; } - public ITriggerCollection? Triggers { get; internal set; } - public IExecutorCollection? Executors { get; internal set; } - public ITriggerCollection? Expecting { get; internal set; } - public IUnexpectedDialogPolicy? Unexpected { get; internal set; } + public IConditionCollection? Conditions { get; internal set; } + public ITriggerCollection? Triggers { get; internal set; } + public IExecutorCollection? Executors { get; internal set; } + public ITriggerCollection? Expecting { get; internal set; } + public IUnexpectedDialogPolicy? Unexpected { get; internal set; } - public YamlNode? Yaml { get; internal set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } + public YamlNode? Yaml { get; internal set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - bool ICondition.IsSatisfied(IResolutionContext? context) - { - return _satisfied; - } + bool ICondition.IsSatisfied(IResolutionContext? context) + { + return _satisfied; + } - void ILoadedFromYamlFile.LoadComplete(object parent) - { - YamlParent = parent; - - (Conditions as ILoadedFromYamlFile)?.LoadComplete(this); - (Triggers as ILoadedFromYamlFile)?.LoadComplete(this); - (Executors as ILoadedFromYamlFile)?.LoadComplete(this); - (Expecting as ILoadedFromYamlFile)?.LoadComplete(this); - - _satisfied = CheckSatisfied(); - } + void ILoadedFromYamlFile.LoadComplete(object parent) + { + YamlParent = parent; - public void Unload() - { - (Conditions as ILoadedFromYamlFile)?.Unload(); - (Triggers as ILoadedFromYamlFile)?.Unload(); - (Executors as ILoadedFromYamlFile)?.Unload(); - (Expecting as ILoadedFromYamlFile)?.Unload(); - } + (Conditions as ILoadedFromYamlFile)?.LoadComplete(this); + (Triggers as ILoadedFromYamlFile)?.LoadComplete(this); + (Executors as ILoadedFromYamlFile)?.LoadComplete(this); + (Expecting as ILoadedFromYamlFile)?.LoadComplete(this); - void INotifyCondition.ConditionChanged(ICondition condition) - { - var satisfied = CheckSatisfied(); - if (satisfied != _satisfied) + _satisfied = CheckSatisfied(); + } + + public void Unload() { - _satisfied = satisfied; - NotifyConditionChanged(); + (Conditions as ILoadedFromYamlFile)?.Unload(); + (Triggers as ILoadedFromYamlFile)?.Unload(); + (Executors as ILoadedFromYamlFile)?.Unload(); + (Expecting as ILoadedFromYamlFile)?.Unload(); + } + + void INotifyCondition.ConditionChanged(ICondition condition) + { + var satisfied = CheckSatisfied(); + if (satisfied != _satisfied) + { + _satisfied = satisfied; + NotifyConditionChanged(); + } } - } IExecutionContext ICommand.GetExecutionContext() { @@ -100,43 +105,44 @@ public void ClearContext() PersistContext(null, null, null); } - private string GetId() - { - if (_id == null) + private string GetId() { - _id = Yaml != null ? GetYamlId() : GetNextSequentialId(); - _id = _id.Replace("\\", "/"); + if (_id == null) + { + _id = Yaml != null ? GetYamlId() : GetNextSequentialId(); + _id = _id.Replace("\\", "/"); + } + return _id; } - return _id; - } - private string GetYamlId() - { - var id = $"{YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"; - return !string.IsNullOrEmpty(Name) ? $"{id}:{Name}" : id; - } + private string GetYamlId() + { + var id = $"{YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"; + return !string.IsNullOrEmpty(Name) ? $"{id}:{Name}" : id; + } - private string GetNextSequentialId() - { - _nextSequentialId++; - return $"Command{_nextSequentialId}"; - } + private string GetNextSequentialId() + { + _nextSequentialId++; + return $"Command{_nextSequentialId}"; + } - private bool CheckSatisfied() - { - return Conditions?.All(condition => condition.IsSatisfied()) ?? true; - } + private bool CheckSatisfied() + { + return Conditions?.All(condition => condition.IsSatisfied()) ?? true; + } - private void NotifyConditionChanged() - { - var notify = YamlParent as INotifyCondition; - notify?.ConditionChanged(this); - } + private void NotifyConditionChanged() + { + var notify = YamlParent as INotifyCondition; + notify?.ConditionChanged(this); + } - private string? _id; - private bool _satisfied = false; + private string? _id; + private bool _satisfied = false; - private IExecutionContext? _persistentContext; + private IExecutionContext? _persistentContext; - private static int _nextSequentialId = 0; -} + private static int _nextSequentialId = 0; + } +} \ No newline at end of file diff --git a/src/cs/Command/Conditions/AllCondition.cs b/src/cs/Command/Conditions/AllCondition.cs index 20fc661f..69d01cf0 100644 --- a/src/cs/Command/Conditions/AllCondition.cs +++ b/src/cs/Command/Conditions/AllCondition.cs @@ -1,5 +1,7 @@ -namespace macaroni; - -internal class AllCondition : ConditionsOperationBase +namespace macaroni { -} + + internal class AllCondition : ConditionsOperationBase + { + } +} \ No newline at end of file diff --git a/src/cs/Command/Conditions/AllConditionYamlParser.cs b/src/cs/Command/Conditions/AllConditionYamlParser.cs index 4fa1b87e..d542d73b 100644 --- a/src/cs/Command/Conditions/AllConditionYamlParser.cs +++ b/src/cs/Command/Conditions/AllConditionYamlParser.cs @@ -1,7 +1,11 @@ -namespace macaroni; +using System; -internal class AllConditionYamlParser : ConditionsOperationYamlParserBase, IConditionYamlParser +namespace macaroni { - public AllConditionYamlParser(IServiceProvider services, ISystemContext context) : base(services, ConditionCollectionEvaluationOperation.All, context) { } - public override string Kind { get { return "all"; } } -} + + internal class AllConditionYamlParser : ConditionsOperationYamlParserBase, IConditionYamlParser + { + public AllConditionYamlParser(IServiceProvider services, ISystemContext context) : base(services, ConditionCollectionEvaluationOperation.All, context) { } + public override string Kind { get { return "all"; } } + } +} \ No newline at end of file diff --git a/src/cs/Command/Conditions/AnyCondition.cs b/src/cs/Command/Conditions/AnyCondition.cs index 476af486..b9044deb 100644 --- a/src/cs/Command/Conditions/AnyCondition.cs +++ b/src/cs/Command/Conditions/AnyCondition.cs @@ -1,5 +1,6 @@ -namespace macaroni; - -internal class AnyCondition : ConditionsOperationBase +namespace macaroni { -} + internal class AnyCondition : ConditionsOperationBase + { + } +} \ No newline at end of file diff --git a/src/cs/Command/Conditions/AnyConditionYamlParser.cs b/src/cs/Command/Conditions/AnyConditionYamlParser.cs index 1ca7afe0..3d66ac11 100644 --- a/src/cs/Command/Conditions/AnyConditionYamlParser.cs +++ b/src/cs/Command/Conditions/AnyConditionYamlParser.cs @@ -1,7 +1,10 @@ -namespace macaroni; +using System; -internal class AnyConditionYamlParser : ConditionsOperationYamlParserBase, IConditionYamlParser +namespace macaroni { - public AnyConditionYamlParser(IServiceProvider services, ISystemContext context) : base(services, ConditionCollectionEvaluationOperation.Any, context) { } - public override string Kind { get { return "any"; } } -} + internal class AnyConditionYamlParser : ConditionsOperationYamlParserBase, IConditionYamlParser + { + public AnyConditionYamlParser(IServiceProvider services, ISystemContext context) : base(services, ConditionCollectionEvaluationOperation.Any, context) { } + public override string Kind { get { return "any"; } } + } +} \ No newline at end of file diff --git a/src/cs/Command/Conditions/AppCondition.cs b/src/cs/Command/Conditions/AppCondition.cs index cf54d3a2..ee5f33ff 100644 --- a/src/cs/Command/Conditions/AppCondition.cs +++ b/src/cs/Command/Conditions/AppCondition.cs @@ -1,97 +1,100 @@ -using System.Diagnostics; +using System.Collections.Generic; +using System.Linq; +using YamlDotNet.RepresentationModel; -namespace macaroni; - -internal class AppCondition : ICondition, ILoadedFromYamlFile +namespace macaroni { - public AppCondition() + internal class AppCondition : ICondition, ILoadedFromYamlFile { - } + public AppCondition() + { + } - public string? Title { get; set; } - public string? Process { get; set; } - public string? TitleOrProcess { get; set; } + public string? Title { get; set; } + public string? Process { get; set; } + public string? TitleOrProcess { get; set; } - public bool? Focus { get; set; } - public bool? Running { get; set; } + public bool? Focus { get; set; } + public bool? Running { get; set; } - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public bool IsSatisfied(IResolutionContext? context) - { - if (Focus != null && _focused == Focus.Value) return true; - if (Running != null && _running == Running.Value) return true; - return false; - } - - public void LoadComplete(object parent) - { - YamlParent = parent; + public bool IsSatisfied(IResolutionContext? context) + { + if (Focus != null && _focused == Focus.Value) return true; + if (Running != null && _running == Running.Value) return true; + return false; + } - if (OS.IsWindows() && !this.IsEditorDesignMode()) + public void LoadComplete(object parent) { - ForceCheckFocus(); - ForceCheckRunning(); + YamlParent = parent; + + if (OS.IsWindows() && !this.IsEditorDesignMode()) + { + ForceCheckFocus(); + ForceCheckRunning(); - _monitor = this.GetParentOrService(); - _monitor?.StartNotify((_, info) => CheckFocus(info), (o, n) => CheckRunning(n.Values)); + _monitor = this.GetParentOrService(); + _monitor?.StartNotify((_, info) => CheckFocus(info), (o, n) => CheckRunning(n.Values)); + } } - } - public void Unload() - { - _monitor?.StopNotify(); - } + public void Unload() + { + _monitor?.StopNotify(); + } - private void ForceCheckFocus() - { - var info = WindowInfo.FromHwnd(window_interop.GetForegroundWindow()); - if (info != null) CheckFocus(info, false); - } + private void ForceCheckFocus() + { + var info = WindowInfo.FromHwnd(window_interop.GetForegroundWindow()); + if (info != null) CheckFocus(info, false); + } - private void ForceCheckRunning() - { - var windows = WindowInfo.GetVisibleWindows(); - CheckRunning(windows.Values, false); - } + private void ForceCheckRunning() + { + var windows = WindowInfo.GetVisibleWindows(); + CheckRunning(windows.Values, false); + } - private void CheckFocus(WindowInfo info, bool notify = true) - { - if (Focus != null) + private void CheckFocus(WindowInfo info, bool notify = true) { - var focused = WindowInfo.TitleAndProcessMatch(info, TitleOrProcess, Title, Process, null); - if (focused != _focused) + if (Focus != null) { - _focused = focused; - MR.DBG_TRACE_VERBOSE($"app (focus={Title ?? TitleOrProcess ?? Process}): {focused}"); - if (notify) NotifyConditionChanged(); + var focused = WindowInfo.TitleAndProcessMatch(info, TitleOrProcess, Title, Process, null); + if (focused != _focused) + { + _focused = focused; + MR.DBG_TRACE_VERBOSE($"app (focus={Title ?? TitleOrProcess ?? Process}): {focused}"); + if (notify) NotifyConditionChanged(); + } } } - } - private void CheckRunning(IEnumerable windows, bool notify = true) - { - if (Focus == null && Running != null) + private void CheckRunning(IEnumerable windows, bool notify = true) { - var running = windows.Any(info => WindowInfo.TitleAndProcessMatch(info, TitleOrProcess, Title, Process, null)); - if (running != _running) + if (Focus == null && Running != null) { - _running = running; - MR.DBG_TRACE_VERBOSE($"app (running={Running}, match={Title ?? TitleOrProcess ?? Process}): {running}"); - if (notify) NotifyConditionChanged(); + var running = windows.Any(info => WindowInfo.TitleAndProcessMatch(info, TitleOrProcess, Title, Process, null)); + if (running != _running) + { + _running = running; + MR.DBG_TRACE_VERBOSE($"app (running={Running}, match={Title ?? TitleOrProcess ?? Process}): {running}"); + if (notify) NotifyConditionChanged(); + } } } - } - private void NotifyConditionChanged() - { - var notify = YamlParent as INotifyCondition; - notify?.ConditionChanged(this); - } + private void NotifyConditionChanged() + { + var notify = YamlParent as INotifyCondition; + notify?.ConditionChanged(this); + } - private bool _focused = false; - private bool _running = false; - private IWindowMonitoringService? _monitor; -} + private bool _focused = false; + private bool _running = false; + private IWindowMonitoringService? _monitor; + } +} \ No newline at end of file diff --git a/src/cs/Command/Conditions/AppConditionYamlParser.cs b/src/cs/Command/Conditions/AppConditionYamlParser.cs index af39c715..8166a42f 100644 --- a/src/cs/Command/Conditions/AppConditionYamlParser.cs +++ b/src/cs/Command/Conditions/AppConditionYamlParser.cs @@ -1,11 +1,13 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class AppConditionYamlParser : ConditionYamlParserBase +namespace macaroni { - public AppConditionYamlParser(ISystemContext context) : base(context) { } + internal class AppConditionYamlParser : ConditionYamlParserBase + { + public AppConditionYamlParser(ISystemContext context) : base(context) { } - public override string Kind { get { return "app"; } } - public override bool RequireScalarRhsNotNull => false; + public override string Kind { get { return "app"; } } + public override bool RequireScalarRhsNotNull => false; protected override ICondition ParseMapping(string file, YamlMappingNode mapping, string? scalar, IParsedValueWarningChecker? warnings) { @@ -15,28 +17,29 @@ protected override ICondition ParseMapping(string file, YamlMappingNode mapping, var focus = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "focus", warnings); var running = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "running", warnings); - RequireNoUnexpectedMappingKeys(file, mapping, Kind, new[] { "title", "process", "focus", "running" }); - - if (string.IsNullOrEmpty(title) && string.IsNullOrEmpty(process) && string.IsNullOrEmpty(titleOrProcess)) - { - var expected = $"`title: (string)` or `process: (string)`"; - throw ErrorParsingYamlException(file, mapping.Start.Line, mapping.Start.Column, "Unexpected `app` mapping", $"EXPECTED: {expected}"); + RequireNoUnexpectedMappingKeys(file, mapping, Kind, new[] { "title", "process", "focus", "running" }); + + if (string.IsNullOrEmpty(title) && string.IsNullOrEmpty(process) && string.IsNullOrEmpty(titleOrProcess)) + { + var expected = $"`title: (string)` or `process: (string)`"; + throw ErrorParsingYamlException(file, mapping.Start.Line, mapping.Start.Column, "Unexpected `app` mapping", $"EXPECTED: {expected}"); + } + + var focusOk = bool.TryParse(focus, out bool focusValue); + var runningOk = bool.TryParse(running, out bool runningValue); + + var condition = new AppCondition() + { + TitleOrProcess = titleOrProcess, + Title = title, + Process = process, + Focus = focusOk ? focusValue : (runningOk ? (bool?)null : true), + Running = runningOk ? runningValue : (focusOk ? (bool?)null : true), + Yaml = mapping, + YamlFile = file + }; + + return condition; } - - var focusOk = bool.TryParse(focus, out bool focusValue); - var runningOk = bool.TryParse(running, out bool runningValue); - - var condition = new AppCondition() - { - TitleOrProcess = titleOrProcess, - Title = title, - Process = process, - Focus = focusOk ? focusValue : (runningOk ? null : true), - Running = runningOk ? runningValue : (focusOk ? null : true), - Yaml = mapping, - YamlFile = file - }; - - return condition; } -} +} \ No newline at end of file diff --git a/src/cs/Command/Conditions/ComputerNameCondition.cs b/src/cs/Command/Conditions/ComputerNameCondition.cs index 73b4dd0b..32da6bdf 100644 --- a/src/cs/Command/Conditions/ComputerNameCondition.cs +++ b/src/cs/Command/Conditions/ComputerNameCondition.cs @@ -1,27 +1,29 @@ -using System.Diagnostics; +using System; +using YamlDotNet.RepresentationModel; -namespace macaroni; - -internal class ComputerNameCondition : ICondition, ILoadedFromYamlFile +namespace macaroni { - public string? Value { get; set; } + internal class ComputerNameCondition : ICondition, ILoadedFromYamlFile + { + public string? Value { get; set; } - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public bool IsSatisfied(IResolutionContext? context) - { - var resolved = context == null ? Value : context.Resolve(Value, true); - return Environment.MachineName == resolved?.ToLower(); - } + public bool IsSatisfied(IResolutionContext? context) + { + var resolved = context == null ? Value : context.Resolve(Value, true); + return Environment.MachineName == resolved?.ToLower(); + } - public void LoadComplete(object parent) - { - YamlParent = parent; - } + public void LoadComplete(object parent) + { + YamlParent = parent; + } - public void Unload() - { + public void Unload() + { + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Conditions/ComputerNameConditionYamlParser.cs b/src/cs/Command/Conditions/ComputerNameConditionYamlParser.cs index 86ffbf38..3fab9477 100644 --- a/src/cs/Command/Conditions/ComputerNameConditionYamlParser.cs +++ b/src/cs/Command/Conditions/ComputerNameConditionYamlParser.cs @@ -1,21 +1,32 @@ -namespace macaroni; +using System; +using YamlDotNet.RepresentationModel; -internal class ComputerNameConditionYamlParser : ConditionYamlParserBase +namespace macaroni { - public ComputerNameConditionYamlParser(ISystemContext context) : base(context) { } + internal class ComputerNameConditionYamlParser : ConditionYamlParserBase + { + public ComputerNameConditionYamlParser(ISystemContext context) : base(context) + { + } - public override string Kind { get { return "computer"; } } - public override bool TryMappingRhs => false; + public override string Kind + { + get { return "computer"; } + } - protected override ICondition ParseMapping(string file, YamlMappingNode mapping, string? scalar, IParsedValueWarningChecker? warnings) - { - RequireNoUnexpectedMappingKeys(file, mapping, Kind, Array.Empty()); + public override bool TryMappingRhs => false; - return new ComputerNameCondition() + protected override ICondition ParseMapping(string file, YamlMappingNode mapping, string? scalar, + IParsedValueWarningChecker? warnings) { - Value = scalar, - Yaml = mapping, - YamlFile = file - }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, Array.Empty()); + + return new ComputerNameCondition() + { + Value = scalar, + Yaml = mapping, + YamlFile = file + }; + } } } diff --git a/src/cs/Command/Conditions/Condition.cs b/src/cs/Command/Conditions/Condition.cs index 8c786a88..ce6cb781 100644 --- a/src/cs/Command/Conditions/Condition.cs +++ b/src/cs/Command/Conditions/Condition.cs @@ -1,112 +1,115 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class Condition : ICondition, ILoadedFromYamlFile +namespace macaroni { - public string? Value { get; set; } - - public YamlNode? Yaml { get; internal set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public bool IsSatisfied(IResolutionContext? context) + internal class Condition : ICondition, ILoadedFromYamlFile { - if (context == null || Value == null) return false; - - var resolved = context.Resolve(Value, true); - return resolved != null && EvalConditionValue(resolved); - } + public string? Value { get; set; } - public void LoadComplete(object parent) - { - YamlParent = parent; - } + public YamlNode? Yaml { get; internal set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public void Unload() - { - } + public bool IsSatisfied(IResolutionContext? context) + { + if (context == null || Value == null) return false; - private bool EvalConditionValue(string eval) - { - object a, b; - if (ParseComparison(eval, "<=", out a, out b)) return EvalLte(a, b); - if (ParseComparison(eval, "==", out a, out b)) return EvalEq(a, b); - if (ParseComparison(eval, "!=", out a, out b)) return !EvalEq(a, b); - if (ParseComparison(eval, ">=", out a, out b)) return EvalGte(a, b); + var resolved = context.Resolve(Value, true); + return resolved != null && EvalConditionValue(resolved); + } - if (ParseComparison(eval, "<", out a, out b)) return EvalLt(a, b); - if (ParseComparison(eval, ">", out a, out b)) return EvalGt(a, b); + public void LoadComplete(object parent) + { + YamlParent = parent; + } - return false; - } + public void Unload() + { + } - private bool ParseComparison(string s, string op, out object a, out object b) - { - var at = s.IndexOf(op); - if (at < 0) + private bool EvalConditionValue(string eval) { - a = 0; - b = 0; + object a, b; + if (ParseComparison(eval, "<=", out a, out b)) return EvalLte(a, b); + if (ParseComparison(eval, "==", out a, out b)) return EvalEq(a, b); + if (ParseComparison(eval, "!=", out a, out b)) return !EvalEq(a, b); + if (ParseComparison(eval, ">=", out a, out b)) return EvalGte(a, b); + + if (ParseComparison(eval, "<", out a, out b)) return EvalLt(a, b); + if (ParseComparison(eval, ">", out a, out b)) return EvalGt(a, b); + return false; } - var sa = s.Substring(0, at).Trim(); - var sb = s.Substring(at + op.Length).Trim(); - - if (double.TryParse(sa, out var da) && - double.TryParse(sb, out var db)) + private bool ParseComparison(string s, string op, out object a, out object b) { - a = da; - b = db; + var at = s.IndexOf(op); + if (at < 0) + { + a = 0; + b = 0; + return false; + } + + var sa = s.Substring(0, at).Trim(); + var sb = s.Substring(at + op.Length).Trim(); + + if (double.TryParse(sa, out var da) && + double.TryParse(sb, out var db)) + { + a = da; + b = db; + return true; + } + + a = sa; + b = sb; return true; } - a = sa; - b = sb; - return true; - } - - private bool EvalLte(object a, object b) - { - return a is double && b is double - ? (double)(a) <= (double)(b) - : a is string && b is string - ? string.Compare(a as string, b as string) <= 0 - : false; - } + private bool EvalLte(object a, object b) + { + return a is double && b is double + ? (double)(a) <= (double)(b) + : a is string && b is string + ? string.Compare(a as string, b as string) <= 0 + : false; + } - private bool EvalEq(object a, object b) - { - return a is double && b is double - ? (double)(a) == (double)(b) - : a is string && b is string - ? string.Compare(a as string, b as string) == 0 - : false; - } + private bool EvalEq(object a, object b) + { + return a is double && b is double + ? (double)(a) == (double)(b) + : a is string && b is string + ? string.Compare(a as string, b as string) == 0 + : false; + } - private bool EvalGte(object a, object b) - { - return a is double && b is double - ? (double)(a) >= (double)(b) - : a is string && b is string - ? string.Compare(a as string, b as string) >= 0 - : false; - } + private bool EvalGte(object a, object b) + { + return a is double && b is double + ? (double)(a) >= (double)(b) + : a is string && b is string + ? string.Compare(a as string, b as string) >= 0 + : false; + } - private bool EvalLt(object a, object b) - { - return a is double && b is double - ? (double)(a) < (double)(b) - : a is string && b is string - ? string.Compare(a as string, b as string) < 0 - : false; - } + private bool EvalLt(object a, object b) + { + return a is double && b is double + ? (double)(a) < (double)(b) + : a is string && b is string + ? string.Compare(a as string, b as string) < 0 + : false; + } - private bool EvalGt(object a, object b) - { - return a is double && b is double - ? (double)(a) > (double)(b) - : a is string && b is string - ? string.Compare(a as string, b as string) > 0 - : false; + private bool EvalGt(object a, object b) + { + return a is double && b is double + ? (double)(a) > (double)(b) + : a is string && b is string + ? string.Compare(a as string, b as string) > 0 + : false; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Conditions/ConditionCollection.cs b/src/cs/Command/Conditions/ConditionCollection.cs index 7aa533d5..74eabcbc 100644 --- a/src/cs/Command/Conditions/ConditionCollection.cs +++ b/src/cs/Command/Conditions/ConditionCollection.cs @@ -1,75 +1,80 @@ -namespace macaroni; +using System.Collections.Generic; +using System.Linq; +using YamlDotNet.RepresentationModel; -internal class ConditionCollection : List, IConditionCollection, INotifyCondition, ILoadedFromYamlFile +namespace macaroni { - public ConditionCollection(IEnumerable conditions) : base(conditions) + internal class ConditionCollection : List, IConditionCollection, INotifyCondition, ILoadedFromYamlFile { - Operation = ConditionCollectionEvaluationOperation.All; - } + public ConditionCollection(IEnumerable conditions) : base(conditions) + { + Operation = ConditionCollectionEvaluationOperation.All; + } - public ConditionCollectionEvaluationOperation Operation { get; set; } + public ConditionCollectionEvaluationOperation Operation { get; set; } - public YamlNode? Yaml { get; internal set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } + public YamlNode? Yaml { get; internal set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public bool IsSatisfied(IResolutionContext? context) - { - if (context != null) ReCheck(context); + public bool IsSatisfied(IResolutionContext? context) + { + if (context != null) ReCheck(context); - return _satisfied; - } + return _satisfied; + } - public void LoadComplete(object parent) - { - YamlParent = parent; - if (Yaml == null) Yaml = (parent as ILoadedFromYamlFile)?.Yaml; - if (YamlFile == null) YamlFile = (parent as ILoadedFromYamlFile)?.YamlFile; + public void LoadComplete(object parent) + { + YamlParent = parent; + if (Yaml == null) Yaml = (parent as ILoadedFromYamlFile)?.Yaml; + if (YamlFile == null) YamlFile = (parent as ILoadedFromYamlFile)?.YamlFile; - this.ForEach(x => (x as ILoadedFromYamlFile)?.LoadComplete(this)); + this.ForEach(x => (x as ILoadedFromYamlFile)?.LoadComplete(this)); + + if (!this.IsEditorDesignMode()) + { + _satisfied = CheckSatisfied(); + } + } - if (!this.IsEditorDesignMode()) + public void Unload() { - _satisfied = CheckSatisfied(); + this.ForEach(x => (x as ILoadedFromYamlFile)?.Unload()); } - } - public void Unload() - { - this.ForEach(x => (x as ILoadedFromYamlFile)?.Unload()); - } + public void ConditionChanged(ICondition condition) + { + ReCheck(); + } - public void ConditionChanged(ICondition condition) - { - ReCheck(); - } + private void ReCheck(IResolutionContext? context = null) + { + var satisfied = CheckSatisfied(context); + if (satisfied != _satisfied) + { + _satisfied = satisfied; + NotifyConditionChanged(); + } + } - private void ReCheck(IResolutionContext? context = null) - { - var satisfied = CheckSatisfied(context); - if (satisfied != _satisfied) + private bool CheckSatisfied(IResolutionContext? context = null) { - _satisfied = satisfied; - NotifyConditionChanged(); + return Operation switch + { + ConditionCollectionEvaluationOperation.All => this.All(condition => condition.IsSatisfied(context)), + ConditionCollectionEvaluationOperation.Any => this.Any(condition => condition.IsSatisfied(context)), + ConditionCollectionEvaluationOperation.None => !this.Any(condition => condition.IsSatisfied(context)), + _ => false + }; } - } - private bool CheckSatisfied(IResolutionContext? context = null) - { - return Operation switch + private void NotifyConditionChanged() { - ConditionCollectionEvaluationOperation.All => this.All(condition => condition.IsSatisfied(context)), - ConditionCollectionEvaluationOperation.Any => this.Any(condition => condition.IsSatisfied(context)), - ConditionCollectionEvaluationOperation.None => !this.Any(condition => condition.IsSatisfied(context)), - _ => false - }; - } + var notify = YamlParent as INotifyCondition; + notify?.ConditionChanged(this); + } - private void NotifyConditionChanged() - { - var notify = YamlParent as INotifyCondition; - notify?.ConditionChanged(this); + private bool _satisfied = false; } - - private bool _satisfied = false; -} +} \ No newline at end of file diff --git a/src/cs/Command/Conditions/ConditionCollectionYamlParser.cs b/src/cs/Command/Conditions/ConditionCollectionYamlParser.cs index aaa14e87..89baaeb5 100644 --- a/src/cs/Command/Conditions/ConditionCollectionYamlParser.cs +++ b/src/cs/Command/Conditions/ConditionCollectionYamlParser.cs @@ -1,11 +1,13 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class ConditionCollectionYamlParser : YamlParserBase, IConditionCollectionYamlParser +namespace macaroni { - public ConditionCollectionYamlParser(IConditionFactory factory, ISystemContext context) : base(context) + internal class ConditionCollectionYamlParser : YamlParserBase, IConditionCollectionYamlParser { - _factory = factory; - } + public ConditionCollectionYamlParser(IConditionFactory factory, ISystemContext context) : base(context) + { + _factory = factory; + } public IConditionCollection? CheckForConditions(string file, YamlMappingNode mapping, string conditionsMappingName, IParsedValueWarningChecker? warnings) { @@ -24,12 +26,13 @@ public IConditionCollection ConditionsFromSequence(string file, YamlSequenceNode (file, node) => _factory.ConditionFromYamlNode(file, node, warnings), (file, node) => ErrorUnexpectedNode(file, node, _factory.GetValidConditionMappingTypes())); - return new ConditionCollection(conditions) - { - Yaml = sequence, - YamlFile = file - }; - } + return new ConditionCollection(conditions) + { + Yaml = sequence, + YamlFile = file + }; + } - private readonly IConditionFactory _factory; -} + private readonly IConditionFactory _factory; + } +} \ No newline at end of file diff --git a/src/cs/Command/Conditions/ConditionFactory.cs b/src/cs/Command/Conditions/ConditionFactory.cs index 83af04d2..c5c05ccd 100644 --- a/src/cs/Command/Conditions/ConditionFactory.cs +++ b/src/cs/Command/Conditions/ConditionFactory.cs @@ -1,19 +1,23 @@ -namespace macaroni; +using System.Collections.Generic; +using System.Linq; +using YamlDotNet.RepresentationModel; -internal class ConditionFactory : YamlParserBase, IConditionFactory +namespace macaroni { - public ConditionFactory(IEnumerable parsers, ISystemContext context) : base(context) + internal class ConditionFactory : YamlParserBase, IConditionFactory { - _parsers = parsers; - } + public ConditionFactory(IEnumerable parsers, ISystemContext context) : base(context) + { + _parsers = parsers; + } - public bool IsInvalidConditionNode(YamlMappingNode mapping) - { - var count = mapping.Children - .Count(x => _validConditionMappingTypeKeys - .Contains((x.Key as YamlScalarNode)?.Value)); - return count == 0; - } + public bool IsInvalidConditionNode(YamlMappingNode mapping) + { + var count = mapping.Children + .Count(x => _validConditionMappingTypeKeys + .Contains((x.Key as YamlScalarNode)?.Value)); + return count == 0; + } public ICondition ConditionFromYamlNode(string file, YamlNode node, IParsedValueWarningChecker? warnings) { @@ -27,10 +31,10 @@ public ICondition ConditionFromYamlNode(string file, YamlNode node, IParsedValue return ParseConditionFromMapping(file, mapping, warnings); } - public string GetValidConditionMappingTypes() - { - return string.Join(", ", _validConditionMappingTypeKeys); - } + public string GetValidConditionMappingTypes() + { + return string.Join(", ", _validConditionMappingTypeKeys); + } private ICondition ParseConditionFromMapping(string file, YamlMappingNode mapping, IParsedValueWarningChecker? warnings) { @@ -42,10 +46,11 @@ private ICondition ParseConditionFromMapping(string file, YamlMappingNode mappin } } - return new Condition() { Yaml = mapping, YamlFile = file }; - } + return new Condition() { Yaml = mapping, YamlFile = file }; + } - private IEnumerable _parsers; + private IEnumerable _parsers; - private static IEnumerable _validConditionMappingTypeKeys = new string[] { "all", "any", "app", "clipboard", "control", "condition", "environment", "file", "global", "input", "javascript", "missing", "none", "not", "platform", "required", "script", "user", "computer" }; -} + private static IEnumerable _validConditionMappingTypeKeys = new string[] { "all", "any", "app", "clipboard", "control", "condition", "environment", "file", "global", "input", "javascript", "missing", "none", "not", "platform", "required", "script", "user", "computer" }; + } +} \ No newline at end of file diff --git a/src/cs/Command/Conditions/ConditionYamlParser.cs b/src/cs/Command/Conditions/ConditionYamlParser.cs index 002e7bc4..bcd9f848 100644 --- a/src/cs/Command/Conditions/ConditionYamlParser.cs +++ b/src/cs/Command/Conditions/ConditionYamlParser.cs @@ -1,20 +1,30 @@ -namespace macaroni; +using System; +using YamlDotNet.RepresentationModel; -internal class ConditionYamlParser : ConditionYamlParserBase +namespace macaroni { - public ConditionYamlParser(ISystemContext context) : base(context) { } + internal class ConditionYamlParser : ConditionYamlParserBase + { + public ConditionYamlParser(ISystemContext context) : base(context) + { + } - public override string Kind { get { return "condition"; } } - public override bool TryMappingRhs => false; + public override string Kind + { + get { return "condition"; } + } - protected override ICondition ParseMapping(string file, YamlMappingNode mapping, string? scalar, IParsedValueWarningChecker? warnings) - { - RequireNoUnexpectedMappingKeys(file, mapping, Kind, Array.Empty()); - return new Condition() + public override bool TryMappingRhs => false; + + protected override ICondition ParseMapping(string file, YamlMappingNode mapping, string? scalar, IParsedValueWarningChecker? warnings) { - Value = scalar, - Yaml = mapping, - YamlFile = file - }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, Array.Empty()); + return new Condition() + { + Value = scalar, + Yaml = mapping, + YamlFile = file + }; + } } } diff --git a/src/cs/Command/Conditions/ConditionYamlParserBase.cs b/src/cs/Command/Conditions/ConditionYamlParserBase.cs index 220cde6a..6e4abe8b 100644 --- a/src/cs/Command/Conditions/ConditionYamlParserBase.cs +++ b/src/cs/Command/Conditions/ConditionYamlParserBase.cs @@ -1,43 +1,47 @@ -namespace macaroni; +using System; +using YamlDotNet.RepresentationModel; -internal abstract class ConditionYamlParserBase : YamlParserBase, IConditionYamlParser +namespace macaroni { - public ConditionYamlParserBase(ISystemContext context) : base(context) { } - - public virtual string Kind => throw new NotImplementedException(); - public virtual bool TryMappingRhs => true; - public virtual bool TryScalarRhs => true; - public virtual bool RequireScalarRhsNotNull => true; - - public virtual ICondition Parse(string file, YamlMappingNode condition, YamlNode value, IParsedValueWarningChecker? warnings) + internal abstract class ConditionYamlParserBase : YamlParserBase, IConditionYamlParser { - if (TryScalarRhs) - { - var scalar = value as YamlScalarNode; - if (scalar != null) return ParseScalarRhs(file, condition, scalar, warnings); - } + public ConditionYamlParserBase(ISystemContext context) : base(context) { } - if (TryMappingRhs) + public virtual string Kind => throw new NotImplementedException(); + public virtual bool TryMappingRhs => true; + public virtual bool TryScalarRhs => true; + public virtual bool RequireScalarRhsNotNull => true; + + public virtual ICondition Parse(string file, YamlMappingNode condition, YamlNode value, IParsedValueWarningChecker? warnings) { - var mapping = value as YamlMappingNode; - if (mapping != null) return ParseMapping(file, mapping, null, warnings); + if (TryScalarRhs) + { + var scalar = value as YamlScalarNode; + if (scalar != null) return ParseScalarRhs(file, condition, scalar, warnings); + } + + if (TryMappingRhs) + { + var mapping = value as YamlMappingNode; + if (mapping != null) return ParseMapping(file, mapping, null, warnings); + } + + throw !TryMappingRhs + ? ExpectedStringValue(file, value) + : ExpectedMappingOrStringValueException(file, Kind, value); } - throw !TryMappingRhs - ? ExpectedStringValue(file, value) - : ExpectedMappingOrStringValueException(file, Kind, value); - } + protected virtual ICondition ParseScalarRhs(string file, YamlMappingNode condition, YamlScalarNode scalar, IParsedValueWarningChecker? warnings) + { + var value = RequireScalarRhsNotNull + ? RequireScalarStringValueNotNullOrEmpty(file, Kind, scalar, null) // don't parse warnings here, see next line of code below + : scalar.Value; - protected virtual ICondition ParseScalarRhs(string file, YamlMappingNode condition, YamlScalarNode scalar, IParsedValueWarningChecker? warnings) - { - var value = RequireScalarRhsNotNull - ? RequireScalarStringValueNotNullOrEmpty(file, Kind, scalar, null) // don't parse warnings here, see next line of code below - : scalar.Value; + warnings?.CheckParsedValue(file, Kind, scalar, value); // check here instead - warnings?.CheckParsedValue(file, Kind, scalar, value); // check here instead + return ParseMapping(file, condition, value, warnings); + } - return ParseMapping(file, condition, value, warnings); + protected abstract ICondition ParseMapping(string file, YamlMappingNode mapping, string? scalar, IParsedValueWarningChecker? warnings); } - - protected abstract ICondition ParseMapping(string file, YamlMappingNode mapping, string? scalar, IParsedValueWarningChecker? warnings); -} +} \ No newline at end of file diff --git a/src/cs/Command/Conditions/ConditionsOperationBase.cs b/src/cs/Command/Conditions/ConditionsOperationBase.cs index 1a8d9e21..977ee6ee 100644 --- a/src/cs/Command/Conditions/ConditionsOperationBase.cs +++ b/src/cs/Command/Conditions/ConditionsOperationBase.cs @@ -1,38 +1,41 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal abstract class ConditionsOperationBase : ICondition, ILoadedFromYamlFile, INotifyCondition +namespace macaroni { - public IConditionCollection? Conditions { get; set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) - { - YamlParent = parent; - - (Conditions as ILoadedFromYamlFile)?.LoadComplete(this); - } - - public void Unload() - { - (Conditions as ILoadedFromYamlFile)?.Unload(); - } - - public bool IsSatisfied(IResolutionContext? context) - { - return Conditions != null && Conditions.IsSatisfied(context); - } - - public void ConditionChanged(ICondition condition) - { - NotifyConditionChanged(); - } - - private void NotifyConditionChanged() + internal abstract class ConditionsOperationBase : ICondition, ILoadedFromYamlFile, INotifyCondition { - var notify = YamlParent as INotifyCondition; - notify?.ConditionChanged(this); + public IConditionCollection? Conditions { get; set; } + + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } + + public void LoadComplete(object parent) + { + YamlParent = parent; + + (Conditions as ILoadedFromYamlFile)?.LoadComplete(this); + } + + public void Unload() + { + (Conditions as ILoadedFromYamlFile)?.Unload(); + } + + public bool IsSatisfied(IResolutionContext? context) + { + return Conditions != null && Conditions.IsSatisfied(context); + } + + public void ConditionChanged(ICondition condition) + { + NotifyConditionChanged(); + } + + private void NotifyConditionChanged() + { + var notify = YamlParent as INotifyCondition; + notify?.ConditionChanged(this); + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Conditions/ConditionsOperationYamlParserBase.cs b/src/cs/Command/Conditions/ConditionsOperationYamlParserBase.cs index 8d396b31..543dfacd 100644 --- a/src/cs/Command/Conditions/ConditionsOperationYamlParserBase.cs +++ b/src/cs/Command/Conditions/ConditionsOperationYamlParserBase.cs @@ -1,32 +1,34 @@ +using System; using Microsoft.Extensions.DependencyInjection; +using YamlDotNet.RepresentationModel; -namespace macaroni; - -internal abstract class ConditionsOperationYamlParserBase : YamlParserBase, IConditionYamlParser where T : ConditionsOperationBase, ICondition, new() +namespace macaroni { - public ConditionsOperationYamlParserBase(IServiceProvider services, ConditionCollectionEvaluationOperation operation, ISystemContext context) : base(context) + internal abstract class ConditionsOperationYamlParserBase : YamlParserBase, IConditionYamlParser where T : ConditionsOperationBase, ICondition, new() { - _serviceProvider = services; - _operation = operation; - } + public ConditionsOperationYamlParserBase(IServiceProvider services, ConditionCollectionEvaluationOperation operation, ISystemContext context) : base(context) + { + _serviceProvider = services; + _operation = operation; + } - public abstract string Kind { get; } + public abstract string Kind { get; } public ICondition Parse(string file, YamlMappingNode condition, YamlNode value, IParsedValueWarningChecker? warnings) { var sequence = value as YamlSequenceNode; if (sequence != null) return ParseSequence(file, condition, sequence, warnings); - throw ErrorParsingYamlException(file, value.Start.Line, value.Start.Column, "Unexpected YamlNode type", $"EXPECTED: `{Kind}: {{condition sequence}}`"); - } + throw ErrorParsingYamlException(file, value.Start.Line, value.Start.Column, "Unexpected YamlNode type", $"EXPECTED: `{Kind}: {{condition sequence}}`"); + } - private void EnsureParser() - { - if (_conditionsParser == null) + private void EnsureParser() { - _conditionsParser = _serviceProvider.GetRequiredService(); + if (_conditionsParser == null) + { + _conditionsParser = _serviceProvider.GetRequiredService(); + } } - } private ICondition ParseSequence(string file, YamlMappingNode condition, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) { @@ -38,17 +40,18 @@ private ICondition ParseSequence(string file, YamlMappingNode condition, YamlSeq conditions.Operation = _operation; } - RequireNoUnexpectedMappingKeys(file, condition, Kind, Array.Empty()); + RequireNoUnexpectedMappingKeys(file, condition, Kind, Array.Empty()); - return new T() - { - Conditions = conditions, - Yaml = sequence, - YamlFile = file - }; - } + return new T() + { + Conditions = conditions, + Yaml = sequence, + YamlFile = file + }; + } - private readonly IServiceProvider _serviceProvider; - private IConditionCollectionYamlParser? _conditionsParser; - private ConditionCollectionEvaluationOperation _operation; -} + private readonly IServiceProvider _serviceProvider; + private IConditionCollectionYamlParser? _conditionsParser; + private ConditionCollectionEvaluationOperation _operation; + } +} \ No newline at end of file diff --git a/src/cs/Command/Conditions/EnvironmentCondition.cs b/src/cs/Command/Conditions/EnvironmentCondition.cs index 40aa2bf7..3e6ec9c6 100644 --- a/src/cs/Command/Conditions/EnvironmentCondition.cs +++ b/src/cs/Command/Conditions/EnvironmentCondition.cs @@ -1,35 +1,37 @@ -using System.Diagnostics; +using System; +using YamlDotNet.RepresentationModel; -namespace macaroni; - -internal class EnvironmentCondition : ICondition, ILoadedFromYamlFile +namespace macaroni { - public string? Name { get; set; } - public string? Value { get; set; } + internal class EnvironmentCondition : ICondition, ILoadedFromYamlFile + { + public string? Name { get; set; } + public string? Value { get; set; } - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public void LoadComplete(object parent) - { - YamlParent = parent; - } + public void LoadComplete(object parent) + { + YamlParent = parent; + } - public void Unload() - { - } + public void Unload() + { + } - public bool IsSatisfied(IResolutionContext? context) - { - if (Name == null) return false; + public bool IsSatisfied(IResolutionContext? context) + { + if (Name == null) return false; - var currentValue = Environment.GetEnvironmentVariable(Name); - var currentValueOk = !string.IsNullOrEmpty(currentValue); + var currentValue = Environment.GetEnvironmentVariable(Name); + var currentValueOk = !string.IsNullOrEmpty(currentValue); - if (Value == null) return currentValueOk; // check/return existence - if (!currentValueOk) return false; // check/return value ==, can't be if not ok + if (Value == null) return currentValueOk; // check/return existence + if (!currentValueOk) return false; // check/return value ==, can't be if not ok - return string.Compare(currentValue, Value, true) == 0; + return string.Compare(currentValue, Value, true) == 0; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Conditions/EnvironmentConditionYamlParser.cs b/src/cs/Command/Conditions/EnvironmentConditionYamlParser.cs index b94c8b9a..f5df1fcf 100644 --- a/src/cs/Command/Conditions/EnvironmentConditionYamlParser.cs +++ b/src/cs/Command/Conditions/EnvironmentConditionYamlParser.cs @@ -1,25 +1,29 @@ -namespace macaroni; +using System; +using YamlDotNet.RepresentationModel; -internal class EnvironmentConditionYamlParser : ConditionYamlParserBase +namespace macaroni { - public EnvironmentConditionYamlParser(ISystemContext context) : base(context) { } + internal class EnvironmentConditionYamlParser : ConditionYamlParserBase + { + public EnvironmentConditionYamlParser(ISystemContext context) : base(context) { } - public override string Kind { get { return "environment"; } } + public override string Kind { get { return "environment"; } } protected override ICondition ParseMapping(string file, YamlMappingNode mapping, string? scalar, IParsedValueWarningChecker? warnings) { var name = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "name", warnings); var value = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "value", warnings); - var allowed = scalar != null ? Array.Empty() : new[] { "name" }; - RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + var allowed = scalar != null ? Array.Empty() : new[] { "name" }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); - return new EnvironmentCondition - { - Name = name, - Value = value, - Yaml = mapping, - YamlFile = file - }; + return new EnvironmentCondition + { + Name = name, + Value = value, + Yaml = mapping, + YamlFile = file + }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Conditions/GlobalNamedStateCondition.cs b/src/cs/Command/Conditions/GlobalNamedStateCondition.cs index ac2b5f43..39cd35cb 100644 --- a/src/cs/Command/Conditions/GlobalNamedStateCondition.cs +++ b/src/cs/Command/Conditions/GlobalNamedStateCondition.cs @@ -1,113 +1,114 @@ -using System.Diagnostics; +using YamlDotNet.RepresentationModel; -namespace macaroni; - -internal class GlobalNamedStateCondition : ICondition, ILoadedFromYamlFile +namespace macaroni { - public GlobalNamedStateCondition(string name) + internal class GlobalNamedStateCondition : ICondition, ILoadedFromYamlFile { - Name = name; - } - - public string Name { get; set; } - public string? Contains { get; set; } - public string? Contents { get; set; } + public GlobalNamedStateCondition(string name) + { + Name = name; + } - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } + public string Name { get; set; } + public string? Contains { get; set; } + public string? Contents { get; set; } - public bool IsSatisfied(IResolutionContext? context) - { - var satisfied = _valueMatchesContent || _valueContainsMatch || _existOnlyMatch; - if (satisfied || context == null) return satisfied; + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - return context != null && CheckDynamicState(context); - } + public bool IsSatisfied(IResolutionContext? context) + { + var satisfied = _valueMatchesContent || _valueContainsMatch || _existOnlyMatch; + if (satisfied || context == null) return satisfied; - public void LoadComplete(object parent) - { - YamlParent = parent; + return context != null && CheckDynamicState(context); + } - if (!this.IsEditorDesignMode()) + public void LoadComplete(object parent) { - _service = this.GetRequiredParentOrService(); - _monitor = this.GetParentOrService(); + YamlParent = parent; + + if (!this.IsEditorDesignMode()) + { + _service = this.GetRequiredParentOrService(); + _monitor = this.GetParentOrService(); - var value = _service.GetNamedState(Name); - CheckStaticState(value, false); + var value = _service.GetNamedState(Name); + CheckStaticState(value, false); - _monitor?.StartNotify(Name, state => CheckStaticState(state.Value, true)); + _monitor?.StartNotify(Name, state => CheckStaticState(state.Value, true)); + } } - } - public void Unload() - { - _monitor?.StopNotify(); - } + public void Unload() + { + _monitor?.StopNotify(); + } - private bool CheckDynamicState(IResolutionContext context) - { - var name = context.Resolve(Name); - if (name == null) return false; + private bool CheckDynamicState(IResolutionContext context) + { + var name = context.Resolve(Name); + if (name == null) return false; - var value = _service?.GetNamedState(name); - var resolvedValue = context.Resolve(value); - var resolvedContents = context.Resolve(Contents); - var resolvedContains = context.Resolve(Contains); + var value = _service?.GetNamedState(name); + var resolvedValue = context.Resolve(value); + var resolvedContents = context.Resolve(Contents); + var resolvedContains = context.Resolve(Contains); - var valueMatchesContent = CheckContents(resolvedValue, resolvedContents); - var valueContainsMatch = CheckContains(resolvedValue, resolvedContains); - var existOnlyMatch = CheckExistOnly(resolvedValue); + var valueMatchesContent = CheckContents(resolvedValue, resolvedContents); + var valueContainsMatch = CheckContains(resolvedValue, resolvedContains); + var existOnlyMatch = CheckExistOnly(resolvedValue); - return valueMatchesContent || valueContainsMatch || existOnlyMatch; - } + return valueMatchesContent || valueContainsMatch || existOnlyMatch; + } - private void CheckStaticState(string? value, bool notify = false) - { - MR.TRACE_VERBOSE($"Checking state '{Name}'..."); + private void CheckStaticState(string? value, bool notify = false) + { + MR.TRACE_VERBOSE($"Checking state '{Name}'..."); - var valueMatchesContent = CheckContents(value, Contents); - var valueContainsMatch = CheckContains(value, Contains); - var existOnlyMatch = CheckExistOnly(value); + var valueMatchesContent = CheckContents(value, Contents); + var valueContainsMatch = CheckContains(value, Contains); + var existOnlyMatch = CheckExistOnly(value); - var changed = valueMatchesContent != _valueMatchesContent || - valueContainsMatch != _valueContainsMatch || - existOnlyMatch != _existOnlyMatch; - - _valueMatchesContent = valueMatchesContent; - _valueContainsMatch = valueContainsMatch; - _existOnlyMatch = existOnlyMatch; + var changed = valueMatchesContent != _valueMatchesContent || + valueContainsMatch != _valueContainsMatch || + existOnlyMatch != _existOnlyMatch; - if (changed && notify) NotifyConditionChanged(); + _valueMatchesContent = valueMatchesContent; + _valueContainsMatch = valueContainsMatch; + _existOnlyMatch = existOnlyMatch; - MR.TRACE_VERBOSE($"Checking state '{Name}'... changed={changed}, satisfied={IsSatisfied(null)}"); - } + if (changed && notify) NotifyConditionChanged(); - private bool CheckContents(string? value, string? contents) - { - return value != null && contents != null && value == contents; - } + MR.TRACE_VERBOSE($"Checking state '{Name}'... changed={changed}, satisfied={IsSatisfied(null)}"); + } - private bool CheckContains(string? value, string? contains) - { - return value != null && contains != null && value.Contains(contains); - } + private bool CheckContents(string? value, string? contents) + { + return value != null && contents != null && value == contents; + } - private bool CheckExistOnly(string? value) - { - return value != null && Contains == null && Contents == null; - } + private bool CheckContains(string? value, string? contains) + { + return value != null && contains != null && value.Contains(contains); + } - private void NotifyConditionChanged() - { - var notify = YamlParent as INotifyCondition; - notify?.ConditionChanged(this); - } + private bool CheckExistOnly(string? value) + { + return value != null && Contains == null && Contents == null; + } - private bool _existOnlyMatch; - private bool _valueMatchesContent; - private bool _valueContainsMatch; - private IGlobalNamedStateService? _service; - private IGlobalNamedStateMonitorService? _monitor; -} + private void NotifyConditionChanged() + { + var notify = YamlParent as INotifyCondition; + notify?.ConditionChanged(this); + } + + private bool _existOnlyMatch; + private bool _valueMatchesContent; + private bool _valueContainsMatch; + private IGlobalNamedStateService? _service; + private IGlobalNamedStateMonitorService? _monitor; + } +} \ No newline at end of file diff --git a/src/cs/Command/Conditions/GlobalNamedStateConditionYamlParser.cs b/src/cs/Command/Conditions/GlobalNamedStateConditionYamlParser.cs index 49f9cdef..3b5235a0 100644 --- a/src/cs/Command/Conditions/GlobalNamedStateConditionYamlParser.cs +++ b/src/cs/Command/Conditions/GlobalNamedStateConditionYamlParser.cs @@ -1,10 +1,12 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class GlobalNamedStateConditionYamlParser : ConditionYamlParserBase +namespace macaroni { - public GlobalNamedStateConditionYamlParser(ISystemContext context) : base(context) { } + internal class GlobalNamedStateConditionYamlParser : ConditionYamlParserBase + { + public GlobalNamedStateConditionYamlParser(ISystemContext context) : base(context) { } - public override string Kind { get { return "global"; } } + public override string Kind { get { return "global"; } } protected override ICondition ParseMapping(string file, YamlMappingNode mapping, string? scalar, IParsedValueWarningChecker? warnings) { @@ -13,23 +15,24 @@ protected override ICondition ParseMapping(string file, YamlMappingNode mapping, ?? RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "value", warnings); var contains = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "contains", warnings); - if (string.IsNullOrEmpty(contents) && string.IsNullOrEmpty(contains)) - { - var expected = $"`value: (string)`, `contents: (string)` or `contains: (string)`"; - throw ErrorParsingYamlException(file, mapping.Start.Line, mapping.Start.Column, "When parsing `state`, couldn't find attribute", $"EXPECTED: {expected}"); - } + if (string.IsNullOrEmpty(contents) && string.IsNullOrEmpty(contains)) + { + var expected = $"`value: (string)`, `contents: (string)` or `contains: (string)`"; + throw ErrorParsingYamlException(file, mapping.Start.Line, mapping.Start.Column, "When parsing `state`, couldn't find attribute", $"EXPECTED: {expected}"); + } - var allowed = scalar == null - ? new[] { "value", "contents", "contains", "name" } - : new[] { "value", "contents", "contains" }; - RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + var allowed = scalar == null + ? new[] { "value", "contents", "contains", "name" } + : new[] { "value", "contents", "contains" }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); - return new GlobalNamedStateCondition(name) - { - Contents = contents, - Contains = contains, - Yaml = mapping, - YamlFile = file - }; + return new GlobalNamedStateCondition(name) + { + Contents = contents, + Contains = contains, + Yaml = mapping, + YamlFile = file + }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Conditions/JavaScriptConditionYamlParser.cs b/src/cs/Command/Conditions/JavaScriptConditionYamlParser.cs index 67b67790..ec378b6a 100644 --- a/src/cs/Command/Conditions/JavaScriptConditionYamlParser.cs +++ b/src/cs/Command/Conditions/JavaScriptConditionYamlParser.cs @@ -1,8 +1,9 @@ -namespace macaroni; - -internal class JavaScriptConditionYamlParser : ScriptConditionYamlParser, IConditionYamlParser +namespace macaroni { - public JavaScriptConditionYamlParser(ISystemContext context) : base(context) { } + internal class JavaScriptConditionYamlParser : ScriptConditionYamlParser, IConditionYamlParser + { + public JavaScriptConditionYamlParser(ISystemContext context) : base(context) { } - public override string Kind { get { return "javascript"; } } -} + public override string Kind { get { return "javascript"; } } + } +} \ No newline at end of file diff --git a/src/cs/Command/Conditions/MissingCondition.cs b/src/cs/Command/Conditions/MissingCondition.cs index 7a794b3b..51db874b 100644 --- a/src/cs/Command/Conditions/MissingCondition.cs +++ b/src/cs/Command/Conditions/MissingCondition.cs @@ -1,31 +1,32 @@ -using System.Diagnostics; +using YamlDotNet.RepresentationModel; -namespace macaroni; - -internal class MissingCondition : ICondition, ILoadedFromYamlFile +namespace macaroni { - public string? Value { get; set; } + internal class MissingCondition : ICondition, ILoadedFromYamlFile + { + public string? Value { get; set; } - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public bool IsSatisfied(IResolutionContext? context) - { - if (context == null || Value == null) return false; + public bool IsSatisfied(IResolutionContext? context) + { + if (context == null || Value == null) return false; - var resolved = context.Resolve(Value, true); - var value = context.Resolve("{values." + Value.Substring(1)); + var resolved = context.Resolve(Value, true); + var value = context.Resolve("{values." + Value.Substring(1)); - return string.IsNullOrEmpty(resolved) || resolved == value; - } + return string.IsNullOrEmpty(resolved) || resolved == value; + } - public void LoadComplete(object parent) - { - YamlParent = parent; - } + public void LoadComplete(object parent) + { + YamlParent = parent; + } - public void Unload() - { + public void Unload() + { + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Conditions/MissingConditionYamlParser.cs b/src/cs/Command/Conditions/MissingConditionYamlParser.cs index 10b45fe3..b2d1a0c2 100644 --- a/src/cs/Command/Conditions/MissingConditionYamlParser.cs +++ b/src/cs/Command/Conditions/MissingConditionYamlParser.cs @@ -1,20 +1,31 @@ -namespace macaroni; +using System; +using YamlDotNet.RepresentationModel; -internal class MissingConditionYamlParser : ConditionYamlParserBase +namespace macaroni { - public MissingConditionYamlParser(ISystemContext context) : base(context) { } + internal class MissingConditionYamlParser : ConditionYamlParserBase + { + public MissingConditionYamlParser(ISystemContext context) : base(context) + { + } - public override string Kind { get { return "missing"; } } - public override bool TryMappingRhs => false; + public override string Kind + { + get { return "missing"; } + } - protected override ICondition ParseMapping(string file, YamlMappingNode mapping, string? scalar, IParsedValueWarningChecker? warnings) - { - RequireNoUnexpectedMappingKeys(file, mapping, Kind, Array.Empty()); - return new MissingCondition() + public override bool TryMappingRhs => false; + + protected override ICondition ParseMapping(string file, YamlMappingNode mapping, string? scalar, + IParsedValueWarningChecker? warnings) { - Value = scalar, - Yaml = mapping, - YamlFile = file - }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, Array.Empty()); + return new MissingCondition() + { + Value = scalar, + Yaml = mapping, + YamlFile = file + }; + } } } diff --git a/src/cs/Command/Conditions/NoneCondition.cs b/src/cs/Command/Conditions/NoneCondition.cs index b4f0bb9f..bfec883a 100644 --- a/src/cs/Command/Conditions/NoneCondition.cs +++ b/src/cs/Command/Conditions/NoneCondition.cs @@ -1,5 +1,6 @@ -namespace macaroni; - -internal class NoneCondition : ConditionsOperationBase +namespace macaroni { -} + internal class NoneCondition : ConditionsOperationBase + { + } +} \ No newline at end of file diff --git a/src/cs/Command/Conditions/NoneConditionYamlParser.cs b/src/cs/Command/Conditions/NoneConditionYamlParser.cs index 0baee5a2..2c3c17a6 100644 --- a/src/cs/Command/Conditions/NoneConditionYamlParser.cs +++ b/src/cs/Command/Conditions/NoneConditionYamlParser.cs @@ -1,7 +1,10 @@ -namespace macaroni; +using System; -internal class NoneConditionYamlParser : ConditionsOperationYamlParserBase, IConditionYamlParser +namespace macaroni { - public NoneConditionYamlParser(IServiceProvider services, ISystemContext context) : base(services, ConditionCollectionEvaluationOperation.None, context) { } - public override string Kind { get { return "none"; } } -} + internal class NoneConditionYamlParser : ConditionsOperationYamlParserBase, IConditionYamlParser + { + public NoneConditionYamlParser(IServiceProvider services, ISystemContext context) : base(services, ConditionCollectionEvaluationOperation.None, context) { } + public override string Kind { get { return "none"; } } + } +} \ No newline at end of file diff --git a/src/cs/Command/Conditions/PlatformCondition.cs b/src/cs/Command/Conditions/PlatformCondition.cs index 509648d1..172b2018 100644 --- a/src/cs/Command/Conditions/PlatformCondition.cs +++ b/src/cs/Command/Conditions/PlatformCondition.cs @@ -1,36 +1,37 @@ -using System.Diagnostics; +using YamlDotNet.RepresentationModel; -namespace macaroni; - -internal class PlatformCondition : ICondition, ILoadedFromYamlFile +namespace macaroni { - public string? Value { get; set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public bool IsSatisfied(IResolutionContext? context) + internal class PlatformCondition : ICondition, ILoadedFromYamlFile { - var resolved = context == null ? Value : context.Resolve(Value, true); - resolved = resolved?.ToLower(); + public string? Value { get; set; } - return resolved switch + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } + + public bool IsSatisfied(IResolutionContext? context) { - "mac" => OS.IsMac(), - "windows" => OS.IsWindows(), - "android" => OS.IsAndroid(), - "linux" => OS.IsLinux(), - _ => false - }; - } + var resolved = context == null ? Value : context.Resolve(Value, true); + resolved = resolved?.ToLower(); - public void LoadComplete(object parent) - { - YamlParent = parent; - } + return resolved switch + { + "mac" => OS.IsMac(), + "windows" => OS.IsWindows(), + "android" => OS.IsAndroid(), + "linux" => OS.IsLinux(), + _ => false + }; + } - public void Unload() - { + public void LoadComplete(object parent) + { + YamlParent = parent; + } + + public void Unload() + { + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Conditions/PlatformConditionYamlParser.cs b/src/cs/Command/Conditions/PlatformConditionYamlParser.cs index 140cb59e..0a602c08 100644 --- a/src/cs/Command/Conditions/PlatformConditionYamlParser.cs +++ b/src/cs/Command/Conditions/PlatformConditionYamlParser.cs @@ -1,20 +1,31 @@ -namespace macaroni; +using System; +using YamlDotNet.RepresentationModel; -internal class PlatformConditionYamlParser : ConditionYamlParserBase +namespace macaroni { - public PlatformConditionYamlParser(ISystemContext context) : base(context) { } + internal class PlatformConditionYamlParser : ConditionYamlParserBase + { + public PlatformConditionYamlParser(ISystemContext context) : base(context) + { + } - public override string Kind { get { return "platform"; } } - public override bool TryMappingRhs => false; + public override string Kind + { + get { return "platform"; } + } - protected override ICondition ParseMapping(string file, YamlMappingNode mapping, string? scalar, IParsedValueWarningChecker? warnings) - { - RequireNoUnexpectedMappingKeys(file, mapping, Kind, Array.Empty()); - return new PlatformCondition() + public override bool TryMappingRhs => false; + + protected override ICondition ParseMapping(string file, YamlMappingNode mapping, string? scalar, + IParsedValueWarningChecker? warnings) { - Value = scalar, - Yaml = mapping, - YamlFile = file - }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, Array.Empty()); + return new PlatformCondition() + { + Value = scalar, + Yaml = mapping, + YamlFile = file + }; + } } } diff --git a/src/cs/Command/Conditions/RequiredCondition.cs b/src/cs/Command/Conditions/RequiredCondition.cs index 2f6d111c..6f48df31 100644 --- a/src/cs/Command/Conditions/RequiredCondition.cs +++ b/src/cs/Command/Conditions/RequiredCondition.cs @@ -1,31 +1,32 @@ -using System.Diagnostics; +using YamlDotNet.RepresentationModel; -namespace macaroni; - -internal class RequiredCondition : ICondition, ILoadedFromYamlFile +namespace macaroni { - public string? Value { get; set; } + internal class RequiredCondition : ICondition, ILoadedFromYamlFile + { + public string? Value { get; set; } - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public bool IsSatisfied(IResolutionContext? context) - { - if (context == null || Value == null) return false; + public bool IsSatisfied(IResolutionContext? context) + { + if (context == null || Value == null) return false; - var resolved = context.Resolve(Value, true); - var value = context.Resolve("{values." + Value.Substring(1)); + var resolved = context.Resolve(Value, true); + var value = context.Resolve("{values." + Value.Substring(1)); - return !string.IsNullOrEmpty(resolved) && resolved != value; - } + return !string.IsNullOrEmpty(resolved) && resolved != value; + } - public void LoadComplete(object parent) - { - YamlParent = parent; - } + public void LoadComplete(object parent) + { + YamlParent = parent; + } - public void Unload() - { + public void Unload() + { + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Conditions/RequiredConditionYamlParser.cs b/src/cs/Command/Conditions/RequiredConditionYamlParser.cs index b30fb09e..5aa3b7ed 100644 --- a/src/cs/Command/Conditions/RequiredConditionYamlParser.cs +++ b/src/cs/Command/Conditions/RequiredConditionYamlParser.cs @@ -1,20 +1,31 @@ -namespace macaroni; +using System; +using YamlDotNet.RepresentationModel; -internal class RequiredConditionYamlParser : ConditionYamlParserBase +namespace macaroni { - public RequiredConditionYamlParser(ISystemContext context) : base(context) { } + internal class RequiredConditionYamlParser : ConditionYamlParserBase + { + public RequiredConditionYamlParser(ISystemContext context) : base(context) + { + } - public override string Kind { get { return "required"; } } - public override bool TryMappingRhs => false; + public override string Kind + { + get { return "required"; } + } - protected override ICondition ParseMapping(string file, YamlMappingNode mapping, string? scalar, IParsedValueWarningChecker? warnings) - { - RequireNoUnexpectedMappingKeys(file, mapping, Kind, Array.Empty()); - return new RequiredCondition() + public override bool TryMappingRhs => false; + + protected override ICondition ParseMapping(string file, YamlMappingNode mapping, string? scalar, + IParsedValueWarningChecker? warnings) { - Value = scalar, - Yaml = mapping, - YamlFile = file - }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, Array.Empty()); + return new RequiredCondition() + { + Value = scalar, + Yaml = mapping, + YamlFile = file + }; + } } } diff --git a/src/cs/Command/Conditions/ScriptCondition.cs b/src/cs/Command/Conditions/ScriptCondition.cs index 2153588f..815c3ca1 100644 --- a/src/cs/Command/Conditions/ScriptCondition.cs +++ b/src/cs/Command/Conditions/ScriptCondition.cs @@ -1,103 +1,105 @@ -using System.Diagnostics; +using System; +using YamlDotNet.RepresentationModel; -namespace macaroni; - -internal class ScriptCondition : ICondition, ILoadedFromYamlFile +namespace macaroni { - public string? Code { get; set; } - public string? Language { get; set; } - public string? Interval { get; set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class ScriptCondition : ICondition, ILoadedFromYamlFile { - YamlParent = parent; + public string? Code { get; set; } + public string? Language { get; set; } + public string? Interval { get; set; } - if (!this.IsEditorDesignMode()) - { - _scriptExecutionService = this.GetRequiredParentOrService(); + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - CheckStaticCodeCondition(Code, Language, false); - CheckSetIntervalCallback(); - } - } + public void LoadComplete(object parent) + { + YamlParent = parent; - public void Unload() - { - ClearIntervalCallback(); - } + if (!this.IsEditorDesignMode()) + { + _scriptExecutionService = this.GetRequiredParentOrService(); - public bool IsSatisfied(IResolutionContext? context) - { - return context != null - ? CheckDynamicCodeCondition(context) - : CheckStaticCodeCondition(Code, Language, true); - } + CheckStaticCodeCondition(Code, Language, false); + CheckSetIntervalCallback(); + } + } - private bool CheckDynamicCodeCondition(IResolutionContext context) - { - return CheckCondition(context.Resolve(Code), context.Resolve(Language)); - } + public void Unload() + { + ClearIntervalCallback(); + } - private bool CheckStaticCodeCondition(string? code, string? language, bool notify = false) - { - var satisfied = CheckCondition(code, language); - var changed = satisfied != _satisfied; - _satisfied = satisfied; + public bool IsSatisfied(IResolutionContext? context) + { + return context != null + ? CheckDynamicCodeCondition(context) + : CheckStaticCodeCondition(Code, Language, true); + } - if (notify && changed) + private bool CheckDynamicCodeCondition(IResolutionContext context) { - NotifyConditionChanged(); + return CheckCondition(context.Resolve(Code), context.Resolve(Language)); } - return _satisfied; - } + private bool CheckStaticCodeCondition(string? code, string? language, bool notify = false) + { + var satisfied = CheckCondition(code, language); + var changed = satisfied != _satisfied; + _satisfied = satisfied; - private bool CheckCondition(string? code, string? language) - { - if (code == null) return false; + if (notify && changed) + { + NotifyConditionChanged(); + } - var result = _scriptExecutionService?.Evaluate(code, language) as bool?; - if (result != null && (bool)result) return true; + return _satisfied; + } - return false; - } + private bool CheckCondition(string? code, string? language) + { + if (code == null) return false; - private void NotifyConditionChanged() - { - var notify = YamlParent as INotifyCondition; - notify?.ConditionChanged(this); - } + var result = _scriptExecutionService?.Evaluate(code, language) as bool?; + if (result != null && (bool)result) return true; - private void CheckSetIntervalCallback() - { - if (Interval != null) + return false; + } + + private void NotifyConditionChanged() { - var ok = int.TryParse(Interval, out var interval); - if (ok) + var notify = YamlParent as INotifyCondition; + notify?.ConditionChanged(this); + } + + private void CheckSetIntervalCallback() + { + if (Interval != null) { - _timeIntervalService = this.GetRequiredParentOrService(); - _intervalId = _timeIntervalService.SetInterval(CallbackAction(), interval); + var ok = int.TryParse(Interval, out var interval); + if (ok) + { + _timeIntervalService = this.GetRequiredParentOrService(); + _intervalId = _timeIntervalService.SetInterval(CallbackAction(), interval); + } } } - } - private void ClearIntervalCallback() - { - _timeIntervalService?.ClearInterval(_intervalId); - _timeIntervalService = null; - } + private void ClearIntervalCallback() + { + _timeIntervalService?.ClearInterval(_intervalId); + _timeIntervalService = null; + } - private Action CallbackAction() - { - return () => CheckStaticCodeCondition(Code, Language, true); - } + private Action CallbackAction() + { + return () => CheckStaticCodeCondition(Code, Language, true); + } - private IScriptExecutionService? _scriptExecutionService; - private ITimeIntervalService? _timeIntervalService; - private bool _satisfied; - private int _intervalId; -} + private IScriptExecutionService? _scriptExecutionService; + private ITimeIntervalService? _timeIntervalService; + private bool _satisfied; + private int _intervalId; + } +} \ No newline at end of file diff --git a/src/cs/Command/Conditions/ScriptConditionYamlParser.cs b/src/cs/Command/Conditions/ScriptConditionYamlParser.cs index f835224d..50d6f969 100644 --- a/src/cs/Command/Conditions/ScriptConditionYamlParser.cs +++ b/src/cs/Command/Conditions/ScriptConditionYamlParser.cs @@ -1,10 +1,12 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class ScriptConditionYamlParser : ConditionYamlParserBase +namespace macaroni { - public ScriptConditionYamlParser(ISystemContext context) : base(context) { } + internal class ScriptConditionYamlParser : ConditionYamlParserBase + { + public ScriptConditionYamlParser(ISystemContext context) : base(context) { } - public override string Kind { get { return "script"; } } + public override string Kind { get { return "script"; } } protected override ICondition ParseMapping(string file, YamlMappingNode mapping, string? scalar, IParsedValueWarningChecker? warnings) { @@ -17,13 +19,14 @@ protected override ICondition ParseMapping(string file, YamlMappingNode mapping, : new[] { "language", "interval" }; RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); - return new ScriptCondition - { - Code = code, - Language = language, - Interval = interval, - Yaml = mapping, - YamlFile = file - }; + return new ScriptCondition + { + Code = code, + Language = language, + Interval = interval, + Yaml = mapping, + YamlFile = file + }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Conditions/UserNameCondition.cs b/src/cs/Command/Conditions/UserNameCondition.cs index f67b7360..b51cdbe7 100644 --- a/src/cs/Command/Conditions/UserNameCondition.cs +++ b/src/cs/Command/Conditions/UserNameCondition.cs @@ -1,27 +1,29 @@ -using System.Diagnostics; +using System; +using YamlDotNet.RepresentationModel; -namespace macaroni; - -internal class UserNameCondition : ICondition, ILoadedFromYamlFile +namespace macaroni { - public string? Value { get; set; } + internal class UserNameCondition : ICondition, ILoadedFromYamlFile + { + public string? Value { get; set; } - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public bool IsSatisfied(IResolutionContext? context) - { - var resolved = context == null ? Value : context.Resolve(Value, true); - return Environment.UserName == resolved?.ToLower(); - } + public bool IsSatisfied(IResolutionContext? context) + { + var resolved = context == null ? Value : context.Resolve(Value, true); + return Environment.UserName == resolved?.ToLower(); + } - public void LoadComplete(object parent) - { - YamlParent = parent; - } + public void LoadComplete(object parent) + { + YamlParent = parent; + } - public void Unload() - { + public void Unload() + { + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Conditions/UserNameConditionYamlParser.cs b/src/cs/Command/Conditions/UserNameConditionYamlParser.cs index 0853d683..7bb99159 100644 --- a/src/cs/Command/Conditions/UserNameConditionYamlParser.cs +++ b/src/cs/Command/Conditions/UserNameConditionYamlParser.cs @@ -1,20 +1,31 @@ -namespace macaroni; +using System; +using YamlDotNet.RepresentationModel; -internal class UserNameConditionYamlParser : ConditionYamlParserBase +namespace macaroni { - public UserNameConditionYamlParser(ISystemContext context) : base(context) { } + internal class UserNameConditionYamlParser : ConditionYamlParserBase + { + public UserNameConditionYamlParser(ISystemContext context) : base(context) + { + } - public override string Kind { get { return "user"; } } - public override bool TryMappingRhs => false; + public override string Kind + { + get { return "user"; } + } - protected override ICondition ParseMapping(string file, YamlMappingNode mapping, string? scalar, IParsedValueWarningChecker? warnings) - { - RequireNoUnexpectedMappingKeys(file, mapping, Kind, Array.Empty()); - return new UserNameCondition() + public override bool TryMappingRhs => false; + + protected override ICondition ParseMapping(string file, YamlMappingNode mapping, string? scalar, + IParsedValueWarningChecker? warnings) { - Value = scalar, - Yaml = mapping, - YamlFile = file - }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, Array.Empty()); + return new UserNameCondition() + { + Value = scalar, + Yaml = mapping, + YamlFile = file + }; + } } } diff --git a/src/cs/Command/Executors/AlertExecutor.cs b/src/cs/Command/Executors/AlertExecutor.cs index 384fcbdb..14c713dd 100644 --- a/src/cs/Command/Executors/AlertExecutor.cs +++ b/src/cs/Command/Executors/AlertExecutor.cs @@ -1,25 +1,27 @@ -namespace macaroni; - -internal class AlertExecutor : MsgBoxExecutorBase, ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public ExecutionResult Execute(IExecutionContext context) + + internal class AlertExecutor : MsgBoxExecutorBase, ICommandExecutor, ILoadedFromYamlFile { - MR.DBG_TRACE_INFO($"-- ALERT: Execute({Message}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO($"-- ALERT: Execute({Message}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - var title = context.Resolve(Title) ?? "ALERT"; - var message = context.Resolve(Message); - var timeout = context.Resolve(Timeout); + var title = context.Resolve(Title) ?? "ALERT"; + var message = context.Resolve(Message); + var timeout = context.Resolve(Timeout); - if (!string.IsNullOrEmpty(message)) - { - var msgbox = this.GetParentOrService(); - if (msgbox != null) + if (!string.IsNullOrEmpty(message)) { - var ok = msgbox.Show(message, title, timeout); - if (!ok) return ExecutionResult.Stopped; + var msgbox = this.GetParentOrService(); + if (msgbox != null) + { + var ok = msgbox.Show(message, title, timeout); + if (!ok) return ExecutionResult.Stopped; + } } - } - return ExecutionResult.Completed; + return ExecutionResult.Completed; + } } } diff --git a/src/cs/Command/Executors/AlertExecutorYamlParser.cs b/src/cs/Command/Executors/AlertExecutorYamlParser.cs index 273bd751..165e12e6 100644 --- a/src/cs/Command/Executors/AlertExecutorYamlParser.cs +++ b/src/cs/Command/Executors/AlertExecutorYamlParser.cs @@ -1,20 +1,30 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class AlertExecutorYamlParser : ExecutorYamlParserBase_MsgBoxScalarMapping, IExecutorYamlParser +namespace macaroni { - public AlertExecutorYamlParser(ISystemContext context) : base(context) { } - public override string Kind { get { return "alert"; } } - - override protected ICommandExecutor CreateFromMapping(string file, YamlMappingNode mapping, string message, string? title, string? timeout, IParsedValueWarningChecker? warnings) + internal class AlertExecutorYamlParser : ExecutorYamlParserBase_MsgBoxScalarMapping, IExecutorYamlParser { - return new AlertExecutor() + public AlertExecutorYamlParser(ISystemContext context) : base(context) + { + } + + public override string Kind + { + get { return "alert"; } + } + + override protected ICommandExecutor CreateFromMapping(string file, YamlMappingNode mapping, string message, + string? title, string? timeout, IParsedValueWarningChecker? warnings) { - Message = message, - Title = title, - Timeout = timeout, - Yaml = mapping, - YamlFile = file - }; + return new AlertExecutor() + { + Message = message, + Title = title, + Timeout = timeout, + Yaml = mapping, + YamlFile = file + }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/AnalyzeExecutor.cs b/src/cs/Command/Executors/AnalyzeExecutor.cs index ab11a9c3..66f89862 100644 --- a/src/cs/Command/Executors/AnalyzeExecutor.cs +++ b/src/cs/Command/Executors/AnalyzeExecutor.cs @@ -1,52 +1,56 @@ +using System.IO; +using System.Threading.Tasks; using Azure.AI.Vision.ImageAnalysis; +using YamlDotNet.RepresentationModel; -namespace macaroni; - -internal class AnalyzeExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public string? Image { get; set; } - public string? Feature { get; set; } - public string? Language { get; set; } - - public string? Key { get; set; } - public string? Endpoint { get; set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) - { - YamlParent = parent; - } - public void Unload() + internal class AnalyzeExecutor : ICommandExecutor, ILoadedFromYamlFile { - } + public string? Image { get; set; } + public string? Feature { get; set; } + public string? Language { get; set; } + + public string? Key { get; set; } + public string? Endpoint { get; set; } + + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } + + public void LoadComplete(object parent) + { + YamlParent = parent; + } + + public void Unload() + { + } public ExecutionResult Execute(IExecutionContext context) { MR.DBG_TRACE_INFO($"-- ANALYZE: Execute({Image}, {Feature}, {Language}, {Key}, {Endpoint}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - var image = ResolveImageFileName(context, out var deleteFileWhenDone); - var feature = context.Resolve(Feature); - var language = context.Resolve(Language); + var image = ResolveImageFileName(context, out var deleteFileWhenDone); + var feature = context.Resolve(Feature); + var language = context.Resolve(Language); - var key = context.Resolve(Key); - var endpoint = context.Resolve(Endpoint); + var key = context.Resolve(Key); + var endpoint = context.Resolve(Endpoint); - if (image != null) - { - Task.Run(async () => + if (image != null) { - try + Task.Run(async () => { - var service = this.GetRequiredParentOrService(); - var result = await service.Analyze(image, feature, language); + try + { + var service = this.GetRequiredParentOrService(); + var result = await service.Analyze(image, feature, language); - var text = TextFromResult(result, feature); - context.Set("analyze.text", text); - context.Set("analyze.result", result); + var text = TextFromResult(result, feature); + context.Set("analyze.text", text); + context.Set("analyze.result", result); var rectangles = result.AsTextRectangles(); context.Set("analyze.rectangles", rectangles); @@ -64,28 +68,29 @@ public ExecutionResult Execute(IExecutionContext context) return ExecutionResult.Completed; } - private string? ResolveImageFileName(IExecutionContext context, out bool deleteFileWhenDone) - { - var image = context.ResolveImage(Image); - if (image == null) + private string? ResolveImageFileName(IExecutionContext context, out bool deleteFileWhenDone) { - deleteFileWhenDone = false; - return context.Resolve(Image); - } + var image = context.ResolveImage(Image); + if (image == null) + { + deleteFileWhenDone = false; + return context.Resolve(Image); + } - var tempFileName = Path.GetTempFileName() + ".png"; - image.Save(tempFileName); + var tempFileName = Path.GetTempFileName() + ".png"; + image.Save(tempFileName); - deleteFileWhenDone = true; - return tempFileName; - } + deleteFileWhenDone = true; + return tempFileName; + } - private string TextFromResult(ImageAnalysisResult result, string? feature) - { - return feature switch + private string TextFromResult(ImageAnalysisResult result, string? feature) { - "Description" => result.AsDescription(), - _ => result.AsMonospaceTable() - }; + return feature switch + { + "Description" => result.AsDescription(), + _ => result.AsMonospaceTable() + }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/AnalyzeExecutorYamlParser.cs b/src/cs/Command/Executors/AnalyzeExecutorYamlParser.cs index d83fd0d1..bffc154d 100644 --- a/src/cs/Command/Executors/AnalyzeExecutorYamlParser.cs +++ b/src/cs/Command/Executors/AnalyzeExecutorYamlParser.cs @@ -1,11 +1,14 @@ -namespace macaroni; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class AnalyzeExecutorYamlParser : ExecutorYamlParserBase +namespace macaroni { - public AnalyzeExecutorYamlParser(ISystemContext context) : base(context) { } + internal class AnalyzeExecutorYamlParser : ExecutorYamlParserBase + { + public AnalyzeExecutorYamlParser(ISystemContext context) : base(context) { } - public override string Kind { get { return "analyze"; } } - public override bool TrySequenceOfStringRhs => false; + public override string Kind { get { return "analyze"; } } + public override bool TrySequenceOfStringRhs => false; protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) { @@ -17,24 +20,25 @@ protected override ICommandExecutor ParseMapping(string file, YamlMappingNode ma var feature = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "feature", warnings); var language = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "language", warnings); - var allowed = scalar == null - ? new[] { "key", "endpoint", "feature", "language", "image" } - : new[] { "key", "endpoint", "feature", "language" }; - RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + var allowed = scalar == null + ? new[] { "key", "endpoint", "feature", "language", "image" } + : new[] { "key", "endpoint", "feature", "language" }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); - return new AnalyzeExecutor() - { - Image = image, + return new AnalyzeExecutor() + { + Image = image, - Key = key, - Endpoint = endpoint, + Key = key, + Endpoint = endpoint, - Feature = feature, - Language = language, + Feature = feature, + Language = language, - Yaml = mapping, - YamlFile = file - }; - } + Yaml = mapping, + YamlFile = file + }; + } -} + } +} \ No newline at end of file diff --git a/src/cs/Command/Executors/AndroidIntentExecutor.cs b/src/cs/Command/Executors/AndroidIntentExecutor.cs index 50a05331..7c9158ce 100644 --- a/src/cs/Command/Executors/AndroidIntentExecutor.cs +++ b/src/cs/Command/Executors/AndroidIntentExecutor.cs @@ -1,40 +1,45 @@ -namespace macaroni; +using System.Collections.Generic; +using System.Linq; +using YamlDotNet.RepresentationModel; -internal class AndroidIntentExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public string? Action { get; set; } - public string? Uri { get; set; } - public IEnumerable? Extras { get; set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class AndroidIntentExecutor : ICommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; - } + public string? Action { get; set; } + public string? Uri { get; set; } + public IEnumerable? Extras { get; set; } - public void Unload() - { - } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- ANDROID.INTENT: Execute(action={Action}, uri={Uri}, extras.count={Extras?.Count()}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - - var action = context.Resolve(Action); - var uri = context.Resolve(Uri); - - var extras = Extras?.Select(x => context.Resolve(x) ?? x); - var asKvp = extras?.Select(x => new KeyValuePair(x.Before(':'), x.After(':'))); + public void LoadComplete(object parent) + { + YamlParent = parent; + } - var service = this.GetParentOrService(); - if (action != null) + public void Unload() { - service?.StartActivity(action, uri, asKvp); } - return ExecutionResult.Completed; + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO($"-- ANDROID.INTENT: Execute(action={Action}, uri={Uri}, extras.count={Extras?.Count()}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + + var action = context.Resolve(Action); + var uri = context.Resolve(Uri); + + var extras = Extras?.Select(x => context.Resolve(x) ?? x); + var asKvp = extras?.Select(x => new KeyValuePair(x.Before(':'), x.After(':'))); + + var service = this.GetParentOrService(); + if (action != null) + { + service?.StartActivity(action, uri, asKvp); + } + + return ExecutionResult.Completed; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/AndroidIntentExecutorYamlParser.cs b/src/cs/Command/Executors/AndroidIntentExecutorYamlParser.cs index 76bd006c..79508e29 100644 --- a/src/cs/Command/Executors/AndroidIntentExecutorYamlParser.cs +++ b/src/cs/Command/Executors/AndroidIntentExecutorYamlParser.cs @@ -1,11 +1,14 @@ -namespace macaroni; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class AndroidIntentExecutorYamlParser : ExecutorYamlParserBase +namespace macaroni { - public AndroidIntentExecutorYamlParser(ISystemContext context) : base(context) { } + internal class AndroidIntentExecutorYamlParser : ExecutorYamlParserBase + { + public AndroidIntentExecutorYamlParser(ISystemContext context) : base(context) { } - public override string Kind { get { return "android.intent"; } } - public override bool TrySequenceOfStringRhs => false; + public override string Kind { get { return "android.intent"; } } + public override bool TrySequenceOfStringRhs => false; protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) { @@ -13,18 +16,19 @@ protected override ICommandExecutor ParseMapping(string file, YamlMappingNode ma var uri = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "uri", warnings); var extras = GetScalarStrings(file, mapping, "extras", warnings); - var allowed = scalar == null - ? new[] { "uri", "extras", "action" } - : new[] { "uri", "extras" }; - RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + var allowed = scalar == null + ? new[] { "uri", "extras", "action" } + : new[] { "uri", "extras" }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); - return new AndroidIntentExecutor() - { - Action = action, - Uri = uri, - Extras = extras, - Yaml = mapping, - YamlFile = file - }; + return new AndroidIntentExecutor() + { + Action = action, + Uri = uri, + Extras = extras, + Yaml = mapping, + YamlFile = file + }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/AppCloseExecutor.cs b/src/cs/Command/Executors/AppCloseExecutor.cs index 06d7d31c..c52c1fc1 100644 --- a/src/cs/Command/Executors/AppCloseExecutor.cs +++ b/src/cs/Command/Executors/AppCloseExecutor.cs @@ -1,20 +1,22 @@ -namespace macaroni; - -internal class AppCloseExecutor : AppExecutorBase, ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public ExecutionResult Execute(IExecutionContext context) + + internal class AppCloseExecutor : AppExecutorBase, ICommandExecutor, ILoadedFromYamlFile { - MR.DBG_TRACE_INFO($"-- CLOSE: Execute({Title}, {Process}, {TitleOrProcess}, {Exclude}, {All}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO($"-- CLOSE: Execute({Title}, {Process}, {TitleOrProcess}, {Exclude}, {All}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - var titleOrProcess = context.Resolve(TitleOrProcess); - var process = context.Resolve(Process); - var title = context.Resolve(Title); - var exclude = context.Resolve(Exclude); - var all = context.Resolve(All); + var titleOrProcess = context.Resolve(TitleOrProcess); + var process = context.Resolve(Process); + var title = context.Resolve(Title); + var exclude = context.Resolve(Exclude); + var all = context.Resolve(All); - var runApp = this.GetParentOrService(); - runApp?.Close(title, process, titleOrProcess, exclude, all == "true"); + var runApp = this.GetParentOrService(); + runApp?.Close(title, process, titleOrProcess, exclude, all == "true"); - return ExecutionResult.Completed; + return ExecutionResult.Completed; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/AppCloseExecutorYamlParser.cs b/src/cs/Command/Executors/AppCloseExecutorYamlParser.cs index 3e57b305..6526ccb3 100644 --- a/src/cs/Command/Executors/AppCloseExecutorYamlParser.cs +++ b/src/cs/Command/Executors/AppCloseExecutorYamlParser.cs @@ -1,22 +1,25 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class AppCloseExecutorYamlParser : ExecutorYamlParserBase_AppScalarMapping, IExecutorYamlParser +namespace macaroni { - public AppCloseExecutorYamlParser(ISystemContext context) : base ("close", context) + internal class AppCloseExecutorYamlParser : ExecutorYamlParserBase_AppScalarMapping, IExecutorYamlParser { - } + public AppCloseExecutorYamlParser(ISystemContext context) : base("close", context) + { + } - override protected ICommandExecutor CreateFromMapping(string file, YamlMappingNode mapping, string? titleOrProcess, string? title, string? process, string? exclude, string? all, IParsedValueWarningChecker? warnings) - { - return new AppCloseExecutor() + override protected ICommandExecutor CreateFromMapping(string file, YamlMappingNode mapping, string? titleOrProcess, string? title, string? process, string? exclude, string? all, IParsedValueWarningChecker? warnings) { - TitleOrProcess = titleOrProcess, - Title = title, - Process = process, - Exclude = exclude, - All = all, - Yaml = mapping, - YamlFile = file - }; + return new AppCloseExecutor() + { + TitleOrProcess = titleOrProcess, + Title = title, + Process = process, + Exclude = exclude, + All = all, + Yaml = mapping, + YamlFile = file + }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/AppExecutorBase.cs b/src/cs/Command/Executors/AppExecutorBase.cs index 9d0f36ea..aaa826b9 100644 --- a/src/cs/Command/Executors/AppExecutorBase.cs +++ b/src/cs/Command/Executors/AppExecutorBase.cs @@ -1,23 +1,26 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class AppExecutorBase +namespace macaroni { - public string? Title { get; set; } - public string? Process { get; set; } - public string? TitleOrProcess { get; set; } - public string? All { get; set; } - public string? Exclude { get; set; } + internal class AppExecutorBase + { + public string? Title { get; set; } + public string? Process { get; set; } + public string? TitleOrProcess { get; set; } + public string? All { get; set; } + public string? Exclude { get; set; } - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public void LoadComplete(object parent) - { - YamlParent = parent; - } + public void LoadComplete(object parent) + { + YamlParent = parent; + } - public void Unload() - { + public void Unload() + { + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/AppMaximizeExecutor.cs b/src/cs/Command/Executors/AppMaximizeExecutor.cs index 0e9854c0..f3406acd 100644 --- a/src/cs/Command/Executors/AppMaximizeExecutor.cs +++ b/src/cs/Command/Executors/AppMaximizeExecutor.cs @@ -1,20 +1,22 @@ -namespace macaroni; - -internal class AppMaximizeExecutor : AppExecutorBase, ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public ExecutionResult Execute(IExecutionContext context) + + internal class AppMaximizeExecutor : AppExecutorBase, ICommandExecutor, ILoadedFromYamlFile { - MR.DBG_TRACE_INFO($"-- MAXIMIZE: Execute({Title}, {Process}, {TitleOrProcess}, {Exclude}, {All}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO($"-- MAXIMIZE: Execute({Title}, {Process}, {TitleOrProcess}, {Exclude}, {All}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - var titleOrProcess = context.Resolve(TitleOrProcess); - var process = context.Resolve(Process); - var title = context.Resolve(Title); - var exclude = context.Resolve(Exclude); - var all = context.Resolve(All); + var titleOrProcess = context.Resolve(TitleOrProcess); + var process = context.Resolve(Process); + var title = context.Resolve(Title); + var exclude = context.Resolve(Exclude); + var all = context.Resolve(All); - var runApp = this.GetParentOrService(); - runApp?.Maximize(title, process, titleOrProcess, exclude, all == "true"); + var runApp = this.GetParentOrService(); + runApp?.Maximize(title, process, titleOrProcess, exclude, all == "true"); - return ExecutionResult.Completed; + return ExecutionResult.Completed; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/AppMaximizeExecutorYamlParser.cs b/src/cs/Command/Executors/AppMaximizeExecutorYamlParser.cs index 50c1c573..472d1a76 100644 --- a/src/cs/Command/Executors/AppMaximizeExecutorYamlParser.cs +++ b/src/cs/Command/Executors/AppMaximizeExecutorYamlParser.cs @@ -1,22 +1,25 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class AppMaximizeExecutorYamlParser : ExecutorYamlParserBase_AppScalarMapping, IExecutorYamlParser +namespace macaroni { - public AppMaximizeExecutorYamlParser(ISystemContext context) : base ("maximize", context) + internal class AppMaximizeExecutorYamlParser : ExecutorYamlParserBase_AppScalarMapping, IExecutorYamlParser { - } + public AppMaximizeExecutorYamlParser(ISystemContext context) : base("maximize", context) + { + } - override protected ICommandExecutor CreateFromMapping(string file, YamlMappingNode mapping, string? titleOrProcess, string? title, string? process, string? exclude, string? all, IParsedValueWarningChecker? warnings) - { - return new AppMaximizeExecutor() + override protected ICommandExecutor CreateFromMapping(string file, YamlMappingNode mapping, string? titleOrProcess, string? title, string? process, string? exclude, string? all, IParsedValueWarningChecker? warnings) { - TitleOrProcess = titleOrProcess, - Title = title, - Process = process, - Exclude = exclude, - All = all, - Yaml = mapping, - YamlFile = file - }; + return new AppMaximizeExecutor() + { + TitleOrProcess = titleOrProcess, + Title = title, + Process = process, + Exclude = exclude, + All = all, + Yaml = mapping, + YamlFile = file + }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/AppMinimizeExecutor.cs b/src/cs/Command/Executors/AppMinimizeExecutor.cs index 3d6ca60e..a176605c 100644 --- a/src/cs/Command/Executors/AppMinimizeExecutor.cs +++ b/src/cs/Command/Executors/AppMinimizeExecutor.cs @@ -1,20 +1,22 @@ -namespace macaroni; - -internal class AppMinimizeExecutor : AppExecutorBase, ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public ExecutionResult Execute(IExecutionContext context) + + internal class AppMinimizeExecutor : AppExecutorBase, ICommandExecutor, ILoadedFromYamlFile { - MR.DBG_TRACE_INFO($"-- MINIMIZE: Execute({Title}, {Process}, {TitleOrProcess}, {Exclude}, {All}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO($"-- MINIMIZE: Execute({Title}, {Process}, {TitleOrProcess}, {Exclude}, {All}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - var titleOrProcess = context.Resolve(TitleOrProcess); - var process = context.Resolve(Process); - var title = context.Resolve(Title); - var exclude = context.Resolve(Exclude); - var all = context.Resolve(All); + var titleOrProcess = context.Resolve(TitleOrProcess); + var process = context.Resolve(Process); + var title = context.Resolve(Title); + var exclude = context.Resolve(Exclude); + var all = context.Resolve(All); - var runApp = this.GetParentOrService(); - runApp?.Minimize(title, process, titleOrProcess, exclude, all == "true"); + var runApp = this.GetParentOrService(); + runApp?.Minimize(title, process, titleOrProcess, exclude, all == "true"); - return ExecutionResult.Completed; + return ExecutionResult.Completed; + } } } diff --git a/src/cs/Command/Executors/AppMinimizeExecutorYamlParser.cs b/src/cs/Command/Executors/AppMinimizeExecutorYamlParser.cs index ab750b5d..d45dd046 100644 --- a/src/cs/Command/Executors/AppMinimizeExecutorYamlParser.cs +++ b/src/cs/Command/Executors/AppMinimizeExecutorYamlParser.cs @@ -1,22 +1,25 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class AppMinimizeExecutorYamlParser : ExecutorYamlParserBase_AppScalarMapping, IExecutorYamlParser +namespace macaroni { - public AppMinimizeExecutorYamlParser(ISystemContext context) : base("minimize", context) + internal class AppMinimizeExecutorYamlParser : ExecutorYamlParserBase_AppScalarMapping, IExecutorYamlParser { - } + public AppMinimizeExecutorYamlParser(ISystemContext context) : base("minimize", context) + { + } - override protected ICommandExecutor CreateFromMapping(string file, YamlMappingNode mapping, string? titleOrProcess, string? title, string? process, string? exclude, string? all, IParsedValueWarningChecker? warnings) - { - return new AppMinimizeExecutor() + override protected ICommandExecutor CreateFromMapping(string file, YamlMappingNode mapping, string? titleOrProcess, string? title, string? process, string? exclude, string? all, IParsedValueWarningChecker? warnings) { - TitleOrProcess = titleOrProcess, - Title = title, - Process = process, - Exclude = exclude, - All = all, - Yaml = mapping, - YamlFile = file - }; + return new AppMinimizeExecutor() + { + TitleOrProcess = titleOrProcess, + Title = title, + Process = process, + Exclude = exclude, + All = all, + Yaml = mapping, + YamlFile = file + }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/AppRestoreExecutor.cs b/src/cs/Command/Executors/AppRestoreExecutor.cs index 22816813..3c46b3bf 100644 --- a/src/cs/Command/Executors/AppRestoreExecutor.cs +++ b/src/cs/Command/Executors/AppRestoreExecutor.cs @@ -1,20 +1,21 @@ -namespace macaroni; - -internal class AppRestoreExecutor : AppExecutorBase, ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public ExecutionResult Execute(IExecutionContext context) + internal class AppRestoreExecutor : AppExecutorBase, ICommandExecutor, ILoadedFromYamlFile { - MR.DBG_TRACE_INFO($"-- RESTORE: Execute({Title}, {Process}, {TitleOrProcess}, {Exclude}, {All}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO($"-- RESTORE: Execute({Title}, {Process}, {TitleOrProcess}, {Exclude}, {All}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - var titleOrProcess = context.Resolve(TitleOrProcess); - var process = context.Resolve(Process); - var title = context.Resolve(Title); - var exclude = context.Resolve(Exclude); - var all = context.Resolve(All); + var titleOrProcess = context.Resolve(TitleOrProcess); + var process = context.Resolve(Process); + var title = context.Resolve(Title); + var exclude = context.Resolve(Exclude); + var all = context.Resolve(All); - var runApp = this.GetParentOrService(); - runApp?.Restore(title, process, titleOrProcess, exclude, all == "true"); + var runApp = this.GetParentOrService(); + runApp?.Restore(title, process, titleOrProcess, exclude, all == "true"); - return ExecutionResult.Completed; + return ExecutionResult.Completed; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/AppRestoreExecutorYamlParser.cs b/src/cs/Command/Executors/AppRestoreExecutorYamlParser.cs index 13b45572..16bfd8b8 100644 --- a/src/cs/Command/Executors/AppRestoreExecutorYamlParser.cs +++ b/src/cs/Command/Executors/AppRestoreExecutorYamlParser.cs @@ -1,22 +1,25 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class AppRestoreExecutorYamlParser : ExecutorYamlParserBase_AppScalarMapping, IExecutorYamlParser +namespace macaroni { - public AppRestoreExecutorYamlParser(ISystemContext context) : base("restore", context) + internal class AppRestoreExecutorYamlParser : ExecutorYamlParserBase_AppScalarMapping, IExecutorYamlParser { - } + public AppRestoreExecutorYamlParser(ISystemContext context) : base("restore", context) + { + } - override protected ICommandExecutor CreateFromMapping(string file, YamlMappingNode mapping, string? titleOrProcess, string? title, string? process, string? exclude, string? all, IParsedValueWarningChecker? warnings) - { - return new AppRestoreExecutor() + override protected ICommandExecutor CreateFromMapping(string file, YamlMappingNode mapping, string? titleOrProcess, string? title, string? process, string? exclude, string? all, IParsedValueWarningChecker? warnings) { - TitleOrProcess = titleOrProcess, - Title = title, - Process = process, - Exclude = exclude, - All = all, - Yaml = mapping, - YamlFile = file - }; + return new AppRestoreExecutor() + { + TitleOrProcess = titleOrProcess, + Title = title, + Process = process, + Exclude = exclude, + All = all, + Yaml = mapping, + YamlFile = file + }; + } } } diff --git a/src/cs/Command/Executors/AppSwitchToExecutor.cs b/src/cs/Command/Executors/AppSwitchToExecutor.cs index cb124aaa..2a425993 100644 --- a/src/cs/Command/Executors/AppSwitchToExecutor.cs +++ b/src/cs/Command/Executors/AppSwitchToExecutor.cs @@ -1,20 +1,21 @@ -namespace macaroni; - -internal class AppSwitchToExecutor : AppExecutorBase, ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public ExecutionResult Execute(IExecutionContext context) + internal class AppSwitchToExecutor : AppExecutorBase, ICommandExecutor, ILoadedFromYamlFile { - MR.DBG_TRACE_INFO($"-- APP: Execute({Title}, {Process}, {TitleOrProcess}, {Exclude}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO($"-- APP: Execute({Title}, {Process}, {TitleOrProcess}, {Exclude}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - var titleOrProcess = context.Resolve(TitleOrProcess); - var process = context.Resolve(Process); - var title = context.Resolve(Title); - var exclude = context.Resolve(Exclude); + var titleOrProcess = context.Resolve(TitleOrProcess); + var process = context.Resolve(Process); + var title = context.Resolve(Title); + var exclude = context.Resolve(Exclude); - var runApp = this.GetParentOrService(); - runApp?.SwitchTo(title, process, titleOrProcess, exclude); + var runApp = this.GetParentOrService(); + runApp?.SwitchTo(title, process, titleOrProcess, exclude); - return ExecutionResult.Completed; - } + return ExecutionResult.Completed; + } -} + } +} \ No newline at end of file diff --git a/src/cs/Command/Executors/AppSwitchToExecutorYamlParser.cs b/src/cs/Command/Executors/AppSwitchToExecutorYamlParser.cs index 8e278aad..a4098296 100644 --- a/src/cs/Command/Executors/AppSwitchToExecutorYamlParser.cs +++ b/src/cs/Command/Executors/AppSwitchToExecutorYamlParser.cs @@ -1,22 +1,25 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class AppSwitchToExecutorYamlParser : ExecutorYamlParserBase_AppScalarMapping, IExecutorYamlParser +namespace macaroni { - public AppSwitchToExecutorYamlParser(ISystemContext context) : base("app", context) + internal class AppSwitchToExecutorYamlParser : ExecutorYamlParserBase_AppScalarMapping, IExecutorYamlParser { - } + public AppSwitchToExecutorYamlParser(ISystemContext context) : base("app", context) + { + } - override protected ICommandExecutor CreateFromMapping(string file, YamlMappingNode mapping, string? titleOrProcess, string? title, string? process, string? exclude, string? all, IParsedValueWarningChecker? warnings) - { - return new AppSwitchToExecutor() + override protected ICommandExecutor CreateFromMapping(string file, YamlMappingNode mapping, string? titleOrProcess, string? title, string? process, string? exclude, string? all, IParsedValueWarningChecker? warnings) { - TitleOrProcess = titleOrProcess, - Title = title, - Process = process, - Exclude = exclude, - All = all, - Yaml = mapping, - YamlFile = file - }; + return new AppSwitchToExecutor() + { + TitleOrProcess = titleOrProcess, + Title = title, + Process = process, + Exclude = exclude, + All = all, + Yaml = mapping, + YamlFile = file + }; + } } } diff --git a/src/cs/Command/Executors/BroadcastExecutor.cs b/src/cs/Command/Executors/BroadcastExecutor.cs index 78783c6f..a9dc351a 100644 --- a/src/cs/Command/Executors/BroadcastExecutor.cs +++ b/src/cs/Command/Executors/BroadcastExecutor.cs @@ -1,44 +1,47 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class BroadcastExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public BroadcastExecutor(string name, string? value) + internal class BroadcastExecutor : ICommandExecutor, ILoadedFromYamlFile { - Name = name; - Value = value; - } + public BroadcastExecutor(string name, string? value) + { + Name = name; + Value = value; + } - public string Name { get; set; } - public string? Value { get; set; } - public string? Scope { get; set; } + public string Name { get; set; } + public string? Value { get; set; } + public string? Scope { get; set; } - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public void LoadComplete(object parent) - { - YamlParent = parent; - } + public void LoadComplete(object parent) + { + YamlParent = parent; + } - public void Unload() - { - } + public void Unload() + { + } - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- BROADCAST: Execute({Name}, {Value}, {Scope}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO($"-- BROADCAST: Execute({Name}, {Value}, {Scope}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - var name = context.Resolve(Name); - var value = context.Resolve(Value); - var scope = context.Resolve(Scope); + var name = context.Resolve(Name); + var value = context.Resolve(Value); + var scope = context.Resolve(Scope); - var broadcast = this.GetRequiredParentOrService(); - if (name != null) - { - broadcast.BroadcastMessage(name, value, scope); - } + var broadcast = this.GetRequiredParentOrService(); + if (name != null) + { + broadcast.BroadcastMessage(name, value, scope); + } - return ExecutionResult.Completed; + return ExecutionResult.Completed; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/BroadcastExecutorYamlParser.cs b/src/cs/Command/Executors/BroadcastExecutorYamlParser.cs index 0089effc..79dac062 100644 --- a/src/cs/Command/Executors/BroadcastExecutorYamlParser.cs +++ b/src/cs/Command/Executors/BroadcastExecutorYamlParser.cs @@ -1,11 +1,14 @@ -namespace macaroni; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class BroadcastExecutorYamlParser : ExecutorYamlParserBase +namespace macaroni { - public BroadcastExecutorYamlParser(ISystemContext context) : base(context) { } + internal class BroadcastExecutorYamlParser : ExecutorYamlParserBase + { + public BroadcastExecutorYamlParser(ISystemContext context) : base(context) { } - public override string Kind { get { return "broadcast"; } } - public override bool TrySequenceOfStringRhs => false; + public override string Kind { get { return "broadcast"; } } + public override bool TrySequenceOfStringRhs => false; protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) { @@ -13,11 +16,12 @@ protected override ICommandExecutor ParseMapping(string file, YamlMappingNode ma var value = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "value", warnings); var scope = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "scope", warnings); - var allowed = scalar == null - ? new[] { "value", "scope", "name" } - : new[] { "value", "scope" }; - RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + var allowed = scalar == null + ? new[] { "value", "scope", "name" } + : new[] { "value", "scope" }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); - return new BroadcastExecutor(name, value) { Scope = scope, Yaml = mapping, YamlFile = file }; + return new BroadcastExecutor(name, value) { Scope = scope, Yaml = mapping, YamlFile = file }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/CancelExecutor.cs b/src/cs/Command/Executors/CancelExecutor.cs index 35cc6a38..10e85314 100644 --- a/src/cs/Command/Executors/CancelExecutor.cs +++ b/src/cs/Command/Executors/CancelExecutor.cs @@ -1,57 +1,62 @@ -namespace macaroni; +using System; +using System.Linq; +using YamlDotNet.RepresentationModel; -internal class CancelExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - public string? Cancel { get; internal set; } - - public void LoadComplete(object parent) + internal class CancelExecutor : ICommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; - } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } + public string? Cancel { get; internal set; } - public void Unload() - { - } + public void LoadComplete(object parent) + { + YamlParent = parent; + } - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- CANCEL: Execute(): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public void Unload() + { + } - var cancel = context.Resolve(Cancel); - var cancelSome = int.TryParse(cancel, out var cancelCount); - var cancelAll = !cancelSome && cancel?.ToLowerInvariant() == "all"; + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO($"-- CANCEL: Execute(): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - var invalidArgs = !cancelSome && !cancelAll && !string.IsNullOrEmpty(cancel); - if (invalidArgs) throw new ArgumentException($"Invalid cancel count: {cancel}"); + var cancel = context.Resolve(Cancel); + var cancelSome = int.TryParse(cancel, out var cancelCount); + var cancelAll = !cancelSome && cancel?.ToLowerInvariant() == "all"; - var command = this.GetRequiredParentOrService(); - var commandExecutionService = this.GetRequiredParentOrService(); + var invalidArgs = !cancelSome && !cancelAll && !string.IsNullOrEmpty(cancel); + if (invalidArgs) throw new ArgumentException($"Invalid cancel count: {cancel}"); - var notCompleted = commandExecutionService.GetNotCompleted().ToList(); - notCompleted.Reverse(); + var command = this.GetRequiredParentOrService(); + var commandExecutionService = this.GetRequiredParentOrService(); - cancelCount = cancelAll - ? notCompleted.Count() - : Math.Min(cancelCount, notCompleted.Count()); + var notCompleted = commandExecutionService.GetNotCompleted().ToList(); + notCompleted.Reverse(); - var canceledSelf = false; - for (var i = 0; i < cancelCount; i++) - { - var cancelCommand = notCompleted[i]; - commandExecutionService.Cancel(cancelCommand); + cancelCount = cancelAll + ? notCompleted.Count() + : Math.Min(cancelCount, notCompleted.Count()); - if (cancelCommand == command) + var canceledSelf = false; + for (var i = 0; i < cancelCount; i++) { - canceledSelf = true; + var cancelCommand = notCompleted[i]; + commandExecutionService.Cancel(cancelCommand); + + if (cancelCommand == command) + { + canceledSelf = true; + } } - } - var result = canceledSelf ? ExecutionResult.Canceled : ExecutionResult.Completed; - - MR.DBG_TRACE_INFO($"-- CANCEL: Execute(): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column}) - {result}"); - return result; + var result = canceledSelf ? ExecutionResult.Canceled : ExecutionResult.Completed; + + MR.DBG_TRACE_INFO($"-- CANCEL: Execute(): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column}) - {result}"); + return result; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/CancelExecutorYamlParser.cs b/src/cs/Command/Executors/CancelExecutorYamlParser.cs index b60349de..3c462f54 100644 --- a/src/cs/Command/Executors/CancelExecutorYamlParser.cs +++ b/src/cs/Command/Executors/CancelExecutorYamlParser.cs @@ -1,21 +1,32 @@ -namespace macaroni; +using System; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class CancelExecutorYamlParser : ExecutorYamlParserBase +namespace macaroni { - public CancelExecutorYamlParser(ISystemContext context) : base(context) { } + internal class CancelExecutorYamlParser : ExecutorYamlParserBase + { + public CancelExecutorYamlParser(ISystemContext context) : base(context) + { + } - public override string Kind { get { return "cancel"; } } - public override bool TrySequenceOfStringRhs => false; - public override bool TryMappingRhs => false; + public override string Kind + { + get { return "cancel"; } + } - protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) - { - RequireNoUnexpectedMappingKeys(file, mapping, Kind, Array.Empty()); - return new CancelExecutor() + public override bool TrySequenceOfStringRhs => false; + public override bool TryMappingRhs => false; + + protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) { - Cancel = scalar, - Yaml = mapping, - YamlFile = file - }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, Array.Empty()); + return new CancelExecutor() + { + Cancel = scalar, + Yaml = mapping, + YamlFile = file + }; + } } } diff --git a/src/cs/Command/Executors/ClipboardExecutor.cs b/src/cs/Command/Executors/ClipboardExecutor.cs index 0884892f..26e52fd7 100644 --- a/src/cs/Command/Executors/ClipboardExecutor.cs +++ b/src/cs/Command/Executors/ClipboardExecutor.cs @@ -1,45 +1,48 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class ClipboardExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public string? Set { get; set; } - public string? Clear { get; set; } - public string? Format { get; set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class ClipboardExecutor : ICommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; - } - - public void Unload() - { - } + public string? Set { get; set; } + public string? Clear { get; set; } + public string? Format { get; set; } - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- CLIPBOARD: Execute({Set}, {Clear}, {Format}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - - var set = context.Resolve(Set); - var clear = context.Resolve(Clear); - var format = context.Resolve(Format); + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - var clipboard = this.GetParentOrService(); - if (clear == "true") clipboard?.Clear(); + public void LoadComplete(object parent) + { + YamlParent = parent; + } - var image = context.ResolveImage(Set); - if (image != null && image is IImage) + public void Unload() { - clipboard?.Clear(); - clipboard?.SetImage(image); - return ExecutionResult.Completed; } - if (set != null) clipboard?.Set(set, format); + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO($"-- CLIPBOARD: Execute({Set}, {Clear}, {Format}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + + var set = context.Resolve(Set); + var clear = context.Resolve(Clear); + var format = context.Resolve(Format); + + var clipboard = this.GetParentOrService(); + if (clear == "true") clipboard?.Clear(); - return ExecutionResult.Completed; + var image = context.ResolveImage(Set); + if (image != null && image is IImage) + { + clipboard?.Clear(); + clipboard?.SetImage(image); + return ExecutionResult.Completed; + } + + if (set != null) clipboard?.Set(set, format); + + return ExecutionResult.Completed; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/ClipboardExecutorYamlParser.cs b/src/cs/Command/Executors/ClipboardExecutorYamlParser.cs index 21949092..67ab891e 100644 --- a/src/cs/Command/Executors/ClipboardExecutorYamlParser.cs +++ b/src/cs/Command/Executors/ClipboardExecutorYamlParser.cs @@ -1,12 +1,15 @@ -namespace macaroni; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class ClipboardExecutorYamlParser : ExecutorYamlParserBase +namespace macaroni { - public ClipboardExecutorYamlParser(ISystemContext context) : base(context) { } + internal class ClipboardExecutorYamlParser : ExecutorYamlParserBase + { + public ClipboardExecutorYamlParser(ISystemContext context) : base(context) { } - public override string Kind { get { return "clipboard"; } } - public override bool TrySequenceOfStringRhs => false; - public override bool RequireScalarRhsNotNull => false; + public override string Kind { get { return "clipboard"; } } + public override bool TrySequenceOfStringRhs => false; + public override bool RequireScalarRhsNotNull => false; protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) { @@ -14,16 +17,17 @@ protected override ICommandExecutor ParseMapping(string file, YamlMappingNode ma var clear = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "clear", warnings) ?? RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "empty", warnings); var format = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "format", warnings); - var allowed = scalar == null - ? new[] { "clear", "empty", "format", "set" } - : new[] { "clear", "empty", "format" }; - RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + var allowed = scalar == null + ? new[] { "clear", "empty", "format", "set" } + : new[] { "clear", "empty", "format" }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); - if (set == null && string.IsNullOrEmpty(clear)) - { - clear = "true"; - } + if (set == null && string.IsNullOrEmpty(clear)) + { + clear = "true"; + } - return new ClipboardExecutor() { Set = set, Clear = clear, Format = format, Yaml = mapping, YamlFile = file }; + return new ClipboardExecutor() { Set = set, Clear = clear, Format = format, Yaml = mapping, YamlFile = file }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/CommandExecutor.cs b/src/cs/Command/Executors/CommandExecutor.cs index cd188abd..69e94ba8 100644 --- a/src/cs/Command/Executors/CommandExecutor.cs +++ b/src/cs/Command/Executors/CommandExecutor.cs @@ -1,23 +1,26 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class CommandExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public YamlNode? Yaml { get; internal set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class CommandExecutor : ICommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; - } + public YamlNode? Yaml { get; internal set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public void Unload() - { - } + public void LoadComplete(object parent) + { + YamlParent = parent; + } - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- GENERIC COMMAND EXECUTOR: Execute(): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - return ExecutionResult.Completed; + public void Unload() + { + } + + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO($"-- GENERIC COMMAND EXECUTOR: Execute(): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + return ExecutionResult.Completed; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/CompleteExecutor.cs b/src/cs/Command/Executors/CompleteExecutor.cs index e75e4548..18ddd57a 100644 --- a/src/cs/Command/Executors/CompleteExecutor.cs +++ b/src/cs/Command/Executors/CompleteExecutor.cs @@ -1,66 +1,71 @@ -namespace macaroni; +using System.Threading.Tasks; +using YamlDotNet.RepresentationModel; -internal class CompleteExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public string? Prompt { get; set; } - - public string? Key { get; set; } - public string? Endpoint { get; set; } - public string? Deployment { get; set; } - - public string? MaxTokens { get; set; } - public string? Temperature { get; set; } - public string? FrequencyPenalty { get; set; } - public string? PresencePenalty { get; set; } - public string? TopP { get; set; } - public string? Stop { get; set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class CompleteExecutor : ICommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; - } + public string? Prompt { get; set; } - public void Unload() - { - } + public string? Key { get; set; } + public string? Endpoint { get; set; } + public string? Deployment { get; set; } - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- COMPLETE: Execute({Prompt}, {Deployment}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public string? MaxTokens { get; set; } + public string? Temperature { get; set; } + public string? FrequencyPenalty { get; set; } + public string? PresencePenalty { get; set; } + public string? TopP { get; set; } + public string? Stop { get; set; } + + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } + + public void LoadComplete(object parent) + { + YamlParent = parent; + } + + public void Unload() + { + } + + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO($"-- COMPLETE: Execute({Prompt}, {Deployment}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - var prompt = context.Resolve(Prompt); + var prompt = context.Resolve(Prompt); - var key = context.Resolve(Key); - var endpoint = context.Resolve(Endpoint); - var deployment = context.Resolve(Deployment); + var key = context.Resolve(Key); + var endpoint = context.Resolve(Endpoint); + var deployment = context.Resolve(Deployment); - var maxTokens = context.Resolve(MaxTokens); - var temperature = context.Resolve(Temperature); - var frequencyPenalty = context.Resolve(FrequencyPenalty); - var presencePenalty = context.Resolve(PresencePenalty); - var topP = context.Resolve(TopP); - var stop = context.Resolve(Stop); + var maxTokens = context.Resolve(MaxTokens); + var temperature = context.Resolve(Temperature); + var frequencyPenalty = context.Resolve(FrequencyPenalty); + var presencePenalty = context.Resolve(PresencePenalty); + var topP = context.Resolve(TopP); + var stop = context.Resolve(Stop); - Task.Run(async () => { + Task.Run(async () => + { - var service = this.GetRequiredParentOrService(); - var response = prompt != null - ? await service.Complete(prompt, key, endpoint, deployment, maxTokens, temperature, frequencyPenalty, presencePenalty, topP, stop) - : ""; + var service = this.GetRequiredParentOrService(); + var response = prompt != null + ? await service.Complete(prompt, key, endpoint, deployment, maxTokens, temperature, frequencyPenalty, presencePenalty, topP, stop) + : ""; - response = response - // .Replace("\n", "") - .Replace(" .", ".") - .Trim(); + response = response + // .Replace("\n", "") + .Replace(" .", ".") + .Trim(); - context.Set("complete.text", response); + context.Set("complete.text", response); - }).Wait(); + }).Wait(); - return ExecutionResult.Completed; + return ExecutionResult.Completed; + } } } diff --git a/src/cs/Command/Executors/CompleteExecutorYamlParser.cs b/src/cs/Command/Executors/CompleteExecutorYamlParser.cs index 836aeeec..eeaca820 100644 --- a/src/cs/Command/Executors/CompleteExecutorYamlParser.cs +++ b/src/cs/Command/Executors/CompleteExecutorYamlParser.cs @@ -1,11 +1,14 @@ -namespace macaroni; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class CompleteExecutorYamlParser : ExecutorYamlParserBase +namespace macaroni { - public CompleteExecutorYamlParser(ISystemContext context) : base(context) { } + internal class CompleteExecutorYamlParser : ExecutorYamlParserBase + { + public CompleteExecutorYamlParser(ISystemContext context) : base(context) { } - public override string Kind { get { return "complete"; } } - public override bool TrySequenceOfStringRhs => false; + public override string Kind { get { return "complete"; } } + public override bool TrySequenceOfStringRhs => false; protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) { @@ -22,27 +25,28 @@ protected override ICommandExecutor ParseMapping(string file, YamlMappingNode ma var topP = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "topP", warnings); var stop = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "stop", warnings); - var allowed = scalar == null - ? new[] { "key", "endpoint", "deployment", "maxTokens", "temperature", "frequencyPenalty", "presencePenalty", "topP", "stop", "prompt" } - : new[] { "key", "endpoint", "deployment", "maxTokens", "temperature", "frequencyPenalty", "presencePenalty", "topP", "stop" }; - RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); - - return new CompleteExecutor() - { - Prompt = prompt, - - Key = key, - Endpoint = endpoint, - Deployment = deployment, - - MaxTokens = maxTokens, - Temperature = temperature, - FrequencyPenalty = frequencyPenalty, - PresencePenalty = presencePenalty, - TopP = topP, - Stop = stop, - Yaml = mapping, - YamlFile = file - }; + var allowed = scalar == null + ? new[] { "key", "endpoint", "deployment", "maxTokens", "temperature", "frequencyPenalty", "presencePenalty", "topP", "stop", "prompt" } + : new[] { "key", "endpoint", "deployment", "maxTokens", "temperature", "frequencyPenalty", "presencePenalty", "topP", "stop" }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + + return new CompleteExecutor() + { + Prompt = prompt, + + Key = key, + Endpoint = endpoint, + Deployment = deployment, + + MaxTokens = maxTokens, + Temperature = temperature, + FrequencyPenalty = frequencyPenalty, + PresencePenalty = presencePenalty, + TopP = topP, + Stop = stop, + Yaml = mapping, + YamlFile = file + }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/ConfirmExecutor.cs b/src/cs/Command/Executors/ConfirmExecutor.cs index 90187782..18746ae9 100644 --- a/src/cs/Command/Executors/ConfirmExecutor.cs +++ b/src/cs/Command/Executors/ConfirmExecutor.cs @@ -1,25 +1,26 @@ -namespace macaroni; - -internal class ConfirmExecutor : MsgBoxExecutorBase, ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public ExecutionResult Execute(IExecutionContext context) + internal class ConfirmExecutor : MsgBoxExecutorBase, ICommandExecutor, ILoadedFromYamlFile { - MR.DBG_TRACE_INFO($"-- CONFIRM: Execute({Message}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO($"-- CONFIRM: Execute({Message}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - var title = context.Resolve(Title); - var message = context.Resolve(Message); - var timeout = context.Resolve(Timeout); + var title = context.Resolve(Title); + var message = context.Resolve(Message); + var timeout = context.Resolve(Timeout); - if (!string.IsNullOrEmpty(message)) - { - var msgbox = this.GetParentOrService(); - if (msgbox != null) + if (!string.IsNullOrEmpty(message)) { - var ok = msgbox.Confirm(message, title, timeout); - if (!ok) return ExecutionResult.Stopped; + var msgbox = this.GetParentOrService(); + if (msgbox != null) + { + var ok = msgbox.Confirm(message, title, timeout); + if (!ok) return ExecutionResult.Stopped; + } } - } - return ExecutionResult.Completed; + return ExecutionResult.Completed; + } } } diff --git a/src/cs/Command/Executors/ConfirmExecutorYamlParser.cs b/src/cs/Command/Executors/ConfirmExecutorYamlParser.cs index 386d1670..ad49270c 100644 --- a/src/cs/Command/Executors/ConfirmExecutorYamlParser.cs +++ b/src/cs/Command/Executors/ConfirmExecutorYamlParser.cs @@ -1,20 +1,23 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class ConfirmExecutorYamlParser : ExecutorYamlParserBase_MsgBoxScalarMapping, IExecutorYamlParser +namespace macaroni { - public ConfirmExecutorYamlParser(ISystemContext context) : base(context) { } + internal class ConfirmExecutorYamlParser : ExecutorYamlParserBase_MsgBoxScalarMapping, IExecutorYamlParser + { + public ConfirmExecutorYamlParser(ISystemContext context) : base(context) { } - public override string Kind { get { return "confirm"; } } + public override string Kind { get { return "confirm"; } } - protected override ICommandExecutor CreateFromMapping(string file, YamlMappingNode mapping, string message, string? title, string? timeout, IParsedValueWarningChecker? warnings) - { - return new ConfirmExecutor() + protected override ICommandExecutor CreateFromMapping(string file, YamlMappingNode mapping, string message, string? title, string? timeout, IParsedValueWarningChecker? warnings) { - Message = message, - Title = title, - Timeout = timeout, - Yaml = mapping, - YamlFile = file - }; + return new ConfirmExecutor() + { + Message = message, + Title = title, + Timeout = timeout, + Yaml = mapping, + YamlFile = file + }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/ContextPopulatingJsonParser.cs b/src/cs/Command/Executors/ContextPopulatingJsonParser.cs index 312d25ea..684b7ca8 100644 --- a/src/cs/Command/Executors/ContextPopulatingJsonParser.cs +++ b/src/cs/Command/Executors/ContextPopulatingJsonParser.cs @@ -1,116 +1,117 @@ using System.Text.Json; -namespace macaroni; - -internal class ContextPopulatingJsonParser +namespace macaroni { - public ContextPopulatingJsonParser(string defaultOutputName) + internal class ContextPopulatingJsonParser { - _defaultOutputName = defaultOutputName; - } - - public void PopulateContext(IExecutionContext context, string json, string path, string output) - { - var document = JsonDocument.Parse(json); - ParseElement(context, path, output, "", document.RootElement); - } + public ContextPopulatingJsonParser(string defaultOutputName) + { + _defaultOutputName = defaultOutputName; + } - private void ParseElement(IExecutionContext context, string path, string output, string name, JsonElement elem) - { - var outputJson = false; - var kind = elem.ValueKind; - switch (kind) + public void PopulateContext(IExecutionContext context, string json, string path, string output) { - case JsonValueKind.String: - ParseString(context, path, output, name, elem.GetString()); - break; - case JsonValueKind.Number: - ParseNumber(context, path, output, name, elem.GetDouble()); - break; - case JsonValueKind.Object: - ParseObject(context, path, output, name, elem.EnumerateObject()); - outputJson = true; - break; - case JsonValueKind.Array: - ParseArray(context, path, output, name, elem.EnumerateArray()); - outputJson = true; - break; - case JsonValueKind.True: - ParseBool(context, path, output, name, true); - break; - case JsonValueKind.False: - ParseBool(context, path, output, name, false); - break; + var document = JsonDocument.Parse(json); + ParseElement(context, path, output, "", document.RootElement); } - if (outputJson && TryGetOutputName(path, output, name, out var outputName)) + private void ParseElement(IExecutionContext context, string path, string output, string name, JsonElement elem) { - if (string.IsNullOrEmpty(outputName)) + var outputJson = false; + var kind = elem.ValueKind; + switch (kind) + { + case JsonValueKind.String: + ParseString(context, path, output, name, elem.GetString()); + break; + case JsonValueKind.Number: + ParseNumber(context, path, output, name, elem.GetDouble()); + break; + case JsonValueKind.Object: + ParseObject(context, path, output, name, elem.EnumerateObject()); + outputJson = true; + break; + case JsonValueKind.Array: + ParseArray(context, path, output, name, elem.EnumerateArray()); + outputJson = true; + break; + case JsonValueKind.True: + ParseBool(context, path, output, name, true); + break; + case JsonValueKind.False: + ParseBool(context, path, output, name, false); + break; + } + + if (outputJson && TryGetOutputName(path, output, name, out var outputName)) { - outputName = _defaultOutputName; + if (string.IsNullOrEmpty(outputName)) + { + outputName = _defaultOutputName; + } + context.Set(outputName!, elem.ToString()); } - context.Set(outputName!, elem.ToString()); } - } - private void ParseBool(IExecutionContext context, string path, string output, string name, bool value) - { - if (TryGetOutputName(path, output, name, out var outputName)) + private void ParseBool(IExecutionContext context, string path, string output, string name, bool value) { - context.Set(outputName!, value); + if (TryGetOutputName(path, output, name, out var outputName)) + { + context.Set(outputName!, value); + } } - } - private void ParseString(IExecutionContext context, string path, string output, string name, string? value) - { - if (value != null && TryGetOutputName(path, output, name, out var outputName)) + private void ParseString(IExecutionContext context, string path, string output, string name, string? value) { - context.Set(outputName!, value); + if (value != null && TryGetOutputName(path, output, name, out var outputName)) + { + context.Set(outputName!, value); + } } - } - private void ParseNumber(IExecutionContext context, string path, string output, string name, double value) - { - if (TryGetOutputName(path, output, name, out var outputName)) + private void ParseNumber(IExecutionContext context, string path, string output, string name, double value) { - context.Set(outputName!, value); + if (TryGetOutputName(path, output, name, out var outputName)) + { + context.Set(outputName!, value); + } } - } - private void ParseObject(IExecutionContext context, string path, string output, string name, JsonElement.ObjectEnumerator items) - { - foreach (var item in items) + private void ParseObject(IExecutionContext context, string path, string output, string name, JsonElement.ObjectEnumerator items) { - var fullName = name.Length >= 1 ? $"{name}.{item.Name}" : item.Name; - ParseElement(context, path, output, fullName, item.Value); + foreach (var item in items) + { + var fullName = name.Length >= 1 ? $"{name}.{item.Name}" : item.Name; + ParseElement(context, path, output, fullName, item.Value); + } } - } - private void ParseArray(IExecutionContext context, string path, string output, string name, JsonElement.ArrayEnumerator items) - { - var i = 0; - foreach (var item in items) + private void ParseArray(IExecutionContext context, string path, string output, string name, JsonElement.ArrayEnumerator items) { - var fullName = $"{name}[{i}]"; - ParseElement(context, path, output, fullName, item); + var i = 0; + foreach (var item in items) + { + var fullName = $"{name}[{i}]"; + ParseElement(context, path, output, fullName, item); + } } - } - private static bool TryGetOutputName(string path, string output, string name, out string? outputName) - { - outputName = null; - if (name.StartsWith(path)) + private static bool TryGetOutputName(string path, string output, string name, out string? outputName) { - outputName = name.Substring(path.Length).TrimStart('.'); - if (output.Length > 1) + outputName = null; + if (name.StartsWith(path)) { - outputName = outputName.Length > 1 - ? $"{output}.{outputName}" - : output; + outputName = name.Substring(path.Length).TrimStart('.'); + if (output.Length > 1) + { + outputName = outputName.Length > 1 + ? $"{output}.{outputName}" + : output; + } } + return outputName != null; } - return outputName != null; - } - private readonly string _defaultOutputName; -} + private readonly string _defaultOutputName; + } +} \ No newline at end of file diff --git a/src/cs/Command/Executors/DelayExecutor.cs b/src/cs/Command/Executors/DelayExecutor.cs index 8b4e7a68..f6667625 100644 --- a/src/cs/Command/Executors/DelayExecutor.cs +++ b/src/cs/Command/Executors/DelayExecutor.cs @@ -1,41 +1,48 @@ -namespace macaroni; +using System; +using System.Threading.Tasks; +using YamlDotNet.RepresentationModel; -internal class DelayExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public string? Time { get; set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class DelayExecutor : ICommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; - } + public string? Time { get; set; } - public void Unload() - { - } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- DELAY: Execute({Time}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public void LoadComplete(object parent) + { + YamlParent = parent; + } - var time = context.Resolve(Time); - var timeOk = int.TryParse(time, out var timeAsInt); - if (timeOk) + public void Unload() { - if (timeAsInt < 1000) - { - var stop = DateTime.Now.AddMilliseconds(timeAsInt); - while (DateTime.Now < stop) { } - } - else + } + + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO($"-- DELAY: Execute({Time}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + + var time = context.Resolve(Time); + var timeOk = int.TryParse(time, out var timeAsInt); + if (timeOk) { - Task.Delay(timeAsInt).Wait(); + if (timeAsInt < 1000) + { + var stop = DateTime.Now.AddMilliseconds(timeAsInt); + while (DateTime.Now < stop) + { + } + } + else + { + Task.Delay(timeAsInt).Wait(); + } } + + return ExecutionResult.Completed; } - - return ExecutionResult.Completed; } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/DelayExecutorYamlParser.cs b/src/cs/Command/Executors/DelayExecutorYamlParser.cs index 6cb816be..7fa1622f 100644 --- a/src/cs/Command/Executors/DelayExecutorYamlParser.cs +++ b/src/cs/Command/Executors/DelayExecutorYamlParser.cs @@ -1,19 +1,24 @@ -namespace macaroni; +using System; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class DelayExecutorYamlParser : ExecutorYamlParserBase +namespace macaroni { - public DelayExecutorYamlParser(ISystemContext context) : base(context) { } + internal class DelayExecutorYamlParser : ExecutorYamlParserBase + { + public DelayExecutorYamlParser(ISystemContext context) : base(context) { } - public override string Kind { get { return "delay"; } } - public override bool TrySequenceOfStringRhs => false; + public override string Kind { get { return "delay"; } } + public override bool TrySequenceOfStringRhs => false; protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) { string time = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "time", warnings); - var allowed = scalar == null ? new[] { "time" } : Array.Empty(); - RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + var allowed = scalar == null ? new[] { "time" } : Array.Empty(); + RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); - return new DelayExecutor() { Time = time, Yaml = mapping, YamlFile = file }; + return new DelayExecutor() { Time = time, Yaml = mapping, YamlFile = file }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/DialogExecutor.cs b/src/cs/Command/Executors/DialogExecutor.cs index 63ad19ba..56824468 100644 --- a/src/cs/Command/Executors/DialogExecutor.cs +++ b/src/cs/Command/Executors/DialogExecutor.cs @@ -1,41 +1,44 @@ -namespace macaroni; +using System.Linq; +using YamlDotNet.RepresentationModel; -internal class DialogExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public IExecutorCollection? Executors { get; internal set; } - public string? AutoPushPopListen { get; internal set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class DialogExecutor : ICommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; + public IExecutorCollection? Executors { get; internal set; } + public string? AutoPushPopListen { get; internal set; } - (Executors as ILoadedFromYamlFile)?.LoadComplete(this); - } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public void Unload() - { - (Executors as ILoadedFromYamlFile)?.Unload(); - } + public void LoadComplete(object parent) + { + YamlParent = parent; + + (Executors as ILoadedFromYamlFile)?.LoadComplete(this); + } + + public void Unload() + { + (Executors as ILoadedFromYamlFile)?.Unload(); + } public ExecutionResult Execute(IExecutionContext context) { MR.DBG_TRACE_INFO($"-- DIALOG: Execute({Executors?.Count()}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - var command = this.GetRequiredParentOrService(); - command.PersistContext(context, null, null); + var command = this.GetRequiredParentOrService(); + command.PersistContext(context, null, null); - var autoPushPopListen = context.Resolve(AutoPushPopListen); - var doAutoPushPopListen = string.IsNullOrEmpty(autoPushPopListen) || autoPushPopListen == "true"; - if (doAutoPushPopListen) - { - var turn = context.Get("context.turn", null) as string; - if (turn != "1") PopListeningState(context); - PushListeningState(context); - } + var autoPushPopListen = context.Resolve(AutoPushPopListen); + var doAutoPushPopListen = string.IsNullOrEmpty(autoPushPopListen) || autoPushPopListen == "true"; + if (doAutoPushPopListen) + { + var turn = context.Get("context.turn", null) as string; + if (turn != "1") PopListeningState(context); + PushListeningState(context); + } ExecutionResult result = ExecutionResult.Completed; while (true) @@ -93,41 +96,42 @@ private bool IsEnabled(ICommandExecutor executor, IExecutionContext context) return enabled; } - private bool ShouldContinue(ICommandExecutor? executor, IExecutionContext context) - { - var check = executor as IWhenExecutor; - var resolved = context.Resolve(check?.Continue); - return resolved == "true"; - } + private bool ShouldContinue(ICommandExecutor? executor, IExecutionContext context) + { + var check = executor as IWhenExecutor; + var resolved = context.Resolve(check?.Continue); + return resolved == "true"; + } - private void StartListening() - { - var intent = this.GetRequiredParentOrService(); + private void StartListening() + { + var intent = this.GetRequiredParentOrService(); - intent.SetState(intent.GetState() == ListeningState.Once - ? ListeningState.Once - : ListeningState.On); + intent.SetState(intent.GetState() == ListeningState.Once + ? ListeningState.Once + : ListeningState.On); - MR.DBG_TRACE_INFO($"DIALOG: ListeningState.{intent.GetState()} ***"); - } + MR.DBG_TRACE_INFO($"DIALOG: ListeningState.{intent.GetState()} ***"); + } - private void PushListeningState(IExecutionContext context) - { - var intent = this.GetRequiredParentOrService(); - var stash = intent.GetState(); - context.Set("listen.state.stash", stash); - MR.DBG_TRACE_INFO($"PushState = {stash}"); - } + private void PushListeningState(IExecutionContext context) + { + var intent = this.GetRequiredParentOrService(); + var stash = intent.GetState(); + context.Set("listen.state.stash", stash); + MR.DBG_TRACE_INFO($"PushState = {stash}"); + } - private void PopListeningState(IExecutionContext context) - { - var intent = this.GetRequiredParentOrService(); - var stashed = context.Get("listen.state.stash", null); - if (stashed != null) + private void PopListeningState(IExecutionContext context) { - MR.DBG_TRACE_INFO($"PopState = {stashed}"); - var restore = (ListeningState)stashed; - intent.SetState(restore); + var intent = this.GetRequiredParentOrService(); + var stashed = context.Get("listen.state.stash", null); + if (stashed != null) + { + MR.DBG_TRACE_INFO($"PopState = {stashed}"); + var restore = (ListeningState)stashed; + intent.SetState(restore); + } } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/DialogExecutorYamlParser.cs b/src/cs/Command/Executors/DialogExecutorYamlParser.cs index bd088ce9..eb870281 100644 --- a/src/cs/Command/Executors/DialogExecutorYamlParser.cs +++ b/src/cs/Command/Executors/DialogExecutorYamlParser.cs @@ -1,23 +1,25 @@ -using Microsoft.Extensions.DependencyInjection; +using System; +using Microsoft.Extensions.DependencyInjection; +using YamlDotNet.RepresentationModel; -namespace macaroni; - -internal class DialogExecutorYamlParser : YamlParserBase, IExecutorYamlParser +namespace macaroni { - public DialogExecutorYamlParser(IServiceProvider services, ISystemContext context) : base(context) + internal class DialogExecutorYamlParser : YamlParserBase, IExecutorYamlParser { - _serviceProvider = services; - } + public DialogExecutorYamlParser(IServiceProvider services, ISystemContext context) : base(context) + { + _serviceProvider = services; + } - public string Kind { get { return "dialog"; } } + public string Kind { get { return "dialog"; } } public ICommandExecutor Parse(string file, YamlMappingNode executor, YamlNode value, IParsedValueWarningChecker? warnings) { var sequence = value as YamlSequenceNode; if (sequence != null) return ParseSequence(file, executor, sequence, warnings); - throw ErrorParsingYamlException(file, value.Start.Line, value.Start.Column, "Unexpected YamlNode type", "EXPECTED: `dialog: {when executor sequence}`"); - } + throw ErrorParsingYamlException(file, value.Start.Line, value.Start.Column, "Unexpected YamlNode type", "EXPECTED: `dialog: {when executor sequence}`"); + } private ICommandExecutor ParseSequence(string file, YamlMappingNode executor, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) { @@ -26,25 +28,26 @@ private ICommandExecutor ParseSequence(string file, YamlMappingNode executor, Ya var executors = _executorsParser?.ExecutorsFromSequence(file, sequence, warnings); var autoPushPopListen = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, executor, "autoPushPopListen", warnings); - RequireNoUnexpectedMappingKeys(file, executor, Kind, new[] { "autoPushPopListen" }); + RequireNoUnexpectedMappingKeys(file, executor, Kind, new[] { "autoPushPopListen" }); - return new DialogExecutor() - { - Executors = executors, - AutoPushPopListen = autoPushPopListen, - Yaml = sequence, - YamlFile = file - }; - } + return new DialogExecutor() + { + Executors = executors, + AutoPushPopListen = autoPushPopListen, + Yaml = sequence, + YamlFile = file + }; + } - private void EnsureParsers() - { - if (_executorsParser == null) + private void EnsureParsers() { - _executorsParser = _serviceProvider.GetRequiredService(); + if (_executorsParser == null) + { + _executorsParser = _serviceProvider.GetRequiredService(); + } } - } - private readonly IServiceProvider _serviceProvider; - private IExecutorCollectionYamlParser? _executorsParser; -} + private readonly IServiceProvider _serviceProvider; + private IExecutorCollectionYamlParser? _executorsParser; + } +} \ No newline at end of file diff --git a/src/cs/Command/Executors/DisplayExecutor.cs b/src/cs/Command/Executors/DisplayExecutor.cs index c36cdba8..63ab12ec 100644 --- a/src/cs/Command/Executors/DisplayExecutor.cs +++ b/src/cs/Command/Executors/DisplayExecutor.cs @@ -1,40 +1,43 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class DisplayExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public string? Message { get; set; } - public string? Timeout { get; set; } - public string? From { get; set; } - public string? Pending { get; set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class DisplayExecutor : ICommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; - } - - public void Unload() - { - } + public string? Message { get; set; } + public string? Timeout { get; set; } + public string? From { get; set; } + public string? Pending { get; set; } - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- DISPLAY: Execute({Message}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - var message = context.Resolve(Message); - var timeout = context.Resolve(Timeout) ?? "0"; - var from = context.Resolve(From) ?? ""; - var pending = context.Resolve(Pending); + public void LoadComplete(object parent) + { + YamlParent = parent; + } - if (!string.IsNullOrEmpty(message)) + public void Unload() { - var osd = this.GetParentOrService(); - osd?.DisplayText(message, from, bool.TryParse(pending, out var pendingBool) ? pendingBool : null, int.Parse(timeout)); } - return ExecutionResult.Completed; + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO($"-- DISPLAY: Execute({Message}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + + var message = context.Resolve(Message); + var timeout = context.Resolve(Timeout) ?? "0"; + var from = context.Resolve(From) ?? ""; + var pending = context.Resolve(Pending); + + if (!string.IsNullOrEmpty(message)) + { + var osd = this.GetParentOrService(); + osd?.DisplayText(message, from, bool.TryParse(pending, out var pendingBool) ? pendingBool : (bool?)null, int.Parse(timeout)); + } + + return ExecutionResult.Completed; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/DisplayExecutorYamlParser.cs b/src/cs/Command/Executors/DisplayExecutorYamlParser.cs index 66ca8b16..e0d5b596 100644 --- a/src/cs/Command/Executors/DisplayExecutorYamlParser.cs +++ b/src/cs/Command/Executors/DisplayExecutorYamlParser.cs @@ -1,11 +1,14 @@ -namespace macaroni; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class DisplayExecutorYamlParser : ExecutorYamlParserBase +namespace macaroni { - public DisplayExecutorYamlParser(ISystemContext context) : base(context) { } + internal class DisplayExecutorYamlParser : ExecutorYamlParserBase + { + public DisplayExecutorYamlParser(ISystemContext context) : base(context) { } - public override string Kind { get { return "display"; } } - public override bool TrySequenceOfStringRhs => false; + public override string Kind { get { return "display"; } } + public override bool TrySequenceOfStringRhs => false; protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) { @@ -14,11 +17,12 @@ protected override ICommandExecutor ParseMapping(string file, YamlMappingNode ma var pending = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "pending", warnings); var timeout = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "timeout", warnings); - var allowed = scalar == null - ? new[] { "from", "pending", "timeout", "message" } - : new[] { "from", "pending", "timeout" }; - RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + var allowed = scalar == null + ? new[] { "from", "pending", "timeout", "message" } + : new[] { "from", "pending", "timeout" }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); - return new DisplayExecutor() { Message = message, From = from, Pending = pending, Timeout = timeout, Yaml = mapping, YamlFile = file }; + return new DisplayExecutor() { Message = message, From = from, Pending = pending, Timeout = timeout, Yaml = mapping, YamlFile = file }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/EmulateExecutor.cs b/src/cs/Command/Executors/EmulateExecutor.cs index 1a333c1f..b537d02b 100644 --- a/src/cs/Command/Executors/EmulateExecutor.cs +++ b/src/cs/Command/Executors/EmulateExecutor.cs @@ -1,28 +1,28 @@ -using System.Text.Json; +using YamlDotNet.RepresentationModel; -namespace macaroni; - -internal class EmulateExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public string? Emulate { get; set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class EmulateExecutor : ICommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; + public string? Emulate { get; set; } + + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - if (!this.IsEditorDesignMode()) + public void LoadComplete(object parent) { - _service = this.GetRequiredParentOrService(); + YamlParent = parent; + + if (!this.IsEditorDesignMode()) + { + _service = this.GetRequiredParentOrService(); + } } - } - public void Unload() - { - } + public void Unload() + { + } public ExecutionResult Execute(IExecutionContext context) { @@ -37,5 +37,6 @@ public ExecutionResult Execute(IExecutionContext context) return ExecutionResult.Completed; } - private IIntentRecognizerService? _service; -} + private IIntentRecognizerService? _service; + } +} \ No newline at end of file diff --git a/src/cs/Command/Executors/EmulateExecutorYamlParser.cs b/src/cs/Command/Executors/EmulateExecutorYamlParser.cs index 9a89d49f..dd7a0ad4 100644 --- a/src/cs/Command/Executors/EmulateExecutorYamlParser.cs +++ b/src/cs/Command/Executors/EmulateExecutorYamlParser.cs @@ -1,21 +1,26 @@ -namespace macaroni; +using System; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class EmulateExecutorYamlParser : ExecutorYamlParserBase +namespace macaroni { - public EmulateExecutorYamlParser(ISystemContext context) : base(context) { } + internal class EmulateExecutorYamlParser : ExecutorYamlParserBase + { + public EmulateExecutorYamlParser(ISystemContext context) : base(context) { } - public override string Kind { get { return "emulate"; } } - public override bool TrySequenceOfStringRhs => false; - public override bool TryMappingRhs => false; + public override string Kind { get { return "emulate"; } } + public override bool TrySequenceOfStringRhs => false; + public override bool TryMappingRhs => false; - protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) - { - RequireNoUnexpectedMappingKeys(file, mapping, Kind, Array.Empty()); - return new EmulateExecutor() + protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) { - Emulate = scalar, - Yaml = mapping, - YamlFile = file - }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, Array.Empty()); + return new EmulateExecutor() + { + Emulate = scalar, + Yaml = mapping, + YamlFile = file + }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/ExecutorCollection.cs b/src/cs/Command/Executors/ExecutorCollection.cs index f5fc2163..d741895d 100644 --- a/src/cs/Command/Executors/ExecutorCollection.cs +++ b/src/cs/Command/Executors/ExecutorCollection.cs @@ -1,30 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; using Newtonsoft.Json; +using YamlDotNet.RepresentationModel; -namespace macaroni; - -internal class ExecutorCollection : List, IExecutorCollection, ILoadedFromYamlFile +namespace macaroni { - public ExecutorCollection(IEnumerable executors) : base(executors) + internal class ExecutorCollection : List, IExecutorCollection, ILoadedFromYamlFile { - } + public ExecutorCollection(IEnumerable executors) : base(executors) + { + } - public YamlNode? Yaml { get; internal set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) - { - YamlParent = parent; - if (Yaml == null) Yaml = (parent as ILoadedFromYamlFile)?.Yaml; - if (YamlFile == null) YamlFile = (parent as ILoadedFromYamlFile)?.YamlFile; + public YamlNode? Yaml { get; internal set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - this.ForEach(x => (x as ILoadedFromYamlFile)?.LoadComplete(this)); - } + public void LoadComplete(object parent) + { + YamlParent = parent; + if (Yaml == null) Yaml = (parent as ILoadedFromYamlFile)?.Yaml; + if (YamlFile == null) YamlFile = (parent as ILoadedFromYamlFile)?.YamlFile; - public void Unload() - { - this.ForEach(x => (x as ILoadedFromYamlFile)?.Unload()); - } + this.ForEach(x => (x as ILoadedFromYamlFile)?.LoadComplete(this)); + } + + public void Unload() + { + this.ForEach(x => (x as ILoadedFromYamlFile)?.Unload()); + } public ExecutionResult Execute(IExecutionContext context) { @@ -53,9 +57,10 @@ public ExecutionResult Execute(IExecutionContext context) return ExecutionResult.Completed; } - private void BroadcastRuntimeException(Exception ex) - { - var broadcastEx = this.GetRequiredParentOrService(); - broadcastEx.BroadcastException(ExceptionKind.Runtime, ex); + private void BroadcastRuntimeException(Exception ex) + { + var broadcastEx = this.GetRequiredParentOrService(); + broadcastEx.BroadcastException(ExceptionKind.Runtime, ex); + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/ExecutorCollectionYamlParser.cs b/src/cs/Command/Executors/ExecutorCollectionYamlParser.cs index da521538..7a7d5d05 100644 --- a/src/cs/Command/Executors/ExecutorCollectionYamlParser.cs +++ b/src/cs/Command/Executors/ExecutorCollectionYamlParser.cs @@ -1,35 +1,38 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class ExecutorCollectionYamlParser : YamlParserBase, IExecutorCollectionYamlParser +namespace macaroni { - public ExecutorCollectionYamlParser(IExecutorFactory factory, ISystemContext context) : base(context) + internal class ExecutorCollectionYamlParser : YamlParserBase, IExecutorCollectionYamlParser { - _factory = factory; - } - - public IExecutorCollection? CheckForExecutors(string file, YamlMappingNode mapping, string executorsMappingName, IParsedValueWarningChecker? warnings) - { - var sequence = mapping.Children.ContainsKey(executorsMappingName) - ? mapping.Children[executorsMappingName] as YamlSequenceNode - : null; - return sequence != null - ? ExecutorsFromSequence(file, sequence, warnings) - : null; - } + public ExecutorCollectionYamlParser(IExecutorFactory factory, ISystemContext context) : base(context) + { + _factory = factory; + } - public IExecutorCollection ExecutorsFromSequence(string file, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) - { - var executors = RequireSequenceOf(file, sequence, - "executor", - (file, node) => _factory.ExecutorFromYamlNode(file, node, warnings), - (file, node) => ErrorUnexpectedNode(file, node, _factory.GetValidExecutorMappingTypes())); + public IExecutorCollection? CheckForExecutors(string file, YamlMappingNode mapping, string executorsMappingName, IParsedValueWarningChecker? warnings) + { + var sequence = mapping.Children.ContainsKey(executorsMappingName) + ? mapping.Children[executorsMappingName] as YamlSequenceNode + : null; + return sequence != null + ? ExecutorsFromSequence(file, sequence, warnings) + : null; + } - return new ExecutorCollection(executors) + public IExecutorCollection ExecutorsFromSequence(string file, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) { - Yaml = sequence, - YamlFile = file - }; - } + var executors = RequireSequenceOf(file, sequence, + "executor", + (file, node) => _factory.ExecutorFromYamlNode(file, node, warnings), + (file, node) => ErrorUnexpectedNode(file, node, _factory.GetValidExecutorMappingTypes())); - private readonly IExecutorFactory _factory; -} + return new ExecutorCollection(executors) + { + Yaml = sequence, + YamlFile = file + }; + } + + private readonly IExecutorFactory _factory; + } +} \ No newline at end of file diff --git a/src/cs/Command/Executors/ExecutorFactory.cs b/src/cs/Command/Executors/ExecutorFactory.cs index 5a7796b4..cd054c91 100644 --- a/src/cs/Command/Executors/ExecutorFactory.cs +++ b/src/cs/Command/Executors/ExecutorFactory.cs @@ -1,54 +1,58 @@ -namespace macaroni; +using System.Collections.Generic; +using System.Linq; +using YamlDotNet.RepresentationModel; -internal class ExecutorFactory : YamlParserBase, IExecutorFactory +namespace macaroni { - public ExecutorFactory(IEnumerable parsers, ISystemContext context) : base(context) + internal class ExecutorFactory : YamlParserBase, IExecutorFactory { - _parsers = parsers; - } - - public bool IsInvalidExecutorNode(YamlMappingNode mapping) - { - var count = mapping.Children - .Count(x => _validExecutorMappingTypeKeys - .Contains((x.Key as YamlScalarNode)?.Value)); - return count == 0; - } + public ExecutorFactory(IEnumerable parsers, ISystemContext context) : base(context) + { + _parsers = parsers; + } - public ICommandExecutor ExecutorFromYamlNode(string file, YamlNode node, IParsedValueWarningChecker? warnings) - { - var mapping = node as YamlMappingNode; - if (mapping == null || IsInvalidExecutorNode(mapping)) + public bool IsInvalidExecutorNode(YamlMappingNode mapping) { - var expected = GetValidExecutorMappingTypes(); - throw ErrorParsingYamlException(file, node.Start.Line, node.Start.Column, "Unexpected node value", $"EXPECTED: {expected}"); + var count = mapping.Children + .Count(x => _validExecutorMappingTypeKeys + .Contains((x.Key as YamlScalarNode)?.Value)); + return count == 0; } - return ParseExecutorFromMapping(file, mapping, warnings); - } + public ICommandExecutor ExecutorFromYamlNode(string file, YamlNode node, IParsedValueWarningChecker? warnings) + { + var mapping = node as YamlMappingNode; + if (mapping == null || IsInvalidExecutorNode(mapping)) + { + var expected = GetValidExecutorMappingTypes(); + throw ErrorParsingYamlException(file, node.Start.Line, node.Start.Column, "Unexpected node value", $"EXPECTED: {expected}"); + } - public string GetValidExecutorMappingTypes() - { - return string.Join(", ", _validExecutorMappingTypeKeys); - } + return ParseExecutorFromMapping(file, mapping, warnings); + } - private ICommandExecutor ParseExecutorFromMapping(string file, YamlMappingNode mapping, IParsedValueWarningChecker? warnings) - { - foreach (var kind in _validExecutorMappingTypeKeys) + public string GetValidExecutorMappingTypes() + { + return string.Join(", ", _validExecutorMappingTypeKeys); + } + + private ICommandExecutor ParseExecutorFromMapping(string file, YamlMappingNode mapping, IParsedValueWarningChecker? warnings) { - if (mapping.Children.ContainsKey(kind)) + foreach (var kind in _validExecutorMappingTypeKeys) { - var parser = _parsers.First(parser => parser.Kind == kind); - return parser.Parse(file, mapping, mapping.Children[parser.Kind], warnings); + if (mapping.Children.ContainsKey(kind)) + { + var parser = _parsers.First(parser => parser.Kind == kind); + return parser.Parse(file, mapping, mapping.Children[parser.Kind], warnings); + } } - } - return new CommandExecutor() { Yaml = mapping, YamlFile = file }; - } + return new CommandExecutor() { Yaml = mapping, YamlFile = file }; + } - private IEnumerable _parsers; - private static IEnumerable _validExecutorMappingTypeKeys = new string[] - { + private IEnumerable _parsers; + private static IEnumerable _validExecutorMappingTypeKeys = new string[] + { "alert", // message!, title "confirm", // message!, title "display", // message*, timeout @@ -100,12 +104,13 @@ private ICommandExecutor ParseExecutorFromMapping(string file, YamlMappingNode m "cancel", // scalar "broadcast", // name!, value, scope - "invoke", + "invoke", "javascript", // code!, language "script", // code!, language "android.intent", // action!, uri, extras "stop", // null - }; -} + }; + } +} \ No newline at end of file diff --git a/src/cs/Command/Executors/ExecutorYamlParserBase.cs b/src/cs/Command/Executors/ExecutorYamlParserBase.cs index 370c8b09..b2291b93 100644 --- a/src/cs/Command/Executors/ExecutorYamlParserBase.cs +++ b/src/cs/Command/Executors/ExecutorYamlParserBase.cs @@ -1,56 +1,65 @@ -namespace macaroni; +using System; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal abstract class ExecutorYamlParserBase : YamlParserBase, IExecutorYamlParser +namespace macaroni { - public ExecutorYamlParserBase(ISystemContext context) : base(context) { } - - public virtual string Kind => throw new NotImplementedException(); - public virtual bool TrySequenceOfStringRhs => true; - public virtual bool TryMappingRhs => true; - public virtual bool TryScalarRhs => true; - public virtual bool RequireScalarRhsNotNull => true; - - public virtual ICommandExecutor Parse(string file, YamlMappingNode executor, YamlNode value, IParsedValueWarningChecker? warnings) + internal abstract class ExecutorYamlParserBase : YamlParserBase, IExecutorYamlParser { - if (TryScalarRhs) + public ExecutorYamlParserBase(ISystemContext context) : base(context) { - var scalar = value as YamlScalarNode; - if (scalar != null) return ParseScalar(file, executor, scalar, warnings); } - if (TrySequenceOfStringRhs) - { - var sequence = value as YamlSequenceNode; - if (sequence != null) return ParseSequence(file, executor, sequence, warnings); - } + public virtual string Kind => throw new NotImplementedException(); + public virtual bool TrySequenceOfStringRhs => true; + public virtual bool TryMappingRhs => true; + public virtual bool TryScalarRhs => true; + public virtual bool RequireScalarRhsNotNull => true; - if (TryMappingRhs) + public virtual ICommandExecutor Parse(string file, YamlMappingNode executor, YamlNode value, + IParsedValueWarningChecker? warnings) { - var mapping = value as YamlMappingNode; - if (mapping != null) return ParseMapping(file, mapping, null, null, warnings); + if (TryScalarRhs) + { + var scalar = value as YamlScalarNode; + if (scalar != null) return ParseScalar(file, executor, scalar, warnings); + } + + if (TrySequenceOfStringRhs) + { + var sequence = value as YamlSequenceNode; + if (sequence != null) return ParseSequence(file, executor, sequence, warnings); + } + + if (TryMappingRhs) + { + var mapping = value as YamlMappingNode; + if (mapping != null) return ParseMapping(file, mapping, null, null, warnings); + } + + throw !TryMappingRhs + ? ExpectedStringValue(file, value) + : ExpectedMappingOrStringValueException(file, Kind, value); } - throw !TryMappingRhs - ? ExpectedStringValue(file, value) - : ExpectedMappingOrStringValueException(file, Kind, value); - } + protected virtual ICommandExecutor ParseScalar(string file, YamlMappingNode executor, YamlScalarNode scalar, IParsedValueWarningChecker? warnings) + { + var value = RequireScalarRhsNotNull + ? RequireScalarStringValueNotNullOrEmpty(file, Kind, scalar, + null) // don't parse warnings here, see next line of code below + : scalar.Value; - protected virtual ICommandExecutor ParseScalar(string file, YamlMappingNode executor, YamlScalarNode scalar, IParsedValueWarningChecker? warnings) - { - var value = RequireScalarRhsNotNull - ? RequireScalarStringValueNotNullOrEmpty(file, Kind, scalar, null) // don't parse warnings here, see next line of code below - : scalar.Value; + warnings?.CheckParsedValue(file, Kind, scalar, value); // check here instead - warnings?.CheckParsedValue(file, Kind, scalar, value); // check here instead + return ParseMapping(file, executor, value, null, warnings); + } - return ParseMapping(file, executor, value, null, warnings); - } + protected virtual ICommandExecutor ParseSequence(string file, YamlMappingNode executor, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) + { + var random = RequireSequenceOfStringsNotNullOrEmpty(file, Kind, sequence, warnings); + return ParseMapping(file, executor, null, random, warnings); + } - protected virtual ICommandExecutor ParseSequence(string file, YamlMappingNode executor, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) - { - var random = RequireSequenceOfStringsNotNullOrEmpty(file, Kind, sequence, warnings); - return ParseMapping(file, executor, null, random, warnings); + protected abstract ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings); } - - protected abstract ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings); } diff --git a/src/cs/Command/Executors/ExecutorYamlParserBase_AppScalarMapping.cs b/src/cs/Command/Executors/ExecutorYamlParserBase_AppScalarMapping.cs index b68d88f6..3c4d8a43 100644 --- a/src/cs/Command/Executors/ExecutorYamlParserBase_AppScalarMapping.cs +++ b/src/cs/Command/Executors/ExecutorYamlParserBase_AppScalarMapping.cs @@ -1,52 +1,55 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal abstract class ExecutorYamlParserBase_AppScalarMapping : YamlParserBase +namespace macaroni { - public ExecutorYamlParserBase_AppScalarMapping(string kind, ISystemContext context) : base(context) + internal abstract class ExecutorYamlParserBase_AppScalarMapping : YamlParserBase { - Kind = kind; - } + public ExecutorYamlParserBase_AppScalarMapping(string kind, ISystemContext context) : base(context) + { + Kind = kind; + } - public string Kind { get; protected set; } + public string Kind { get; protected set; } - virtual public ICommandExecutor Parse(string file, YamlMappingNode executor, YamlNode value, IParsedValueWarningChecker? warnings) - { - var scalar = value as YamlScalarNode; - if (scalar != null) return ParseScalar(file, executor, scalar, warnings); + virtual public ICommandExecutor Parse(string file, YamlMappingNode executor, YamlNode value, IParsedValueWarningChecker? warnings) + { + var scalar = value as YamlScalarNode; + if (scalar != null) return ParseScalar(file, executor, scalar, warnings); - var mapping = value as YamlMappingNode; - if (mapping != null) return ParseMapping(file, mapping, null, warnings); + var mapping = value as YamlMappingNode; + if (mapping != null) return ParseMapping(file, mapping, null, warnings); - throw ExpectedMappingOrStringValueException(file, Kind, value); - } + throw ExpectedMappingOrStringValueException(file, Kind, value); + } - virtual protected ICommandExecutor ParseScalar(string file, YamlMappingNode executor, YamlScalarNode scalar, IParsedValueWarningChecker? warnings) - { - string titleOrProcess = RequireScalarStringValueNotNullOrEmpty(file, Kind, scalar, warnings); - return ParseMapping(file, executor, titleOrProcess, warnings); - } + virtual protected ICommandExecutor ParseScalar(string file, YamlMappingNode executor, YamlScalarNode scalar, IParsedValueWarningChecker? warnings) + { + string titleOrProcess = RequireScalarStringValueNotNullOrEmpty(file, Kind, scalar, warnings); + return ParseMapping(file, executor, titleOrProcess, warnings); + } - virtual protected ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IParsedValueWarningChecker? warnings) - { - var titleOrProcess = scalar; - var title = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "title", warnings); - var process = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "process", warnings); - var exclude = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "exclude", warnings); - var all = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "all", warnings); - - var allowed = scalar == null - ? new[] { "process", "exclude", "all", "title" } - : new[] { "process", "exclude", "all" }; - RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); - - if (string.IsNullOrEmpty(title) && string.IsNullOrEmpty(process) && string.IsNullOrEmpty(titleOrProcess)) + virtual protected ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IParsedValueWarningChecker? warnings) { - var expected = $"`title: (string)` or `process: (string)`"; - throw ErrorParsingYamlException(file, mapping.Start.Line, mapping.Start.Column, $"Unexpected `{Kind}` mapping", $"EXPECTED: {expected}"); + var titleOrProcess = scalar; + var title = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "title", warnings); + var process = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "process", warnings); + var exclude = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "exclude", warnings); + var all = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "all", warnings); + + var allowed = scalar == null + ? new[] { "process", "exclude", "all", "title" } + : new[] { "process", "exclude", "all" }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + + if (string.IsNullOrEmpty(title) && string.IsNullOrEmpty(process) && string.IsNullOrEmpty(titleOrProcess)) + { + var expected = $"`title: (string)` or `process: (string)`"; + throw ErrorParsingYamlException(file, mapping.Start.Line, mapping.Start.Column, $"Unexpected `{Kind}` mapping", $"EXPECTED: {expected}"); + } + + return CreateFromMapping(file, mapping, titleOrProcess, title, process, exclude, all, warnings); } - return CreateFromMapping(file, mapping, titleOrProcess, title, process, exclude, all, warnings); + abstract protected ICommandExecutor CreateFromMapping(string file, YamlMappingNode mapping, string? titleOrProcess, string? title, string? process, string? exclude, string? all, IParsedValueWarningChecker? warnings); } - - abstract protected ICommandExecutor CreateFromMapping(string file, YamlMappingNode mapping, string? titleOrProcess, string? title, string? process, string? exclude, string? all, IParsedValueWarningChecker? warnings); -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/ExecutorYamlParserBase_MsgBoxScalarMapping.cs b/src/cs/Command/Executors/ExecutorYamlParserBase_MsgBoxScalarMapping.cs index 34ecd916..b9b66d7b 100644 --- a/src/cs/Command/Executors/ExecutorYamlParserBase_MsgBoxScalarMapping.cs +++ b/src/cs/Command/Executors/ExecutorYamlParserBase_MsgBoxScalarMapping.cs @@ -1,26 +1,30 @@ -namespace macaroni; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal abstract class ExecutorYamlParserBase_MsgBoxScalarMapping : ExecutorYamlParserBase +namespace macaroni { - public ExecutorYamlParserBase_MsgBoxScalarMapping(ISystemContext context) : base(context) { } + internal abstract class ExecutorYamlParserBase_MsgBoxScalarMapping : ExecutorYamlParserBase + { + public ExecutorYamlParserBase_MsgBoxScalarMapping(ISystemContext context) : base(context) { } - public override bool TrySequenceOfStringRhs => false; + public override bool TrySequenceOfStringRhs => false; - protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) - { - var message = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "message", warnings); - var title = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "title", warnings); - var timeout = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "timeout", warnings); + protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) + { + var message = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "message", warnings); + var title = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "title", warnings); + var timeout = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "timeout", warnings); - RequireNoUnexpectedMappingKeys(file, mapping, Kind, GetValidMappingKeys()); + RequireNoUnexpectedMappingKeys(file, mapping, Kind, GetValidMappingKeys()); - return CreateFromMapping(file, mapping, message, title, timeout, warnings); - } + return CreateFromMapping(file, mapping, message, title, timeout, warnings); + } - protected virtual string[] GetValidMappingKeys() - { - return new[] { "message", "title", "timeout" }; - } + protected virtual string[] GetValidMappingKeys() + { + return new[] { "message", "title", "timeout" }; + } - abstract protected ICommandExecutor CreateFromMapping(string file, YamlMappingNode mapping, string message, string? title, string? timeout, IParsedValueWarningChecker? warnings); -} + abstract protected ICommandExecutor CreateFromMapping(string file, YamlMappingNode mapping, string message, string? title, string? timeout, IParsedValueWarningChecker? warnings); + } +} \ No newline at end of file diff --git a/src/cs/Command/Executors/FileExecutor.cs b/src/cs/Command/Executors/FileExecutor.cs index 3ae82f49..ac9c1999 100644 --- a/src/cs/Command/Executors/FileExecutor.cs +++ b/src/cs/Command/Executors/FileExecutor.cs @@ -1,47 +1,52 @@ -namespace macaroni; +using System.IO; +using YamlDotNet.RepresentationModel; -internal class FileExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public string? File { get; set; } - public string? Write { get; set; } - public string? Append { get; set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class FileExecutor : ICommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; - } + public string? File { get; set; } + public string? Write { get; set; } + public string? Append { get; set; } - public void Unload() - { - } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- FILE: Execute({File}, {Write}, {Append}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public void LoadComplete(object parent) + { + YamlParent = parent; + } - var file = context.Resolve(File); - var write = context.Resolve(Write); - var append = context.Resolve(Append); + public void Unload() + { + } - if (!string.IsNullOrEmpty(file)) + public ExecutionResult Execute(IExecutionContext context) { - var writeOk = !string.IsNullOrEmpty(write); - var appendOk = !string.IsNullOrEmpty(append); + MR.DBG_TRACE_INFO($"-- FILE: Execute({File}, {Write}, {Append}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - var fi = new FileInfo(file); - fi.Directory?.Create(); + var file = context.Resolve(File); + var write = context.Resolve(Write); + var append = context.Resolve(Append); - if (writeOk) System.IO.File.WriteAllText(file, write); - if (appendOk) System.IO.File.AppendAllText(file, append); - - var content = System.IO.File.ReadAllText(file); - context.Set("file.text", content); - } + if (!string.IsNullOrEmpty(file)) + { + var writeOk = !string.IsNullOrEmpty(write); + var appendOk = !string.IsNullOrEmpty(append); + + var fi = new FileInfo(file); + fi.Directory?.Create(); + + if (writeOk) System.IO.File.WriteAllText(file, write); + if (appendOk) System.IO.File.AppendAllText(file, append); - return ExecutionResult.Completed; + var content = System.IO.File.ReadAllText(file); + context.Set("file.text", content); + } + + + return ExecutionResult.Completed; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/FileExecutorYamlParser.cs b/src/cs/Command/Executors/FileExecutorYamlParser.cs index d5e42d52..79ec5045 100644 --- a/src/cs/Command/Executors/FileExecutorYamlParser.cs +++ b/src/cs/Command/Executors/FileExecutorYamlParser.cs @@ -1,30 +1,34 @@ -namespace macaroni; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class FileExecutorYamlParser : ExecutorYamlParserBase +namespace macaroni { - public FileExecutorYamlParser(ISystemContext context) : base(context) { } - - public override string Kind { get { return "file"; } } - public override bool TrySequenceOfStringRhs => false; - - protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) + internal class FileExecutorYamlParser : ExecutorYamlParserBase { - var fileName = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "name", warnings); - var write = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "write", warnings); - var append = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "append", warnings); + public FileExecutorYamlParser(ISystemContext context) : base(context) { } - var allowed = scalar == null - ? new[] { "write", "append", "name" } - : new[] { "write", "append" }; - RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + public override string Kind { get { return "file"; } } + public override bool TrySequenceOfStringRhs => false; - return new FileExecutor() + protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) { - File = fileName, - Write = write, - Append = append, - Yaml = mapping, - YamlFile = file - }; + var fileName = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "name", warnings); + var write = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "write", warnings); + var append = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "append", warnings); + + var allowed = scalar == null + ? new[] { "write", "append", "name" } + : new[] { "write", "append" }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + + return new FileExecutor() + { + File = fileName, + Write = write, + Append = append, + Yaml = mapping, + YamlFile = file + }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/HttpExecutor.cs b/src/cs/Command/Executors/HttpExecutor.cs index 3b999a22..568fba3c 100644 --- a/src/cs/Command/Executors/HttpExecutor.cs +++ b/src/cs/Command/Executors/HttpExecutor.cs @@ -1,51 +1,57 @@ -namespace macaroni; +using System.Collections.Generic; +using System.Linq; +using YamlDotNet.RepresentationModel; -internal class HttpExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public string? Uri { get; set; } - public string? Content { get; set; } - public string? Method { get; set; } - public IEnumerable? Headers { get; set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class HttpExecutor : ICommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; - } + public string? Uri { get; set; } + public string? Content { get; set; } + public string? Method { get; set; } + public IEnumerable? Headers { get; set; } - public void Unload() - { - } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- HTTP: Execute({Uri}, {Method}, {Content}, {Headers?.Count()}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public void LoadComplete(object parent) + { + YamlParent = parent; + } - var uri = context.Resolve(Uri); - var content = context.Resolve(Content); - var method = context.Resolve(Method); - var headers = Headers?.Select(x => context.Resolve(x)!); + public void Unload() + { + } - if (uri != null) + public ExecutionResult Execute(IExecutionContext context) { - var httpClient = this.GetRequiredParentOrService(); - var send = httpClient.SendRequestAsync(uri, method, content, headers); - send.Wait(); + MR.DBG_TRACE_INFO( + $"-- HTTP: Execute({Uri}, {Method}, {Content}, {Headers?.Count()}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - var response = send.Result; - var read = response.Content.ReadAsStringAsync(); - read.Wait(); + var uri = context.Resolve(Uri); + var content = context.Resolve(Content); + var method = context.Resolve(Method); + var headers = Headers?.Select(x => context.Resolve(x)!); - if (read.Result != null) + if (uri != null) { - context.Set("http.response", read.Result); - context.Set("http.response.body", read.Result); // GPT suggested this one instead + var httpClient = this.GetRequiredParentOrService(); + var send = httpClient.SendRequestAsync(uri, method, content, headers); + send.Wait(); + + var response = send.Result; + var read = response.Content.ReadAsStringAsync(); + read.Wait(); + + if (read.Result != null) + { + context.Set("http.response", read.Result); + context.Set("http.response.body", read.Result); // GPT suggested this one instead + } } - } - return ExecutionResult.Completed; + return ExecutionResult.Completed; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/HttpExecutorYamlParser.cs b/src/cs/Command/Executors/HttpExecutorYamlParser.cs index 6892f174..f9742944 100644 --- a/src/cs/Command/Executors/HttpExecutorYamlParser.cs +++ b/src/cs/Command/Executors/HttpExecutorYamlParser.cs @@ -1,11 +1,14 @@ -namespace macaroni; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class HttpExecutorYamlParser : ExecutorYamlParserBase +namespace macaroni { - public HttpExecutorYamlParser(ISystemContext context) : base(context) { } + internal class HttpExecutorYamlParser : ExecutorYamlParserBase + { + public HttpExecutorYamlParser(ISystemContext context) : base(context) { } - public override string Kind { get { return "http"; } } - public override bool TrySequenceOfStringRhs => false; + public override string Kind { get { return "http"; } } + public override bool TrySequenceOfStringRhs => false; protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) { @@ -14,19 +17,20 @@ protected override ICommandExecutor ParseMapping(string file, YamlMappingNode ma var method = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "method", warnings); var headers = GetScalarStrings(file, mapping, "headers", warnings); - var allowed = scalar == null - ? new[] { "content", "method", "headers", "uri" } - : new[] { "content", "method", "headers" }; - RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + var allowed = scalar == null + ? new[] { "content", "method", "headers", "uri" } + : new[] { "content", "method", "headers" }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); - return new HttpExecutor() - { - Uri = uri, - Content = content, - Method = method, - Headers = headers, - Yaml = mapping, - YamlFile = file - }; + return new HttpExecutor() + { + Uri = uri, + Content = content, + Method = method, + Headers = headers, + Yaml = mapping, + YamlFile = file + }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/IWhenExecutor.cs b/src/cs/Command/Executors/IWhenExecutor.cs index c60bb1fb..4615537c 100644 --- a/src/cs/Command/Executors/IWhenExecutor.cs +++ b/src/cs/Command/Executors/IWhenExecutor.cs @@ -1,6 +1,7 @@ -namespace macaroni; - -public interface IWhenExecutor +namespace macaroni { - public string? Continue { get; } -} + public interface IWhenExecutor + { + public string? Continue { get; } + } +} \ No newline at end of file diff --git a/src/cs/Command/Executors/IfExecutor.cs b/src/cs/Command/Executors/IfExecutor.cs index 0befc511..bc59a69a 100644 --- a/src/cs/Command/Executors/IfExecutor.cs +++ b/src/cs/Command/Executors/IfExecutor.cs @@ -1,44 +1,48 @@ -namespace macaroni; +using System.Linq; +using YamlDotNet.RepresentationModel; - -internal class IfExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public IConditionCollection? Conditions { get; internal set; } - public IExecutorCollection? Then { get; internal set; } - public IExecutorCollection? Else { get; internal set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + + internal class IfExecutor : ICommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; + public IConditionCollection? Conditions { get; internal set; } + public IExecutorCollection? Then { get; internal set; } + public IExecutorCollection? Else { get; internal set; } - (Conditions as ILoadedFromYamlFile)?.LoadComplete(this); - (Then as ILoadedFromYamlFile)?.LoadComplete(this); - (Else as ILoadedFromYamlFile)?.LoadComplete(this); - } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public void Unload() - { - (Conditions as ILoadedFromYamlFile)?.Unload(); - (Then as ILoadedFromYamlFile)?.Unload(); - (Else as ILoadedFromYamlFile)?.Unload(); - } + public void LoadComplete(object parent) + { + YamlParent = parent; - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- IF: Execute(then={Then?.Count()}, else={Else?.Count()}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + (Conditions as ILoadedFromYamlFile)?.LoadComplete(this); + (Then as ILoadedFromYamlFile)?.LoadComplete(this); + (Else as ILoadedFromYamlFile)?.LoadComplete(this); + } - if (Conditions != null) + public void Unload() { - var ok = Conditions.IsSatisfied(context); - return ok - ? Then?.Execute(context) ?? ExecutionResult.Completed - : Else?.Execute(context) ?? ExecutionResult.Completed; + (Conditions as ILoadedFromYamlFile)?.Unload(); + (Then as ILoadedFromYamlFile)?.Unload(); + (Else as ILoadedFromYamlFile)?.Unload(); } - return ExecutionResult.Completed; + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO($"-- IF: Execute(then={Then?.Count()}, else={Else?.Count()}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + + if (Conditions != null) + { + var ok = Conditions.IsSatisfied(context); + return ok + ? Then?.Execute(context) ?? ExecutionResult.Completed + : Else?.Execute(context) ?? ExecutionResult.Completed; + } + + return ExecutionResult.Completed; + } } } diff --git a/src/cs/Command/Executors/IfExecutorYamlParser.cs b/src/cs/Command/Executors/IfExecutorYamlParser.cs index ae634651..23d39a0b 100644 --- a/src/cs/Command/Executors/IfExecutorYamlParser.cs +++ b/src/cs/Command/Executors/IfExecutorYamlParser.cs @@ -1,81 +1,84 @@ -using Microsoft.Extensions.DependencyInjection; +using System; +using Microsoft.Extensions.DependencyInjection; +using YamlDotNet.RepresentationModel; -namespace macaroni; - -internal class IfExecutorYamlParser : YamlParserBase, IExecutorYamlParser +namespace macaroni { - public IfExecutorYamlParser(IServiceProvider services, ISystemContext context) : base(context) - { - _serviceProvider = services; - } - - public string Kind { get { return "if"; } } - - public ICommandExecutor Parse(string file, YamlMappingNode executor, YamlNode value, IParsedValueWarningChecker? warnings) + internal class IfExecutorYamlParser : YamlParserBase, IExecutorYamlParser { - var sequence = value as YamlSequenceNode; - if (sequence != null) return ParseSequence(file, executor, sequence, warnings); - - var mapping = value as YamlMappingNode; - if (mapping != null) return ParseMapping(file, mapping, warnings); - - throw ErrorParsingYamlException(file, value.Start.Line, value.Start.Column, "Unexpected YamlNode type", "EXPECTED: `if: {condition sequence}` and `then: {executor sequence}`"); - } - - private ICommandExecutor ParseSequence(string file, YamlMappingNode executor, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) - { - EnsureParsers(); - - var conditions = _conditionsParser?.ConditionsFromSequence(file, sequence, warnings); - var thenExecutors = _executorsParser?.CheckForExecutors(file, executor, "then", warnings); - var elseExecutors = _executorsParser?.CheckForExecutors(file, executor, "else", warnings); + public IfExecutorYamlParser(IServiceProvider services, ISystemContext context) : base(context) + { + _serviceProvider = services; + } - RequireNoUnexpectedMappingKeys(file, executor, Kind, new[] { "then", "else" }); + public string Kind { get { return "if"; } } - return new IfExecutor() + public ICommandExecutor Parse(string file, YamlMappingNode executor, YamlNode value, IParsedValueWarningChecker? warnings) { - Conditions = conditions, - Then = thenExecutors, - Else = elseExecutors, - Yaml = executor, - YamlFile = file - }; - } + var sequence = value as YamlSequenceNode; + if (sequence != null) return ParseSequence(file, executor, sequence, warnings); - private ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, IParsedValueWarningChecker? warnings) - { - EnsureParsers(); - - var conditions = _conditionsParser?.CheckForConditions(file, mapping, "conditions", warnings); - var thenExecutors = _executorsParser?.CheckForExecutors(file, mapping, "then", warnings); - var elseExecutors = _executorsParser?.CheckForExecutors(file, mapping, "else", warnings); + var mapping = value as YamlMappingNode; + if (mapping != null) return ParseMapping(file, mapping, warnings); - RequireNoUnexpectedMappingKeys(file, mapping, Kind, new[] { "conditions", "then", "else" }); + throw ErrorParsingYamlException(file, value.Start.Line, value.Start.Column, "Unexpected YamlNode type", "EXPECTED: `if: {condition sequence}` and `then: {executor sequence}`"); + } - return new IfExecutor() + private ICommandExecutor ParseSequence(string file, YamlMappingNode executor, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) { - Conditions = conditions, - Then = thenExecutors, - Else = elseExecutors, - Yaml = mapping, - YamlFile = file - }; - } + EnsureParsers(); + + var conditions = _conditionsParser?.ConditionsFromSequence(file, sequence, warnings); + var thenExecutors = _executorsParser?.CheckForExecutors(file, executor, "then", warnings); + var elseExecutors = _executorsParser?.CheckForExecutors(file, executor, "else", warnings); + + RequireNoUnexpectedMappingKeys(file, executor, Kind, new[] { "then", "else" }); + + return new IfExecutor() + { + Conditions = conditions, + Then = thenExecutors, + Else = elseExecutors, + Yaml = executor, + YamlFile = file + }; + } - private void EnsureParsers() - { - if (_conditionsParser == null) + private ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, IParsedValueWarningChecker? warnings) { - _conditionsParser = _serviceProvider.GetRequiredService(); + EnsureParsers(); + + var conditions = _conditionsParser?.CheckForConditions(file, mapping, "conditions", warnings); + var thenExecutors = _executorsParser?.CheckForExecutors(file, mapping, "then", warnings); + var elseExecutors = _executorsParser?.CheckForExecutors(file, mapping, "else", warnings); + + RequireNoUnexpectedMappingKeys(file, mapping, Kind, new[] { "conditions", "then", "else" }); + + return new IfExecutor() + { + Conditions = conditions, + Then = thenExecutors, + Else = elseExecutors, + Yaml = mapping, + YamlFile = file + }; } - if (_executorsParser == null) + private void EnsureParsers() { - _executorsParser = _serviceProvider.GetRequiredService(); + if (_conditionsParser == null) + { + _conditionsParser = _serviceProvider.GetRequiredService(); + } + + if (_executorsParser == null) + { + _executorsParser = _serviceProvider.GetRequiredService(); + } } - } - private readonly IServiceProvider _serviceProvider; - private IConditionCollectionYamlParser? _conditionsParser; - private IExecutorCollectionYamlParser? _executorsParser; -} + private readonly IServiceProvider _serviceProvider; + private IConditionCollectionYamlParser? _conditionsParser; + private IExecutorCollectionYamlParser? _executorsParser; + } +} \ No newline at end of file diff --git a/src/cs/Command/Executors/InsertTextExecutor.cs b/src/cs/Command/Executors/InsertTextExecutor.cs index 2659161e..c3b31269 100644 --- a/src/cs/Command/Executors/InsertTextExecutor.cs +++ b/src/cs/Command/Executors/InsertTextExecutor.cs @@ -1,33 +1,37 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class InsertTextExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public string? Text { get; set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class InsertTextExecutor : ICommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; - } + public string? Text { get; set; } - public void Unload() - { - } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- INSERTTEXT: Execute({Text}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public void LoadComplete(object parent) + { + YamlParent = parent; + } - var text = context.Resolve(Text); - if (!string.IsNullOrEmpty(text)) + public void Unload() { - var sendKeys = this.GetParentOrService(); - sendKeys?.InsertText(text); } - return ExecutionResult.Completed; + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO($"-- INSERTTEXT: Execute({Text}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + + var text = context.Resolve(Text); + if (!string.IsNullOrEmpty(text)) + { + var sendKeys = this.GetParentOrService(); + sendKeys?.InsertText(text); + } + + + return ExecutionResult.Completed; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/InsertTextExecutorYamlParser.cs b/src/cs/Command/Executors/InsertTextExecutorYamlParser.cs index bb3a109e..c68e15f0 100644 --- a/src/cs/Command/Executors/InsertTextExecutorYamlParser.cs +++ b/src/cs/Command/Executors/InsertTextExecutorYamlParser.cs @@ -1,19 +1,24 @@ -namespace macaroni; +using System; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class InsertTextExecutorYamlParser : ExecutorYamlParserBase +namespace macaroni { - public InsertTextExecutorYamlParser(ISystemContext context) : base(context) { } + internal class InsertTextExecutorYamlParser : ExecutorYamlParserBase + { + public InsertTextExecutorYamlParser(ISystemContext context) : base(context) { } - public override string Kind { get { return "insert"; } } - public override bool TrySequenceOfStringRhs => false; + public override string Kind { get { return "insert"; } } + public override bool TrySequenceOfStringRhs => false; - protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) - { - var text = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "text", warnings); + protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) + { + var text = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "text", warnings); - var allowed = scalar == null ? new[] { "text" } : Array.Empty(); - RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + var allowed = scalar == null ? new[] { "text" } : Array.Empty(); + RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); - return new InsertTextExecutor() { Text = text, Yaml = mapping, YamlFile = file }; + return new InsertTextExecutor() { Text = text, Yaml = mapping, YamlFile = file }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/JavascriptExecutorYamlParser.cs b/src/cs/Command/Executors/JavascriptExecutorYamlParser.cs index 7f146fde..53318a17 100644 --- a/src/cs/Command/Executors/JavascriptExecutorYamlParser.cs +++ b/src/cs/Command/Executors/JavascriptExecutorYamlParser.cs @@ -1,8 +1,9 @@ -namespace macaroni; - -internal class JavaScriptExecutorYamlParser : ScriptExecutorYamlParser +namespace macaroni { - public JavaScriptExecutorYamlParser(ISystemContext context) : base(context) { } + internal class JavaScriptExecutorYamlParser : ScriptExecutorYamlParser + { + public JavaScriptExecutorYamlParser(ISystemContext context) : base(context) { } - public override string Kind { get { return "javascript"; } } -} + public override string Kind { get { return "javascript"; } } + } +} \ No newline at end of file diff --git a/src/cs/Command/Executors/JsonExecutor.cs b/src/cs/Command/Executors/JsonExecutor.cs index 2981c635..f7c43ad2 100644 --- a/src/cs/Command/Executors/JsonExecutor.cs +++ b/src/cs/Command/Executors/JsonExecutor.cs @@ -1,39 +1,42 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class JsonExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public string? Data { get; set; } - public string? Path { get; set; } - public string? Output { get; set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class JsonExecutor : ICommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; - } + public string? Data { get; set; } + public string? Path { get; set; } + public string? Output { get; set; } - public void Unload() - { - } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- JSON: Execute({Data}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public void LoadComplete(object parent) + { + YamlParent = parent; + } - var data = context.Resolve(Data); - var path = context.Resolve(Path) ?? ""; - var output = context.Resolve(Output) ?? ""; + public void Unload() + { + } - if (data != null) + public ExecutionResult Execute(IExecutionContext context) { - _parser.PopulateContext(context, data, path, output); + MR.DBG_TRACE_INFO($"-- JSON: Execute({Data}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + + var data = context.Resolve(Data); + var path = context.Resolve(Path) ?? ""; + var output = context.Resolve(Output) ?? ""; + + if (data != null) + { + _parser.PopulateContext(context, data, path, output); + } + + return ExecutionResult.Completed; } - return ExecutionResult.Completed; + private ContextPopulatingJsonParser _parser = new ContextPopulatingJsonParser("json"); } - - private ContextPopulatingJsonParser _parser = new ContextPopulatingJsonParser("json"); -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/JsonExecutorYamlParser.cs b/src/cs/Command/Executors/JsonExecutorYamlParser.cs index e9ff8453..e8c1c5ed 100644 --- a/src/cs/Command/Executors/JsonExecutorYamlParser.cs +++ b/src/cs/Command/Executors/JsonExecutorYamlParser.cs @@ -1,30 +1,34 @@ -namespace macaroni; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class JsonExecutorYamlParser : ExecutorYamlParserBase +namespace macaroni { - public JsonExecutorYamlParser(ISystemContext context) : base(context) { } - - public override string Kind { get { return "json"; } } - public override bool TrySequenceOfStringRhs => false; - - protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) + internal class JsonExecutorYamlParser : ExecutorYamlParserBase { - var json = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "data", warnings); - var path = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "path", warnings); - var output = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "output", warnings) ?? path; + public JsonExecutorYamlParser(ISystemContext context) : base(context) { } - var allowed = scalar == null - ? new[] { "path", "output", "data" } - : new[] { "path", "output" }; - RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + public override string Kind { get { return "json"; } } + public override bool TrySequenceOfStringRhs => false; - return new JsonExecutor() + protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) { - Data = json, - Path = path, - Output = output, - Yaml = mapping, - YamlFile = file - }; + var json = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "data", warnings); + var path = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "path", warnings); + var output = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "output", warnings) ?? path; + + var allowed = scalar == null + ? new[] { "path", "output", "data" } + : new[] { "path", "output" }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + + return new JsonExecutor() + { + Data = json, + Path = path, + Output = output, + Yaml = mapping, + YamlFile = file + }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/ListenExecutor.cs b/src/cs/Command/Executors/ListenExecutor.cs index 7b6fbdac..747ae3fc 100644 --- a/src/cs/Command/Executors/ListenExecutor.cs +++ b/src/cs/Command/Executors/ListenExecutor.cs @@ -1,71 +1,75 @@ -namespace macaroni; +using System; +using YamlDotNet.RepresentationModel; -internal class ListenExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public string? State { get; set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class ListenExecutor : ICommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; - } + public string? State { get; set; } - public void Unload() - { - } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- LISTEN: Execute({State}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public void LoadComplete(object parent) + { + YamlParent = parent; + } - var state = context.Resolve(State); - if (!string.IsNullOrEmpty(state)) + public void Unload() { - if (state == "pop") - { - PopState(context); - } - else if (state == "push") - { - PushState(context); - } - else + } + + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO($"-- LISTEN: Execute({State}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + + var state = context.Resolve(State); + if (!string.IsNullOrEmpty(state)) { - SetState(context, state); + if (state == "pop") + { + PopState(context); + } + else if (state == "push") + { + PushState(context); + } + else + { + SetState(context, state); + } } - } - return ExecutionResult.Completed; - } + return ExecutionResult.Completed; + } - private UInt64 SetState(IExecutionContext context, string state) - { - var intent = this.GetRequiredParentOrService(); - return intent.SetState(state.ToLower() == "toggle" - ? ListeningStateHelpers.ToggleState(intent.GetState()) - : ListeningStateHelpers.Parse(state)); - } + private UInt64 SetState(IExecutionContext context, string state) + { + var intent = this.GetRequiredParentOrService(); + return intent.SetState(state.ToLower() == "toggle" + ? ListeningStateHelpers.ToggleState(intent.GetState()) + : ListeningStateHelpers.Parse(state)); + } - private void PushState(IExecutionContext context) - { - var intent = this.GetRequiredParentOrService(); - var stash = intent.GetState(); - context.Set("listen.state.stash", stash); - MR.DBG_TRACE_INFO($"PushState = {stash}"); - } + private void PushState(IExecutionContext context) + { + var intent = this.GetRequiredParentOrService(); + var stash = intent.GetState(); + context.Set("listen.state.stash", stash); + MR.DBG_TRACE_INFO($"PushState = {stash}"); + } - private void PopState(IExecutionContext context) - { - var intent = this.GetRequiredParentOrService(); - var stashed = context.Get("listen.state.stash", null); - if (stashed != null) + private void PopState(IExecutionContext context) { - MR.DBG_TRACE_INFO($"PopState = {stashed}"); - var restore = (ListeningState)stashed; - intent.SetState(restore); + var intent = this.GetRequiredParentOrService(); + var stashed = context.Get("listen.state.stash", null); + if (stashed != null) + { + MR.DBG_TRACE_INFO($"PopState = {stashed}"); + var restore = (ListeningState)stashed; + intent.SetState(restore); + } } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/ListenExecutorYamlParser.cs b/src/cs/Command/Executors/ListenExecutorYamlParser.cs index 162a1042..e8cfb86d 100644 --- a/src/cs/Command/Executors/ListenExecutorYamlParser.cs +++ b/src/cs/Command/Executors/ListenExecutorYamlParser.cs @@ -1,19 +1,24 @@ -namespace macaroni; +using System; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class ListenExecutorYamlParser : ExecutorYamlParserBase +namespace macaroni { - public ListenExecutorYamlParser(ISystemContext context) : base(context) { } + internal class ListenExecutorYamlParser : ExecutorYamlParserBase + { + public ListenExecutorYamlParser(ISystemContext context) : base(context) { } - public override string Kind { get { return "listen"; } } - public override bool TrySequenceOfStringRhs => false; + public override string Kind { get { return "listen"; } } + public override bool TrySequenceOfStringRhs => false; - protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) - { - var state = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "state", warnings); + protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) + { + var state = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "state", warnings); - var allowed = scalar == null ? new[] { "state" } : Array.Empty(); - RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + var allowed = scalar == null ? new[] { "state" } : Array.Empty(); + RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); - return new ListenExecutor() { State = state, Yaml = mapping, YamlFile = file }; + return new ListenExecutor() { State = state, Yaml = mapping, YamlFile = file }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/LogExecutor.cs b/src/cs/Command/Executors/LogExecutor.cs index b56ad327..834eb76b 100644 --- a/src/cs/Command/Executors/LogExecutor.cs +++ b/src/cs/Command/Executors/LogExecutor.cs @@ -1,54 +1,55 @@ -using System.Text.Json; +using YamlDotNet.RepresentationModel; -namespace macaroni; - -internal class LogExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public string? Message { get; set; } - public string? Level { get; set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class LogExecutor : ICommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; - } + public string? Message { get; set; } + public string? Level { get; set; } - public void Unload() - { - } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- LOG: Execute({Message}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - - var message = context.Resolve(Message); - var level = context.Resolve(Level)?.ToLower(); + public void LoadComplete(object parent) + { + YamlParent = parent; + } - if (message != null) + public void Unload() { - switch (level) - { - case "error": - MR.DBG_TRACE_ERROR(message); - break; + } - case "warning": - MR.DBG_TRACE_WARNING(message); - break; + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO($"-- LOG: Execute({Message}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - case "verbose": - MR.DBG_TRACE_VERBOSE(message); - break; + var message = context.Resolve(Message); + var level = context.Resolve(Level)?.ToLower(); - default: - MR.DBG_TRACE_INFO(message); - break; + if (message != null) + { + switch (level) + { + case "error": + MR.DBG_TRACE_ERROR(message); + break; + + case "warning": + MR.DBG_TRACE_WARNING(message); + break; + + case "verbose": + MR.DBG_TRACE_VERBOSE(message); + break; + + default: + MR.DBG_TRACE_INFO(message); + break; + } } - } - return ExecutionResult.Completed; + return ExecutionResult.Completed; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/LogExecutorYamlParser.cs b/src/cs/Command/Executors/LogExecutorYamlParser.cs index 5369b879..9ce71395 100644 --- a/src/cs/Command/Executors/LogExecutorYamlParser.cs +++ b/src/cs/Command/Executors/LogExecutorYamlParser.cs @@ -1,28 +1,32 @@ -namespace macaroni; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class LogExecutorYamlParser : ExecutorYamlParserBase +namespace macaroni { - public LogExecutorYamlParser(ISystemContext context) : base(context) { } - - public override string Kind { get { return "log"; } } - public override bool TrySequenceOfStringRhs => false; - - protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) + internal class LogExecutorYamlParser : ExecutorYamlParserBase { - var message = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "message", warnings); - var level = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "level", warnings); + public LogExecutorYamlParser(ISystemContext context) : base(context) { } - var allowed = scalar == null - ? new[] { "level", "message" } - : new[] { "level" }; - RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + public override string Kind { get { return "log"; } } + public override bool TrySequenceOfStringRhs => false; - return new LogExecutor() + protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) { - Message = message, - Level = level, - Yaml = mapping, - YamlFile = file - }; + var message = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "message", warnings); + var level = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "level", warnings); + + var allowed = scalar == null + ? new[] { "level", "message" } + : new[] { "level" }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + + return new LogExecutor() + { + Message = message, + Level = level, + Yaml = mapping, + YamlFile = file + }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/MouseExecutor.cs b/src/cs/Command/Executors/MouseExecutor.cs index 7ab9da08..0415c7fa 100644 --- a/src/cs/Command/Executors/MouseExecutor.cs +++ b/src/cs/Command/Executors/MouseExecutor.cs @@ -1,63 +1,66 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class MouseExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public string? Action { get; set; } - public string? Position { get; set; } - public string? PosititionRelativeTo { get; set; } - public string? Button { get; set; } - public string? Element { get; set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class MouseExecutor : ICommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; - } + public string? Action { get; set; } + public string? Position { get; set; } + public string? PosititionRelativeTo { get; set; } + public string? Button { get; set; } + public string? Element { get; set; } - public void Unload() - { - } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- MOUSE: Execute({Action}, {Position}, {Element}, {Button}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public void LoadComplete(object parent) + { + YamlParent = parent; + } - var action = context.Resolve(Action); - var position = context.Resolve(Position); - var positionRelative = context.Resolve(PosititionRelativeTo); - var button = context.Resolve(Button); - var element = context.Resolve(Element); + public void Unload() + { + } - if (action != null) + public ExecutionResult Execute(IExecutionContext context) { - if (!string.IsNullOrEmpty(element)) + MR.DBG_TRACE_INFO($"-- MOUSE: Execute({Action}, {Position}, {Element}, {Button}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + + var action = context.Resolve(Action); + var position = context.Resolve(Position); + var positionRelative = context.Resolve(PosititionRelativeTo); + var button = context.Resolve(Button); + var element = context.Resolve(Element); + + if (action != null) { - MR.DBG_TRACE_VERBOSE($"-- MOUSE: finding element={element}"); - var uia = this.GetRequiredParentOrService(); - if (!uia.GetPosition(element, out var rect)) + if (!string.IsNullOrEmpty(element)) { - MR.DBG_TRACE_WARNING($"-- MOUSE: Execute ... FAILED to find Element!"); - return ExecutionResult.Stopped; - } + MR.DBG_TRACE_VERBOSE($"-- MOUSE: finding element={element}"); + var uia = this.GetRequiredParentOrService(); + if (!uia.GetPosition(element, out var rect)) + { + MR.DBG_TRACE_WARNING($"-- MOUSE: Execute ... FAILED to find Element!"); + return ExecutionResult.Stopped; + } + + var x = rect.Left + rect.Width / 2; + var y = rect.Top + rect.Height / 2; + positionRelative = $"{x},{y}"; - var x = rect.Left + rect.Width / 2; - var y = rect.Top + rect.Height / 2; - positionRelative = $"{x},{y}"; + MR.DBG_TRACE_VERBOSE($"-- MOUSE: FOUND element=[{rect.Left},{rect.Top} w={rect.Width},{rect.Height}]; center={positionRelative}"); + } - MR.DBG_TRACE_VERBOSE($"-- MOUSE: FOUND element=[{rect.Left},{rect.Top} w={rect.Width},{rect.Height}]; center={positionRelative}"); + var mouse = this.GetRequiredParentOrService(); + if (action == "move") mouse.Move(position, positionRelative); + if (action.EndsWith("click")) mouse.ClickButton(position, positionRelative, button); + if (action.StartsWith("double-")) mouse.ClickButton(position, positionRelative, button); + if (action == "press") mouse.PressButton(position, positionRelative, button); + if (action == "release") mouse.ReleaseButton(position, positionRelative, button); } - var mouse = this.GetRequiredParentOrService(); - if (action == "move") mouse.Move(position, positionRelative); - if (action.EndsWith("click")) mouse.ClickButton(position, positionRelative, button); - if (action.StartsWith("double-")) mouse.ClickButton(position, positionRelative, button); - if (action == "press") mouse.PressButton(position, positionRelative, button); - if (action == "release") mouse.ReleaseButton(position, positionRelative, button); + return ExecutionResult.Completed; } - - return ExecutionResult.Completed; } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/MouseExecutorYamlParser.cs b/src/cs/Command/Executors/MouseExecutorYamlParser.cs index 097cc08a..1c905d9f 100644 --- a/src/cs/Command/Executors/MouseExecutorYamlParser.cs +++ b/src/cs/Command/Executors/MouseExecutorYamlParser.cs @@ -1,34 +1,38 @@ -namespace macaroni; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class MouseExecutorYamlParser : ExecutorYamlParserBase +namespace macaroni { - public MouseExecutorYamlParser(ISystemContext context) : base(context) { } - - public override string Kind { get { return "mouse"; } } - public override bool TrySequenceOfStringRhs => false; - - protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) + internal class MouseExecutorYamlParser : ExecutorYamlParserBase { - var action = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "action", warnings); - var position = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "position", warnings); - var relative = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "relative", warnings); - var button = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "button", warnings); - var element = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "element", warnings); + public MouseExecutorYamlParser(ISystemContext context) : base(context) { } - var allowed = scalar == null - ? new[] { "position", "relative", "button", "element", "action" } - : new[] { "position", "relative", "button", "element" }; - RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + public override string Kind { get { return "mouse"; } } + public override bool TrySequenceOfStringRhs => false; - return new MouseExecutor() + protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) { - Action = action, - Position = position, - PosititionRelativeTo = relative, - Button = button, - Element = element, - Yaml = mapping, - YamlFile = file - }; + var action = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "action", warnings); + var position = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "position", warnings); + var relative = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "relative", warnings); + var button = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "button", warnings); + var element = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "element", warnings); + + var allowed = scalar == null + ? new[] { "position", "relative", "button", "element", "action" } + : new[] { "position", "relative", "button", "element" }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + + return new MouseExecutor() + { + Action = action, + Position = position, + PosititionRelativeTo = relative, + Button = button, + Element = element, + Yaml = mapping, + YamlFile = file + }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/MsgBoxExecutorBase.cs b/src/cs/Command/Executors/MsgBoxExecutorBase.cs index 753c89fc..458de851 100644 --- a/src/cs/Command/Executors/MsgBoxExecutorBase.cs +++ b/src/cs/Command/Executors/MsgBoxExecutorBase.cs @@ -1,4 +1,6 @@ -namespace macaroni +using YamlDotNet.RepresentationModel; + +namespace macaroni { public class MsgBoxExecutorBase { diff --git a/src/cs/Command/Executors/PickExecutor.cs b/src/cs/Command/Executors/PickExecutor.cs index 85366eed..ddb4d988 100644 --- a/src/cs/Command/Executors/PickExecutor.cs +++ b/src/cs/Command/Executors/PickExecutor.cs @@ -1,38 +1,43 @@ -namespace macaroni; +using System; +using System.Collections.Generic; +using System.Linq; -internal class PickExecutor : MsgBoxExecutorBase, ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public IEnumerable? Choices { get; set; } - public string? Default { get; set; } - - public ExecutionResult Execute(IExecutionContext context) + internal class PickExecutor : MsgBoxExecutorBase, ICommandExecutor, ILoadedFromYamlFile { - MR.DBG_TRACE_INFO($"-- PICK: Execute({Message}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - - var title = context.Resolve(Title); - var message = context.Resolve(Message); - var timeout = context.Resolve(Timeout); + public IEnumerable? Choices { get; set; } + public string? Default { get; set; } - var choices = Choices?.Select(x => context.Resolve(x)); - if (choices?.Count() == 1 && choices!.First()!.IndexOf('\n') > 0) + public ExecutionResult Execute(IExecutionContext context) { - choices = choices!.First()!.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); - } + MR.DBG_TRACE_INFO($"-- PICK: Execute({Message}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - var @default = context.Resolve(Default) ?? string.Empty; + var title = context.Resolve(Title); + var message = context.Resolve(Message); + var timeout = context.Resolve(Timeout); - if (choices?.Count() > 0) - { - var messageBox = this.GetParentOrService(); - if (messageBox != null) + var choices = Choices?.Select(x => context.Resolve(x)); + if (choices?.Count() == 1 && choices!.First()!.IndexOf('\n') > 0) { - var choice = @default; - var ok = messageBox.Pick(choices!, message, title, timeout, ref choice); - if (ok) context.Set("pick.text", choice!); - if (!ok) return ExecutionResult.Stopped; + choices = choices!.First()!.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); } - } - return ExecutionResult.Completed; + var @default = context.Resolve(Default) ?? string.Empty; + + if (choices?.Count() > 0) + { + var messageBox = this.GetParentOrService(); + if (messageBox != null) + { + var choice = @default; + var ok = messageBox.Pick(choices!, message, title, timeout, ref choice); + if (ok) context.Set("pick.text", choice!); + if (!ok) return ExecutionResult.Stopped; + } + } + + return ExecutionResult.Completed; + } } } diff --git a/src/cs/Command/Executors/PickExecutorYamlParser.cs b/src/cs/Command/Executors/PickExecutorYamlParser.cs index 8c5ff029..b1fea2b6 100644 --- a/src/cs/Command/Executors/PickExecutorYamlParser.cs +++ b/src/cs/Command/Executors/PickExecutorYamlParser.cs @@ -1,57 +1,62 @@ -namespace macaroni; +using System; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; - -internal class PickExecutorYamlParser : YamlParserBase, IExecutorYamlParser +namespace macaroni { - public PickExecutorYamlParser(ISystemContext context) : base(context) { } - - public string Kind { get { return "pick"; } } - public ICommandExecutor Parse(string file, YamlMappingNode executor, YamlNode value, IParsedValueWarningChecker? warnings) + internal class PickExecutorYamlParser : YamlParserBase, IExecutorYamlParser { - var scalar = value as YamlScalarNode; - if (scalar != null) return ParseScalar(file, executor, scalar, warnings); + public PickExecutorYamlParser(ISystemContext context) : base(context) { } - var sequence = value as YamlSequenceNode; - if (sequence != null) return ParseSequence(file, executor, sequence, warnings); + public string Kind { get { return "pick"; } } - var mapping = value as YamlMappingNode; - if (mapping != null) return ParseMapping(file, mapping, null, warnings); + public ICommandExecutor Parse(string file, YamlMappingNode executor, YamlNode value, IParsedValueWarningChecker? warnings) + { + var scalar = value as YamlScalarNode; + if (scalar != null) return ParseScalar(file, executor, scalar, warnings); - throw ExpectedMappingOrStringValueException(file, Kind, value); - } + var sequence = value as YamlSequenceNode; + if (sequence != null) return ParseSequence(file, executor, sequence, warnings); - private ICommandExecutor ParseScalar(string file, YamlMappingNode executor, YamlScalarNode scalar, IParsedValueWarningChecker? warnings) - { - string value = RequireScalarStringValueNotNullOrEmpty(file, Kind, scalar, warnings); - var choices = value.Split(new char[]{'\r', '\n'}, StringSplitOptions.RemoveEmptyEntries); - return ParseMapping(file, executor, choices, warnings); - } + var mapping = value as YamlMappingNode; + if (mapping != null) return ParseMapping(file, mapping, null, warnings); - private ICommandExecutor ParseSequence(string file, YamlMappingNode executor, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) - { - var choices = GetScalarStrings(file, sequence, warnings); - return ParseMapping(file, executor, choices, warnings); - } + throw ExpectedMappingOrStringValueException(file, Kind, value); + } - private ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, IEnumerable? choices, IParsedValueWarningChecker? warnings) - { - var message = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "message", warnings); - var title = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "title", warnings); - - choices ??= GetScalarStrings(file, mapping, "choices", warnings); - var defaultValue = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "default", warnings); + private ICommandExecutor ParseScalar(string file, YamlMappingNode executor, YamlScalarNode scalar, IParsedValueWarningChecker? warnings) + { + string value = RequireScalarStringValueNotNullOrEmpty(file, Kind, scalar, warnings); + var choices = value.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + return ParseMapping(file, executor, choices, warnings); + } - RequireNoUnexpectedMappingKeys(file, mapping, Kind, new[] { "message", "title", "choices", "default" }); + private ICommandExecutor ParseSequence(string file, YamlMappingNode executor, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) + { + var choices = GetScalarStrings(file, sequence, warnings); + return ParseMapping(file, executor, choices, warnings); + } - return new PickExecutor() + private ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, IEnumerable? choices, IParsedValueWarningChecker? warnings) { - Message = message, - Title = title, - Choices = choices, - Default = defaultValue, - Yaml = mapping, - YamlFile = file - }; + var message = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "message", warnings); + var title = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "title", warnings); + + choices ??= GetScalarStrings(file, mapping, "choices", warnings); + var defaultValue = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "default", warnings); + + RequireNoUnexpectedMappingKeys(file, mapping, Kind, new[] { "message", "title", "choices", "default" }); + + return new PickExecutor() + { + Message = message, + Title = title, + Choices = choices, + Default = defaultValue, + Yaml = mapping, + YamlFile = file + }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/PlayExecutor.cs b/src/cs/Command/Executors/PlayExecutor.cs index 115cbcef..7979d3f3 100644 --- a/src/cs/Command/Executors/PlayExecutor.cs +++ b/src/cs/Command/Executors/PlayExecutor.cs @@ -1,70 +1,74 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class PlayExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public string? File { get; set; } - public string? Sound { get; set; } - public string? FileOrSound { get; set; } - - public string? Frequency { get; set; } - public string? Duration { get; set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class PlayExecutor : ICommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; - } + public string? File { get; set; } + public string? Sound { get; set; } + public string? FileOrSound { get; set; } - public void Unload() - { - } + public string? Frequency { get; set; } + public string? Duration { get; set; } - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- PLAY: Execute({File}, {Sound}, {FileOrSound}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - var fileOrSound = context.Resolve(FileOrSound); - var file = context.Resolve(File); - var sound = context.Resolve(Sound); - var frequency = context.Resolve(Frequency); - var duration = context.Resolve(Duration); + public void LoadComplete(object parent) + { + YamlParent = parent; + } - var play = this.GetParentOrService(); + public void Unload() + { + } - var what = fileOrSound ?? file ?? sound; - if (what == "beep") + public ExecutionResult Execute(IExecutionContext context) { - var freqOk = int.TryParse(frequency, out var freqAsInt); - var durOk = int.TryParse(duration, out var durAsInt); - if (freqOk && durOk) + MR.DBG_TRACE_INFO( + $"-- PLAY: Execute({File}, {Sound}, {FileOrSound}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + + var fileOrSound = context.Resolve(FileOrSound); + var file = context.Resolve(File); + var sound = context.Resolve(Sound); + var frequency = context.Resolve(Frequency); + var duration = context.Resolve(Duration); + + var play = this.GetParentOrService(); + + var what = fileOrSound ?? file ?? sound; + if (what == "beep") { - play?.Beep(freqAsInt, durAsInt); + var freqOk = int.TryParse(frequency, out var freqAsInt); + var durOk = int.TryParse(duration, out var durAsInt); + if (freqOk && durOk) + { + play?.Beep(freqAsInt, durAsInt); + } + else + { + play?.Beep(); + } } - else + else if (what == "pause") { - play?.Beep(); + play?.Pause(); } + else if (what == "resume") + { + play?.Resume(); + } + else if (what == "stop" || string.IsNullOrEmpty(what)) + { + play?.Stop(); + } + else if (!string.IsNullOrEmpty(what)) + { + play?.Play(what); + } + + return ExecutionResult.Completed; } - else if (what == "pause") - { - play?.Pause(); - } - else if (what == "resume") - { - play?.Resume(); - } - else if (what == "stop" || string.IsNullOrEmpty(what)) - { - play?.Stop(); - } - else if (!string.IsNullOrEmpty(what)) - { - play?.Play(what); - } - - return ExecutionResult.Completed; } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/PlayExecutorYamlParser.cs b/src/cs/Command/Executors/PlayExecutorYamlParser.cs index 3ec05048..e8b3b6d0 100644 --- a/src/cs/Command/Executors/PlayExecutorYamlParser.cs +++ b/src/cs/Command/Executors/PlayExecutorYamlParser.cs @@ -1,39 +1,43 @@ -namespace macaroni; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class PlayExecutorYamlParser : ExecutorYamlParserBase +namespace macaroni { - public PlayExecutorYamlParser(ISystemContext context) : base(context) { } - - public override string Kind { get { return "play"; } } - public override bool TrySequenceOfStringRhs => false; - public override bool RequireScalarRhsNotNull => false; - - protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) + internal class PlayExecutorYamlParser : ExecutorYamlParserBase { - var fileOrSound = scalar; - var fileName = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "file", warnings); - var sound = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "sound", warnings); + public PlayExecutorYamlParser(ISystemContext context) : base(context) { } - if (string.IsNullOrEmpty(fileName) && string.IsNullOrEmpty(sound) && string.IsNullOrEmpty(fileOrSound)) + public override string Kind { get { return "play"; } } + public override bool TrySequenceOfStringRhs => false; + public override bool RequireScalarRhsNotNull => false; + + protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) { - var expected = $"`file: (string)` or `sound: (string)`"; - throw ErrorParsingYamlException(file, mapping.Start.Line, mapping.Start.Column, "Unexpected `play` mapping", $"EXPECTED: {expected}"); - } + var fileOrSound = scalar; + var fileName = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "file", warnings); + var sound = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "sound", warnings); - var frequency = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "frequency", warnings); - var duration = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "duration", warnings); + if (string.IsNullOrEmpty(fileName) && string.IsNullOrEmpty(sound) && string.IsNullOrEmpty(fileOrSound)) + { + var expected = $"`file: (string)` or `sound: (string)`"; + throw ErrorParsingYamlException(file, mapping.Start.Line, mapping.Start.Column, "Unexpected `play` mapping", $"EXPECTED: {expected}"); + } - RequireNoUnexpectedMappingKeys(file, mapping, Kind, new[] { "file", "sound", "frequency", "duration" }); + var frequency = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "frequency", warnings); + var duration = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "duration", warnings); - return new PlayExecutor() - { - FileOrSound = fileOrSound, - File = fileName, - Sound = sound, - Frequency = frequency, - Duration = duration, - Yaml = mapping, - YamlFile = file - }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, new[] { "file", "sound", "frequency", "duration" }); + + return new PlayExecutor() + { + FileOrSound = fileOrSound, + File = fileName, + Sound = sound, + Frequency = frequency, + Duration = duration, + Yaml = mapping, + YamlFile = file + }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/PromptExecutor.cs b/src/cs/Command/Executors/PromptExecutor.cs index c213e1c7..96dfa94d 100644 --- a/src/cs/Command/Executors/PromptExecutor.cs +++ b/src/cs/Command/Executors/PromptExecutor.cs @@ -1,29 +1,30 @@ -namespace macaroni; - -internal class PromptExecutor : MsgBoxExecutorBase, ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public string? Text { get; set; } - - public ExecutionResult Execute(IExecutionContext context) + internal class PromptExecutor : MsgBoxExecutorBase, ICommandExecutor, ILoadedFromYamlFile { - MR.DBG_TRACE_INFO($"-- PROMPT: Execute({Message}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public string? Text { get; set; } - var title = context.Resolve(Title); - var message = context.Resolve(Message); - var timeout = context.Resolve(Timeout); - var text = context.Resolve(Text) ?? string.Empty; - - if (!string.IsNullOrEmpty(message)) + public ExecutionResult Execute(IExecutionContext context) { - var msgbox = this.GetParentOrService(); - if (msgbox != null) + MR.DBG_TRACE_INFO($"-- PROMPT: Execute({Message}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + + var title = context.Resolve(Title); + var message = context.Resolve(Message); + var timeout = context.Resolve(Timeout); + var text = context.Resolve(Text) ?? string.Empty; + + if (!string.IsNullOrEmpty(message)) { - var ok = msgbox.Prompt(message, title, timeout, ref text); - if (ok) context.Set("prompt.text", text); - if (!ok) return ExecutionResult.Stopped; + var msgbox = this.GetParentOrService(); + if (msgbox != null) + { + var ok = msgbox.Prompt(message, title, timeout, ref text); + if (ok) context.Set("prompt.text", text); + if (!ok) return ExecutionResult.Stopped; + } } - } - return ExecutionResult.Completed; + return ExecutionResult.Completed; + } } } diff --git a/src/cs/Command/Executors/PromptExecutorYamlParser.cs b/src/cs/Command/Executors/PromptExecutorYamlParser.cs index 482d21f3..7784c78a 100644 --- a/src/cs/Command/Executors/PromptExecutorYamlParser.cs +++ b/src/cs/Command/Executors/PromptExecutorYamlParser.cs @@ -1,29 +1,32 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class PromptExecutorYamlParser : ExecutorYamlParserBase_MsgBoxScalarMapping +namespace macaroni { - public PromptExecutorYamlParser(ISystemContext context) : base(context) { } - - public override string Kind { get { return "prompt"; } } - - protected override ICommandExecutor CreateFromMapping(string file, YamlMappingNode mapping, string message, string? title, string? timeout, IParsedValueWarningChecker? warnings) + internal class PromptExecutorYamlParser : ExecutorYamlParserBase_MsgBoxScalarMapping { - var text = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "default", warnings) - ?? RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "text", warnings); + public PromptExecutorYamlParser(ISystemContext context) : base(context) { } - return new PromptExecutor() + public override string Kind { get { return "prompt"; } } + + protected override ICommandExecutor CreateFromMapping(string file, YamlMappingNode mapping, string message, string? title, string? timeout, IParsedValueWarningChecker? warnings) { - Message = message, - Title = title, - Timeout = timeout, - Text = text, - Yaml = mapping, - YamlFile = file - }; - } + var text = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "default", warnings) + ?? RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "text", warnings); - protected override string[] GetValidMappingKeys() - { - return new[] { "message", "title", "timeout", "default", "text" }; + return new PromptExecutor() + { + Message = message, + Title = title, + Timeout = timeout, + Text = text, + Yaml = mapping, + YamlFile = file + }; + } + + protected override string[] GetValidMappingKeys() + { + return new[] { "message", "title", "timeout", "default", "text" }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/QuitApplicationExecutor.cs b/src/cs/Command/Executors/QuitApplicationExecutor.cs index d3d81e1e..c0f9e96c 100644 --- a/src/cs/Command/Executors/QuitApplicationExecutor.cs +++ b/src/cs/Command/Executors/QuitApplicationExecutor.cs @@ -1,27 +1,30 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class QuitApplicationExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class QuitApplicationExecutor : ICommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; - } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public void Unload() - { - } + public void LoadComplete(object parent) + { + YamlParent = parent; + } - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- QUIT: Execute(): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public void Unload() + { + } + + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO($"-- QUIT: Execute(): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - var host = this.GetRequiredParentOrService(); - host.Quit(); + var host = this.GetRequiredParentOrService(); + host.Quit(); - return ExecutionResult.Completed; + return ExecutionResult.Completed; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/QuitApplicationExecutorYamlParser.cs b/src/cs/Command/Executors/QuitApplicationExecutorYamlParser.cs index 7731b824..c0ba8883 100644 --- a/src/cs/Command/Executors/QuitApplicationExecutorYamlParser.cs +++ b/src/cs/Command/Executors/QuitApplicationExecutorYamlParser.cs @@ -1,14 +1,18 @@ -namespace macaroni; +using System; +using YamlDotNet.RepresentationModel; -internal class QuitApplicationExecutorYamlParser : YamlParserBase, IExecutorYamlParser +namespace macaroni { - public QuitApplicationExecutorYamlParser(ISystemContext context) : base(context) { } - - public string Kind { get { return "quit"; } } - - public ICommandExecutor Parse(string file, YamlMappingNode executor, YamlNode value, IParsedValueWarningChecker? warnings) + internal class QuitApplicationExecutorYamlParser : YamlParserBase, IExecutorYamlParser { - RequireNoUnexpectedMappingKeys(file, executor, Kind, Array.Empty()); - return new QuitApplicationExecutor(); + public QuitApplicationExecutorYamlParser(ISystemContext context) : base(context) { } + + public string Kind { get { return "quit"; } } + + public ICommandExecutor Parse(string file, YamlMappingNode executor, YamlNode value, IParsedValueWarningChecker? warnings) + { + RequireNoUnexpectedMappingKeys(file, executor, Kind, Array.Empty()); + return new QuitApplicationExecutor(); + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/RandomExecutor.cs b/src/cs/Command/Executors/RandomExecutor.cs index 08f458aa..9d8b4a8a 100644 --- a/src/cs/Command/Executors/RandomExecutor.cs +++ b/src/cs/Command/Executors/RandomExecutor.cs @@ -1,34 +1,37 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class RandomExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public string? Values { get; set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class RandomExecutor : ICommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; - } + public string? Values { get; set; } - public void Unload() - { - } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- RANDOM: Execute({Values}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public void LoadComplete(object parent) + { + YamlParent = parent; + } - var values = context.Resolve(Values)?.Split('\n'); - if (values != null) + public void Unload() { - var random = this.GetRequiredParentOrService(); - var value = random.PickRandom(values); - context.Set("random", value); } - return ExecutionResult.Completed; + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO($"-- RANDOM: Execute({Values}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + + var values = context.Resolve(Values)?.Split('\n'); + if (values != null) + { + var random = this.GetRequiredParentOrService(); + var value = random.PickRandom(values); + context.Set("random", value); + } + + return ExecutionResult.Completed; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/RandomExecutorYamlParser.cs b/src/cs/Command/Executors/RandomExecutorYamlParser.cs index 1f635232..29e2dd1f 100644 --- a/src/cs/Command/Executors/RandomExecutorYamlParser.cs +++ b/src/cs/Command/Executors/RandomExecutorYamlParser.cs @@ -1,38 +1,42 @@ -namespace macaroni; +using System; +using YamlDotNet.RepresentationModel; -internal class RandomExecutorYamlParser : YamlParserBase, IExecutorYamlParser +namespace macaroni { - public RandomExecutorYamlParser(ISystemContext context) : base(context) { } - - public string Kind { get { return "random"; } } - - public ICommandExecutor Parse(string file, YamlMappingNode executor, YamlNode value, IParsedValueWarningChecker? warnings) + internal class RandomExecutorYamlParser : YamlParserBase, IExecutorYamlParser { - var scalar = value as YamlScalarNode; - if (scalar != null) return ParseScalar(file, executor, scalar, warnings); + public RandomExecutorYamlParser(ISystemContext context) : base(context) { } - var sequence = value as YamlSequenceNode; - if (sequence != null) return ParseSequence(file, executor, sequence, warnings); + public string Kind { get { return "random"; } } - throw ExpectedSequenceOrStringValueException(file, Kind, value); - } + public ICommandExecutor Parse(string file, YamlMappingNode executor, YamlNode value, IParsedValueWarningChecker? warnings) + { + var scalar = value as YamlScalarNode; + if (scalar != null) return ParseScalar(file, executor, scalar, warnings); - private ICommandExecutor ParseScalar(string file, YamlMappingNode mapping, YamlScalarNode scalar, IParsedValueWarningChecker? warnings) - { - string values = RequireScalarStringValueNotNullOrEmpty(file, Kind, scalar, warnings); + var sequence = value as YamlSequenceNode; + if (sequence != null) return ParseSequence(file, executor, sequence, warnings); - RequireNoUnexpectedMappingKeys(file, mapping, Kind, Array.Empty()); + throw ExpectedSequenceOrStringValueException(file, Kind, value); + } - return new RandomExecutor() { Values = values, Yaml = scalar, YamlFile = file }; - } + private ICommandExecutor ParseScalar(string file, YamlMappingNode mapping, YamlScalarNode scalar, IParsedValueWarningChecker? warnings) + { + string values = RequireScalarStringValueNotNullOrEmpty(file, Kind, scalar, warnings); - private ICommandExecutor ParseSequence(string file, YamlMappingNode mapping, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) - { - var values = RequireSequenceOfStringsNotNullOrEmpty(file, Kind, sequence, warnings); - var str = string.Join('\n', values); + RequireNoUnexpectedMappingKeys(file, mapping, Kind, Array.Empty()); + + return new RandomExecutor() { Values = values, Yaml = scalar, YamlFile = file }; + } + + private ICommandExecutor ParseSequence(string file, YamlMappingNode mapping, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) + { + var values = RequireSequenceOfStringsNotNullOrEmpty(file, Kind, sequence, warnings); + var str = string.Join('\n', values); - RequireNoUnexpectedMappingKeys(file, mapping, Kind, Array.Empty()); + RequireNoUnexpectedMappingKeys(file, mapping, Kind, Array.Empty()); - return new RandomExecutor() { Values = str, Yaml = sequence, YamlFile = file }; + return new RandomExecutor() { Values = str, Yaml = sequence, YamlFile = file }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/RunExecutor.cs b/src/cs/Command/Executors/RunExecutor.cs index 342248ce..bb26935a 100644 --- a/src/cs/Command/Executors/RunExecutor.cs +++ b/src/cs/Command/Executors/RunExecutor.cs @@ -1,48 +1,52 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class RunExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public string? Process { get; set; } - public string? Command { get; set; } - public string? ProcessOrCommand { get; set; } - public string? Arguments { get; set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class RunExecutor : ICommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; - } - - public void Unload() - { - } - - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- RUN: Execute({Process}, {Command}, {ProcessOrCommand}, {Arguments}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public string? Process { get; set; } + public string? Command { get; set; } + public string? ProcessOrCommand { get; set; } + public string? Arguments { get; set; } - var processOrCommand = context.Resolve(ProcessOrCommand); - var process = context.Resolve(Process); - var command = context.Resolve(Command); - var arguments = context.Resolve(Arguments); + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - var runApp = this.GetParentOrService(); - if (processOrCommand != null) + public void LoadComplete(object parent) { - runApp?.Run(processOrCommand, arguments); + YamlParent = parent; } - else if (process != null) + + public void Unload() { - runApp?.StartProcess(process, arguments); } - else if (command != null) + + public ExecutionResult Execute(IExecutionContext context) { - runApp?.StartCommand(command, arguments); - } + MR.DBG_TRACE_INFO( + $"-- RUN: Execute({Process}, {Command}, {ProcessOrCommand}, {Arguments}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - return ExecutionResult.Completed; + var processOrCommand = context.Resolve(ProcessOrCommand); + var process = context.Resolve(Process); + var command = context.Resolve(Command); + var arguments = context.Resolve(Arguments); + + var runApp = this.GetParentOrService(); + if (processOrCommand != null) + { + runApp?.Run(processOrCommand, arguments); + } + else if (process != null) + { + runApp?.StartProcess(process, arguments); + } + else if (command != null) + { + runApp?.StartCommand(command, arguments); + } + + return ExecutionResult.Completed; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/RunExecutorYamlParser.cs b/src/cs/Command/Executors/RunExecutorYamlParser.cs index 5e2b7825..b41deadf 100644 --- a/src/cs/Command/Executors/RunExecutorYamlParser.cs +++ b/src/cs/Command/Executors/RunExecutorYamlParser.cs @@ -1,36 +1,40 @@ -namespace macaroni; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class RunExecutorYamlParser : ExecutorYamlParserBase +namespace macaroni { - public RunExecutorYamlParser(ISystemContext context) : base(context) { } - - public override string Kind { get { return "run"; } } - public override bool TrySequenceOfStringRhs => false; - public override bool RequireScalarRhsNotNull => false; - - protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) + internal class RunExecutorYamlParser : ExecutorYamlParserBase { - var processOrCommand = scalar; - var command = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "command", warnings); - var process = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "process", warnings); - var arguments = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "arguments", warnings); + public RunExecutorYamlParser(ISystemContext context) : base(context) { } - RequireNoUnexpectedMappingKeys(file, mapping, Kind, new[] { "command", "process", "arguments" }); + public override string Kind { get { return "run"; } } + public override bool TrySequenceOfStringRhs => false; + public override bool RequireScalarRhsNotNull => false; - if (string.IsNullOrEmpty(process) && string.IsNullOrEmpty(command) && string.IsNullOrEmpty(processOrCommand)) + protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) { - var expected = $"`command: (string)` or `process: (string)`"; - throw ErrorParsingYamlException(file, mapping.Start.Line, mapping.Start.Column, "Unexpected `run` mapping", $"EXPECTED: {expected}"); - } + var processOrCommand = scalar; + var command = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "command", warnings); + var process = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "process", warnings); + var arguments = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "arguments", warnings); - return new RunExecutor() - { - ProcessOrCommand = processOrCommand, - Command = command, - Process = process, - Arguments = arguments, - Yaml = mapping, - YamlFile = file - }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, new[] { "command", "process", "arguments" }); + + if (string.IsNullOrEmpty(process) && string.IsNullOrEmpty(command) && string.IsNullOrEmpty(processOrCommand)) + { + var expected = $"`command: (string)` or `process: (string)`"; + throw ErrorParsingYamlException(file, mapping.Start.Line, mapping.Start.Column, "Unexpected `run` mapping", $"EXPECTED: {expected}"); + } + + return new RunExecutor() + { + ProcessOrCommand = processOrCommand, + Command = command, + Process = process, + Arguments = arguments, + Yaml = mapping, + YamlFile = file + }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/ScriptExecutor.cs b/src/cs/Command/Executors/ScriptExecutor.cs index 5331411f..e79051f4 100644 --- a/src/cs/Command/Executors/ScriptExecutor.cs +++ b/src/cs/Command/Executors/ScriptExecutor.cs @@ -1,36 +1,40 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class ScriptExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public string? Code { get; set; } - public string? Language { get; set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class ScriptExecutor : ICommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; - } - - public void Unload() - { - } + public string? Code { get; set; } + public string? Language { get; set; } - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- SCRIPT: Execute({Code}, {Language}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - var code = context.Resolve(Code); - var language = context.Resolve(Language); + public void LoadComplete(object parent) + { + YamlParent = parent; + } - if (!string.IsNullOrEmpty(code)) + public void Unload() { - var script = this.GetParentOrService(); - script?.Execute(context, code, language); } - return ExecutionResult.Completed; + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO( + $"-- SCRIPT: Execute({Code}, {Language}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + + var code = context.Resolve(Code); + var language = context.Resolve(Language); + + if (!string.IsNullOrEmpty(code)) + { + var script = this.GetParentOrService(); + script?.Execute(context, code, language); + } + + return ExecutionResult.Completed; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/ScriptExecutorYamlParser.cs b/src/cs/Command/Executors/ScriptExecutorYamlParser.cs index 6ffe4348..b0a49034 100644 --- a/src/cs/Command/Executors/ScriptExecutorYamlParser.cs +++ b/src/cs/Command/Executors/ScriptExecutorYamlParser.cs @@ -1,22 +1,26 @@ -namespace macaroni; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class ScriptExecutorYamlParser : ExecutorYamlParserBase +namespace macaroni { - public ScriptExecutorYamlParser(ISystemContext context) : base(context) { } + internal class ScriptExecutorYamlParser : ExecutorYamlParserBase + { + public ScriptExecutorYamlParser(ISystemContext context) : base(context) { } - public override string Kind { get { return "script"; } } - public override bool TrySequenceOfStringRhs => false; + public override string Kind { get { return "script"; } } + public override bool TrySequenceOfStringRhs => false; - protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) - { - var code = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "code", warnings); - var language = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "language", warnings); + protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) + { + var code = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "code", warnings); + var language = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "language", warnings); - var allowed = scalar == null - ? new[] { "language", "code" } - : new[] { "language" }; - RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + var allowed = scalar == null + ? new[] { "language", "code" } + : new[] { "language" }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); - return new ScriptExecutor() { Code = code, Language = language, Yaml = mapping, YamlFile = file }; + return new ScriptExecutor() { Code = code, Language = language, Yaml = mapping, YamlFile = file }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/SendKeysExecutor.cs b/src/cs/Command/Executors/SendKeysExecutor.cs index ceb6c9fa..26ff401c 100644 --- a/src/cs/Command/Executors/SendKeysExecutor.cs +++ b/src/cs/Command/Executors/SendKeysExecutor.cs @@ -1,42 +1,46 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class SendKeysExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public string? Keys { get; set; } - public string? Times { get; set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class SendKeysExecutor : ICommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; - } + public string? Keys { get; set; } + public string? Times { get; set; } - public void Unload() - { - } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- SENDKEYS: Execute({Keys}, {Times}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public void LoadComplete(object parent) + { + YamlParent = parent; + } - var keys = context.Resolve(Keys); - var times = context.Resolve(Times); + public void Unload() + { + } - if (keys != null) + public ExecutionResult Execute(IExecutionContext context) { - int repeatCount; - if (string.IsNullOrEmpty(Times) || !int.TryParse(times, out repeatCount)) + MR.DBG_TRACE_INFO( + $"-- SENDKEYS: Execute({Keys}, {Times}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + + var keys = context.Resolve(Keys); + var times = context.Resolve(Times); + + if (keys != null) { - repeatCount = 1; + int repeatCount; + if (string.IsNullOrEmpty(Times) || !int.TryParse(times, out repeatCount)) + { + repeatCount = 1; + } + + var sendKeys = this.GetParentOrService(); + sendKeys?.SendKeys(keys, repeatCount); } - var sendKeys = this.GetParentOrService(); - sendKeys?.SendKeys(keys, repeatCount); + return ExecutionResult.Completed; } - - return ExecutionResult.Completed; } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/SendKeysExecutorYamlParser.cs b/src/cs/Command/Executors/SendKeysExecutorYamlParser.cs index 425f8d0d..fffab354 100644 --- a/src/cs/Command/Executors/SendKeysExecutorYamlParser.cs +++ b/src/cs/Command/Executors/SendKeysExecutorYamlParser.cs @@ -1,28 +1,32 @@ -namespace macaroni; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class SendKeysExecutorYamlParser : ExecutorYamlParserBase +namespace macaroni { - public SendKeysExecutorYamlParser(ISystemContext context) : base(context) { } - - public override string Kind { get { return "sendKeys"; } } - public override bool TrySequenceOfStringRhs => false; - - protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) + internal class SendKeysExecutorYamlParser : ExecutorYamlParserBase { - var keys = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "keys", warnings); - var times = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "times", warnings); + public SendKeysExecutorYamlParser(ISystemContext context) : base(context) { } - var allowed = scalar == null - ? new[] { "times", "keys" } - : new[] { "times" }; - RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + public override string Kind { get { return "sendKeys"; } } + public override bool TrySequenceOfStringRhs => false; - return new SendKeysExecutor() + protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) { - Keys = keys, - Times = times, - Yaml = mapping, - YamlFile = file - }; + var keys = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "keys", warnings); + var times = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "times", warnings); + + var allowed = scalar == null + ? new[] { "times", "keys" } + : new[] { "times" }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + + return new SendKeysExecutor() + { + Keys = keys, + Times = times, + Yaml = mapping, + YamlFile = file + }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/SetValueExecutor.cs b/src/cs/Command/Executors/SetValueExecutor.cs index 6d7b7a46..b6594bb0 100644 --- a/src/cs/Command/Executors/SetValueExecutor.cs +++ b/src/cs/Command/Executors/SetValueExecutor.cs @@ -1,60 +1,63 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class SetValueExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public string? Name { get; set; } - public string? Value { get; set; } - public string? Scope { get; internal set; } + internal class SetValueExecutor : ICommandExecutor, ILoadedFromYamlFile + { + public string? Name { get; set; } + public string? Value { get; set; } + public string? Scope { get; internal set; } - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public void LoadComplete(object parent) - { - YamlParent = parent; - } + public void LoadComplete(object parent) + { + YamlParent = parent; + } - public void Unload() - { - } + public void Unload() + { + } - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- SET: Execute({Name}, {Value}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO($"-- SET: Execute({Name}, {Value}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - var name = context.Resolve(Name); - var value = context.Resolve(Value); - var scope = context.Resolve(Scope) ?? "local"; + var name = context.Resolve(Name); + var value = context.Resolve(Value); + var scope = context.Resolve(Scope) ?? "local"; - if (string.IsNullOrEmpty(name)) return ExecutionResult.Completed; + if (string.IsNullOrEmpty(name)) return ExecutionResult.Completed; - var useGlobal = scope == "global"; - if (useGlobal) SetGlobalNamedState(name, value); + var useGlobal = scope == "global"; + if (useGlobal) SetGlobalNamedState(name, value); - var useThis = !useGlobal && scope == "this"; - if (useThis) SetThisCommandContext(context, name, value); + var useThis = !useGlobal && scope == "this"; + if (useThis) SetThisCommandContext(context, name, value); - var useLocal = !useGlobal && !useThis; - if (useLocal) SetLocalCommandSetContext(name, value); + var useLocal = !useGlobal && !useThis; + if (useLocal) SetLocalCommandSetContext(name, value); - return ExecutionResult.Completed; - } + return ExecutionResult.Completed; + } - private void SetGlobalNamedState(string name, string? value) - { - var service = this.GetRequiredParentOrService(); - service.SetNamedState(name, value); - } + private void SetGlobalNamedState(string name, string? value) + { + var service = this.GetRequiredParentOrService(); + service.SetNamedState(name, value); + } - private void SetLocalCommandSetContext(string name, string? value) - { - var context = this.GetRequiredParentOrService(); - context.Set(name, value ?? "", SetValueKind.InterleavedWithResolvers); - } + private void SetLocalCommandSetContext(string name, string? value) + { + var context = this.GetRequiredParentOrService(); + context.Set(name, value ?? "", SetValueKind.InterleavedWithResolvers); + } - private void SetThisCommandContext(IExecutionContext context, string name, string? value) - { - context.Set(name, value ?? "", SetValueKind.InterleavedWithResolvers); + private void SetThisCommandContext(IExecutionContext context, string name, string? value) + { + context.Set(name, value ?? "", SetValueKind.InterleavedWithResolvers); + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/SetValueExecutorYamlParser.cs b/src/cs/Command/Executors/SetValueExecutorYamlParser.cs index 66e50139..f8b86c7b 100644 --- a/src/cs/Command/Executors/SetValueExecutorYamlParser.cs +++ b/src/cs/Command/Executors/SetValueExecutorYamlParser.cs @@ -1,11 +1,14 @@ -namespace macaroni; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class SetValueExecutorYamlParser : ExecutorYamlParserBase +namespace macaroni { - public SetValueExecutorYamlParser(ISystemContext context) : base(context) { } + internal class SetValueExecutorYamlParser : ExecutorYamlParserBase + { + public SetValueExecutorYamlParser(ISystemContext context) : base(context) { } - public override string Kind { get { return "set"; } } - public override bool TrySequenceOfStringRhs => false; + public override string Kind { get { return "set"; } } + public override bool TrySequenceOfStringRhs => false; protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) { @@ -13,18 +16,19 @@ protected override ICommandExecutor ParseMapping(string file, YamlMappingNode ma var value = RequireMappingStringValueNotNullIfPresent(file, Kind, mapping, "value", warnings); var scope = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "scope", warnings); - var allowed = scalar == null - ? new[] { "value", "scope", "name" } - : new[] { "value", "scope" }; - RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + var allowed = scalar == null + ? new[] { "value", "scope", "name" } + : new[] { "value", "scope" }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); - return new SetValueExecutor() - { - Name = name, - Value = value, - Scope = scope, - Yaml = mapping, - YamlFile = file - }; + return new SetValueExecutor() + { + Name = name, + Value = value, + Scope = scope, + Yaml = mapping, + YamlFile = file + }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/SpeakExecutor.cs b/src/cs/Command/Executors/SpeakExecutor.cs index d99e7498..81bfef0f 100644 --- a/src/cs/Command/Executors/SpeakExecutor.cs +++ b/src/cs/Command/Executors/SpeakExecutor.cs @@ -1,86 +1,91 @@ +using System.Collections.Generic; using Microsoft.CognitiveServices.Speech; using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using YamlDotNet.RepresentationModel; -namespace macaroni; - -internal class SpeakExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public string? Text { get; set; } - public IEnumerable? Random { get; set; } - - public string? Ssml { get; set; } - public string? Voice { get; set; } - public string? Output { get; set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) - { - YamlParent = parent; - } - - public void Unload() + internal class SpeakExecutor : ICommandExecutor, ILoadedFromYamlFile { - } + public string? Text { get; set; } + public IEnumerable? Random { get; set; } - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- SPEAK: Execute({Text}, {Ssml}, {Voice}, {Output}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public string? Ssml { get; set; } + public string? Voice { get; set; } + public string? Output { get; set; } - var text = context.Resolve(Text) ?? context.Resolve(PickRandom()); - var ssml = context.Resolve(Ssml); - var voice = context.Resolve(Voice); - var output = context.Resolve(Output); + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - bool.TryParse(ssml, out var isSsml); - var isText = !isSsml; - - var synthesizer = this.GetRequiredParentOrService(); - if (isText && text != null) + public void LoadComplete(object parent) { - var speak = synthesizer.SpeakText(text, voice, output, null); - return WaitForResultAndStopIfCanceled(context, speak); + YamlParent = parent; } - else if (isSsml && text != null) + + public void Unload() { - var speak = synthesizer!.SpeakSsml(text, voice, output, null); - return WaitForResultAndStopIfCanceled(context, speak); } - return ExecutionResult.Completed; - } - - private ExecutionResult WaitForResultAndStopIfCanceled(IExecutionContext context, Task speak) - { - var sw = Stopwatch.StartNew(); - while (!speak.Wait(1000)) + public ExecutionResult Execute(IExecutionContext context) { - MR.DBG_TRACE_VERBOSE($"WaitForResultAndStopIfCanceled: {sw.Elapsed}"); - if (Debugger.IsAttached && sw.Elapsed.TotalSeconds > 120) + MR.DBG_TRACE_INFO($"-- SPEAK: Execute({Text}, {Ssml}, {Voice}, {Output}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + + var text = context.Resolve(Text) ?? context.Resolve(PickRandom()); + var ssml = context.Resolve(Ssml); + var voice = context.Resolve(Voice); + var output = context.Resolve(Output); + + bool.TryParse(ssml, out var isSsml); + var isText = !isSsml; + + var synthesizer = this.GetRequiredParentOrService(); + if (isText && text != null) + { + var speak = synthesizer.SpeakText(text, voice, output, null); + return WaitForResultAndStopIfCanceled(context, speak); + } + else if (isSsml && text != null) { - MR.DBG_TRACE_WARNING($"WaitForResultAndStopIfCanceled: {sw.Elapsed} > 120... Debugger.Break() !!"); - Debugger.Break(); - sw.Restart(); + var speak = synthesizer!.SpeakSsml(text, voice, output, null); + return WaitForResultAndStopIfCanceled(context, speak); } + + return ExecutionResult.Completed; } - var result = speak.Result; - if (result == null || result.Reason == ResultReason.Canceled) + private ExecutionResult WaitForResultAndStopIfCanceled(IExecutionContext context, Task speak) { - MR.DBG_TRACE_INFO($"-- SPEAK: Execute({result?.Reason}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column}) - Stopped"); - return ExecutionResult.Stopped; - } + var sw = Stopwatch.StartNew(); + while (!speak.Wait(1000)) + { + MR.DBG_TRACE_VERBOSE($"WaitForResultAndStopIfCanceled: {sw.Elapsed}"); + if (Debugger.IsAttached && sw.Elapsed.TotalSeconds > 120) + { + MR.DBG_TRACE_WARNING($"WaitForResultAndStopIfCanceled: {sw.Elapsed} > 120... Debugger.Break() !!"); + Debugger.Break(); + sw.Restart(); + } + } - MR.DBG_TRACE_INFO($"-- SPEAK: Execute({result?.Reason}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column}) - Completed"); - return ExecutionResult.Completed; - } + var result = speak.Result; + if (result == null || result.Reason == ResultReason.Canceled) + { + MR.DBG_TRACE_INFO($"-- SPEAK: Execute({result?.Reason}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column}) - Stopped"); + return ExecutionResult.Stopped; + } - private string? PickRandom() - { - return Random?.Count() > 0 - ? this.GetRequiredParentOrService().PickRandom(Random) - : null; + MR.DBG_TRACE_INFO($"-- SPEAK: Execute({result?.Reason}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column}) - Completed"); + return ExecutionResult.Completed; + } + + private string? PickRandom() + { + return Random?.Count() > 0 + ? this.GetRequiredParentOrService().PickRandom(Random) + : null; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/SpeakExecutorYamlParser.cs b/src/cs/Command/Executors/SpeakExecutorYamlParser.cs index 9fd20b97..b176c7f1 100644 --- a/src/cs/Command/Executors/SpeakExecutorYamlParser.cs +++ b/src/cs/Command/Executors/SpeakExecutorYamlParser.cs @@ -1,41 +1,46 @@ -namespace macaroni; +using System.Collections.Generic; +using System.Linq; +using YamlDotNet.RepresentationModel; -internal class SpeakExecutorYamlParser : ExecutorYamlParserBase +namespace macaroni { - public SpeakExecutorYamlParser(ISystemContext context) : base(context) { } - - public override string Kind { get { return "speak"; } } - - protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) + internal class SpeakExecutorYamlParser : ExecutorYamlParserBase { - var random = sequence ?? GetScalarStrings(file, mapping, "random", warnings); - var text = scalar ?? RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "text", warnings); - var ssml = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "ssml", warnings); - var voice = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "voice", warnings); - var output = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "output", warnings); + public SpeakExecutorYamlParser(ISystemContext context) : base(context) { } - var allowed = scalar == null - ? new[] { "ssml", "voice", "output", "text" } - : new[] { "ssml", "voice", "output", "random" }; - RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + public override string Kind { get { return "speak"; } } - var textOk = !string.IsNullOrEmpty(text); - var randomOk = random?.Count(x => !string.IsNullOrEmpty(x)) > 0; - if (textOk == randomOk) + protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) { - var expected = $"one-of `text: (string)` or `random: (sequence of string) required"; - throw ErrorParsingYamlException(file, mapping.Start.Line, mapping.Start.Column, "Unexpected `speak` mapping", $"EXPECTED: {expected}"); - } + var random = sequence ?? GetScalarStrings(file, mapping, "random", warnings); + var text = scalar ?? RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "text", warnings); + var ssml = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "ssml", warnings); + var voice = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "voice", warnings); + var output = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "output", warnings); - return new SpeakExecutor() - { - Random = random, - Text = text, - Ssml = ssml, - Voice = voice, - Output = output, - Yaml = mapping, - YamlFile = file - }; + var allowed = scalar == null + ? new[] { "ssml", "voice", "output", "text" } + : new[] { "ssml", "voice", "output", "random" }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + + var textOk = !string.IsNullOrEmpty(text); + var randomOk = random?.Count(x => !string.IsNullOrEmpty(x)) > 0; + if (textOk == randomOk) + { + var expected = $"one-of `text: (string)` or `random: (sequence of string) required"; + throw ErrorParsingYamlException(file, mapping.Start.Line, mapping.Start.Column, "Unexpected `speak` mapping", $"EXPECTED: {expected}"); + } + + return new SpeakExecutor() + { + Random = random, + Text = text, + Ssml = ssml, + Voice = voice, + Output = output, + Yaml = mapping, + YamlFile = file + }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/StopExecutor.cs b/src/cs/Command/Executors/StopExecutor.cs index 991f639f..d83424c9 100644 --- a/src/cs/Command/Executors/StopExecutor.cs +++ b/src/cs/Command/Executors/StopExecutor.cs @@ -1,23 +1,26 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class StopExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class StopExecutor : ICommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; - } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public void Unload() - { - } + public void LoadComplete(object parent) + { + YamlParent = parent; + } - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- STOP: Execute(): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - return ExecutionResult.Stopped; + public void Unload() + { + } + + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO($"-- STOP: Execute(): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + return ExecutionResult.Stopped; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/StopExecutorYamlParser.cs b/src/cs/Command/Executors/StopExecutorYamlParser.cs index cd07f8da..4008aa6f 100644 --- a/src/cs/Command/Executors/StopExecutorYamlParser.cs +++ b/src/cs/Command/Executors/StopExecutorYamlParser.cs @@ -1,14 +1,18 @@ -namespace macaroni; +using System; +using YamlDotNet.RepresentationModel; -internal class StopExecutorYamlParser : YamlParserBase, IExecutorYamlParser +namespace macaroni { - public StopExecutorYamlParser(ISystemContext context) : base(context) { } - - public string Kind { get { return "stop"; } } - - public ICommandExecutor Parse(string file, YamlMappingNode executor, YamlNode value, IParsedValueWarningChecker? warnings) + internal class StopExecutorYamlParser : YamlParserBase, IExecutorYamlParser { - RequireNoUnexpectedMappingKeys(file, executor, Kind, Array.Empty()); - return new StopExecutor() { Yaml = value, YamlFile = file}; + public StopExecutorYamlParser(ISystemContext context) : base(context) { } + + public string Kind { get { return "stop"; } } + + public ICommandExecutor Parse(string file, YamlMappingNode executor, YamlNode value, IParsedValueWarningChecker? warnings) + { + RequireNoUnexpectedMappingKeys(file, executor, Kind, Array.Empty()); + return new StopExecutor() { Yaml = value, YamlFile = file }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/SwitchCaseExecutor.cs b/src/cs/Command/Executors/SwitchCaseExecutor.cs index a1549488..057df97b 100644 --- a/src/cs/Command/Executors/SwitchCaseExecutor.cs +++ b/src/cs/Command/Executors/SwitchCaseExecutor.cs @@ -1,38 +1,42 @@ -namespace macaroni; +using System.Linq; +using YamlDotNet.RepresentationModel; - -internal class SwitchCaseExecutor : IConditionalCommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public IConditionCollection? Conditions { get; internal set; } - public IExecutorCollection? Executors { get; internal set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + + internal class SwitchCaseExecutor : IConditionalCommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; + public IConditionCollection? Conditions { get; internal set; } + public IExecutorCollection? Executors { get; internal set; } - (Conditions as ILoadedFromYamlFile)?.LoadComplete(this); - (Executors as ILoadedFromYamlFile)?.LoadComplete(this); - } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public void Unload() - { - (Conditions as ILoadedFromYamlFile)?.Unload(); - (Executors as ILoadedFromYamlFile)?.Unload(); - } + public void LoadComplete(object parent) + { + YamlParent = parent; - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- CASE: Execute({Executors?.Count()}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + (Conditions as ILoadedFromYamlFile)?.LoadComplete(this); + (Executors as ILoadedFromYamlFile)?.LoadComplete(this); + } - if (Conditions != null && Conditions.IsSatisfied(context)) + public void Unload() { - return Executors?.Execute(context) ?? ExecutionResult.Completed; + (Conditions as ILoadedFromYamlFile)?.Unload(); + (Executors as ILoadedFromYamlFile)?.Unload(); } - return ExecutionResult.Completed; + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO($"-- CASE: Execute({Executors?.Count()}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + + if (Conditions != null && Conditions.IsSatisfied(context)) + { + return Executors?.Execute(context) ?? ExecutionResult.Completed; + } + + return ExecutionResult.Completed; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/SwitchCaseExecutorYamlParser.cs b/src/cs/Command/Executors/SwitchCaseExecutorYamlParser.cs index 5e87b2ec..6d0f4655 100644 --- a/src/cs/Command/Executors/SwitchCaseExecutorYamlParser.cs +++ b/src/cs/Command/Executors/SwitchCaseExecutorYamlParser.cs @@ -1,79 +1,83 @@ -using Microsoft.Extensions.DependencyInjection; +using System; +using System.Linq; +using Microsoft.Extensions.DependencyInjection; +using YamlDotNet.RepresentationModel; -namespace macaroni; - -internal class SwitchCaseExecutorYamlParser : YamlParserBase, IExecutorYamlParser +namespace macaroni { - public SwitchCaseExecutorYamlParser(IServiceProvider services, ISystemContext context) : base(context) - { - _serviceProvider = services; - } - - public string Kind { get { return "case"; } } - - public ICommandExecutor Parse(string file, YamlMappingNode executor, YamlNode value, IParsedValueWarningChecker? warnings) + internal class SwitchCaseExecutorYamlParser : YamlParserBase, IExecutorYamlParser { - var sequence = value as YamlSequenceNode; - if (sequence != null) return ParseSequence(file, executor, sequence, warnings); - - var mapping = value as YamlMappingNode; - if (mapping != null) return ParseMapping(file, mapping, warnings); + public SwitchCaseExecutorYamlParser(IServiceProvider services, ISystemContext context) : base(context) + { + _serviceProvider = services; + } - throw ErrorParsingYamlException(file, value.Start.Line, value.Start.Column, "Unexpected YamlNode type", "EXPECTED: `case: {condition sequence}` and `execute: {executor sequence}`"); - } + public string Kind { get { return "case"; } } - private ICommandExecutor ParseSequence(string file, YamlMappingNode executor, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) - { - EnsureParsers(); + public ICommandExecutor Parse(string file, YamlMappingNode executor, YamlNode value, IParsedValueWarningChecker? warnings) + { + var sequence = value as YamlSequenceNode; + if (sequence != null) return ParseSequence(file, executor, sequence, warnings); - var conditions = sequence.Children.Count > 0 - ? _conditionsParser?.ConditionsFromSequence(file, sequence, warnings) - : new ConditionCollection(Enumerable.Empty()); - var executors = _executorsParser?.CheckForExecutors(file, executor, "execute", warnings); + var mapping = value as YamlMappingNode; + if (mapping != null) return ParseMapping(file, mapping, warnings); - RequireNoUnexpectedMappingKeys(file, executor, Kind, new [] { "execute" }); + throw ErrorParsingYamlException(file, value.Start.Line, value.Start.Column, "Unexpected YamlNode type", "EXPECTED: `case: {condition sequence}` and `execute: {executor sequence}`"); + } - return new SwitchCaseExecutor() + private ICommandExecutor ParseSequence(string file, YamlMappingNode executor, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) { - Conditions = conditions, - Executors = executors, - Yaml = executor, - YamlFile = file - }; - } + EnsureParsers(); + + var conditions = sequence.Children.Count > 0 + ? _conditionsParser?.ConditionsFromSequence(file, sequence, warnings) + : new ConditionCollection(Enumerable.Empty()); + var executors = _executorsParser?.CheckForExecutors(file, executor, "execute", warnings); + + RequireNoUnexpectedMappingKeys(file, executor, Kind, new[] { "execute" }); + + return new SwitchCaseExecutor() + { + Conditions = conditions, + Executors = executors, + Yaml = executor, + YamlFile = file + }; + } - private ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, IParsedValueWarningChecker? warnings) - { - EnsureParsers(); - - var conditions = _conditionsParser?.CheckForConditions(file, mapping, "conditions", warnings); - var executors = _executorsParser?.CheckForExecutors(file, mapping, "execute", warnings); + private ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, IParsedValueWarningChecker? warnings) + { + EnsureParsers(); - RequireNoUnexpectedMappingKeys(file, mapping, Kind, new[] { "conditions", "execute" }); + var conditions = _conditionsParser?.CheckForConditions(file, mapping, "conditions", warnings); + var executors = _executorsParser?.CheckForExecutors(file, mapping, "execute", warnings); - return new SwitchCaseExecutor() - { - Conditions = conditions, - Executors = executors, - Yaml = mapping, - YamlFile = file - }; - } + RequireNoUnexpectedMappingKeys(file, mapping, Kind, new[] { "conditions", "execute" }); - private void EnsureParsers() - { - if (_conditionsParser == null) - { - _conditionsParser = _serviceProvider.GetRequiredService(); + return new SwitchCaseExecutor() + { + Conditions = conditions, + Executors = executors, + Yaml = mapping, + YamlFile = file + }; } - if (_executorsParser == null) + private void EnsureParsers() { - _executorsParser = _serviceProvider.GetRequiredService(); + if (_conditionsParser == null) + { + _conditionsParser = _serviceProvider.GetRequiredService(); + } + + if (_executorsParser == null) + { + _executorsParser = _serviceProvider.GetRequiredService(); + } } - } - private readonly IServiceProvider _serviceProvider; - private IConditionCollectionYamlParser? _conditionsParser; - private IExecutorCollectionYamlParser? _executorsParser; -} + private readonly IServiceProvider _serviceProvider; + private IConditionCollectionYamlParser? _conditionsParser; + private IExecutorCollectionYamlParser? _executorsParser; + } +} \ No newline at end of file diff --git a/src/cs/Command/Executors/SwitchExecutor.cs b/src/cs/Command/Executors/SwitchExecutor.cs index 4e2f08b4..23e3b933 100644 --- a/src/cs/Command/Executors/SwitchExecutor.cs +++ b/src/cs/Command/Executors/SwitchExecutor.cs @@ -1,36 +1,40 @@ -namespace macaroni; +using System.Linq; +using YamlDotNet.RepresentationModel; -internal class SwitchExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public IExecutorCollection? Executors { get; internal set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class SwitchExecutor : ICommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; + public IExecutorCollection? Executors { get; internal set; } - (Executors as ILoadedFromYamlFile)?.LoadComplete(this); - } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public void Unload() - { - (Executors as ILoadedFromYamlFile)?.Unload(); - } + public void LoadComplete(object parent) + { + YamlParent = parent; - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- SWITCH: Execute({Executors?.Count()}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + (Executors as ILoadedFromYamlFile)?.LoadComplete(this); + } - var executor = Executors?.FirstOrDefault(x => IsEnabled(x, context)); - return executor?.Execute(context) ?? ExecutionResult.Completed; - } + public void Unload() + { + (Executors as ILoadedFromYamlFile)?.Unload(); + } - private bool IsEnabled(ICommandExecutor executor, IExecutionContext context) - { - var check = executor as IConditionalCommandExecutor; - return check == null || check.Conditions == null || check.Conditions.IsSatisfied(context); + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO($"-- SWITCH: Execute({Executors?.Count()}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + + var executor = Executors?.FirstOrDefault(x => IsEnabled(x, context)); + return executor?.Execute(context) ?? ExecutionResult.Completed; + } + + private bool IsEnabled(ICommandExecutor executor, IExecutionContext context) + { + var check = executor as IConditionalCommandExecutor; + return check == null || check.Conditions == null || check.Conditions.IsSatisfied(context); + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/SwitchExecutorYamlParser.cs b/src/cs/Command/Executors/SwitchExecutorYamlParser.cs index 3162c48d..e9db06ed 100644 --- a/src/cs/Command/Executors/SwitchExecutorYamlParser.cs +++ b/src/cs/Command/Executors/SwitchExecutorYamlParser.cs @@ -1,47 +1,50 @@ -using Microsoft.Extensions.DependencyInjection; +using System; +using Microsoft.Extensions.DependencyInjection; +using YamlDotNet.RepresentationModel; -namespace macaroni; - -internal class SwitchExecutorYamlParser : YamlParserBase, IExecutorYamlParser +namespace macaroni { - public SwitchExecutorYamlParser(IServiceProvider services, ISystemContext context) : base(context) + internal class SwitchExecutorYamlParser : YamlParserBase, IExecutorYamlParser { - _serviceProvider = services; - } + public SwitchExecutorYamlParser(IServiceProvider services, ISystemContext context) : base(context) + { + _serviceProvider = services; + } - public string Kind { get { return "switch"; } } + public string Kind { get { return "switch"; } } - public ICommandExecutor Parse(string file, YamlMappingNode executor, YamlNode value, IParsedValueWarningChecker? warnings) - { - var sequence = value as YamlSequenceNode; - if (sequence != null) return ParseSequence(file, executor, sequence, warnings); + public ICommandExecutor Parse(string file, YamlMappingNode executor, YamlNode value, IParsedValueWarningChecker? warnings) + { + var sequence = value as YamlSequenceNode; + if (sequence != null) return ParseSequence(file, executor, sequence, warnings); - throw ErrorParsingYamlException(file, value.Start.Line, value.Start.Column, "Unexpected YamlNode type", "EXPECTED: `switch: {case executor sequence}`"); - } + throw ErrorParsingYamlException(file, value.Start.Line, value.Start.Column, "Unexpected YamlNode type", "EXPECTED: `switch: {case executor sequence}`"); + } - private ICommandExecutor ParseSequence(string file, YamlMappingNode mapping, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) - { - EnsureParsers(); - var executors = _executorsParser?.ExecutorsFromSequence(file, sequence, warnings); + private ICommandExecutor ParseSequence(string file, YamlMappingNode mapping, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) + { + EnsureParsers(); + var executors = _executorsParser?.ExecutorsFromSequence(file, sequence, warnings); - RequireNoUnexpectedMappingKeys(file, mapping, Kind, Array.Empty()); + RequireNoUnexpectedMappingKeys(file, mapping, Kind, Array.Empty()); - return new SwitchExecutor() - { - Executors = executors, - Yaml = mapping, - YamlFile = file - }; - } + return new SwitchExecutor() + { + Executors = executors, + Yaml = mapping, + YamlFile = file + }; + } - private void EnsureParsers() - { - if (_executorsParser == null) + private void EnsureParsers() { - _executorsParser = _serviceProvider.GetRequiredService(); + if (_executorsParser == null) + { + _executorsParser = _serviceProvider.GetRequiredService(); + } } - } - private readonly IServiceProvider _serviceProvider; - private IExecutorCollectionYamlParser? _executorsParser; -} + private readonly IServiceProvider _serviceProvider; + private IExecutorCollectionYamlParser? _executorsParser; + } +} \ No newline at end of file diff --git a/src/cs/Command/Executors/TranslateExecutor.cs b/src/cs/Command/Executors/TranslateExecutor.cs index b944ed21..0916c355 100644 --- a/src/cs/Command/Executors/TranslateExecutor.cs +++ b/src/cs/Command/Executors/TranslateExecutor.cs @@ -1,39 +1,42 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class TranslateExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public string? Text { get; set; } - public string? From { get; set; } - public string? To { get; set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class TranslateExecutor : ICommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; - } + public string? Text { get; set; } + public string? From { get; set; } + public string? To { get; set; } - public void Unload() - { - } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- TRANSLATE: Execute({Text}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public void LoadComplete(object parent) + { + YamlParent = parent; + } + + public void Unload() + { + } + + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO($"-- TRANSLATE: Execute({Text}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - var text = context.Resolve(Text); - var from = context.Resolve(From); - var to = context.Resolve(To); + var text = context.Resolve(Text); + var from = context.Resolve(From); + var to = context.Resolve(To); - var translate = this.GetRequiredParentOrService(); - var translated = text != null - ? translate.Translate(text, from, to) - : ""; + var translate = this.GetRequiredParentOrService(); + var translated = text != null + ? translate.Translate(text, from, to) + : ""; - context.Set("translate.text", translated); + context.Set("translate.text", translated); - return ExecutionResult.Completed; + return ExecutionResult.Completed; + } } } diff --git a/src/cs/Command/Executors/TranslateExecutorYamlParser.cs b/src/cs/Command/Executors/TranslateExecutorYamlParser.cs index 22e56af2..e97dde3f 100644 --- a/src/cs/Command/Executors/TranslateExecutorYamlParser.cs +++ b/src/cs/Command/Executors/TranslateExecutorYamlParser.cs @@ -1,30 +1,34 @@ -namespace macaroni; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class TranslateExecutorYamlParser : ExecutorYamlParserBase +namespace macaroni { - public TranslateExecutorYamlParser(ISystemContext context) : base(context) { } - - public override string Kind { get { return "translate"; } } - public override bool TrySequenceOfStringRhs => false; - - protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) + internal class TranslateExecutorYamlParser : ExecutorYamlParserBase { - var text = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "text", warnings); - var toLanguage = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "to", warnings); - var fromLanguage = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "from", warnings); + public TranslateExecutorYamlParser(ISystemContext context) : base(context) { } - var allowed = scalar == null - ? new[] { "to", "from", "text" } - : new[] { "to", "from" }; - RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + public override string Kind { get { return "translate"; } } + public override bool TrySequenceOfStringRhs => false; - return new TranslateExecutor() + protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) { - Text = text, - From = fromLanguage, - To = toLanguage, - Yaml = mapping, - YamlFile = file - }; + var text = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "text", warnings); + var toLanguage = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "to", warnings); + var fromLanguage = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "from", warnings); + + var allowed = scalar == null + ? new[] { "to", "from", "text" } + : new[] { "to", "from" }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + + return new TranslateExecutor() + { + Text = text, + From = fromLanguage, + To = toLanguage, + Yaml = mapping, + YamlFile = file + }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/UnexpectedDialogPolicy.cs b/src/cs/Command/Executors/UnexpectedDialogPolicy.cs index 2122e4b7..3ef04f96 100644 --- a/src/cs/Command/Executors/UnexpectedDialogPolicy.cs +++ b/src/cs/Command/Executors/UnexpectedDialogPolicy.cs @@ -1,45 +1,48 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class UnexpectedDialogPolicy : IUnexpectedDialogPolicy, ILoadedFromYamlFile +namespace macaroni { - // CommandPolicy and PhrasePolicy are used to control how "dialogs" work, specifically, what happens when a - // dialog is "open" (not completed) and either (a) an unknown phrase is processed, or (b) a different command is executed - // - // The Policy values can be either (i) an Action enumerated value (e.g. Cancel) or (ii) an implementation of IExecutorCollection - // - // In cases (a) and (b), all "open" dialog commands marked as "Cancel" will be canceled, removed, and thus, no longer "open"; - // their carried context will be destroyed. - // - // In cases (a) and (b), additionally, the most recent "open" dialog command marked as either "Retry" or containing an implementation of - // IExecutorCollection, will be selected to be "retried/re-executed". If marked with action == "Retry", it will simply be "re-executed" - // with the "carried" context (dialog frame), with two changes: - // - the "context.turn" will be incremented by 1 - // - the "trigger.type" will be updated to be either "unexpected.phrase" or "unexpected.command" for cases (a) and (b) respectively. - // - // If it contains an implementation of IExeuctorCollection, the carried context changes will be applied, but instead of re-executing - // the full dialog, simply the executors contained in that policy will be executed. + internal class UnexpectedDialogPolicy : IUnexpectedDialogPolicy, ILoadedFromYamlFile + { + // CommandPolicy and PhrasePolicy are used to control how "dialogs" work, specifically, what happens when a + // dialog is "open" (not completed) and either (a) an unknown phrase is processed, or (b) a different command is executed + // + // The Policy values can be either (i) an Action enumerated value (e.g. Cancel) or (ii) an implementation of IExecutorCollection + // + // In cases (a) and (b), all "open" dialog commands marked as "Cancel" will be canceled, removed, and thus, no longer "open"; + // their carried context will be destroyed. + // + // In cases (a) and (b), additionally, the most recent "open" dialog command marked as either "Retry" or containing an implementation of + // IExecutorCollection, will be selected to be "retried/re-executed". If marked with action == "Retry", it will simply be "re-executed" + // with the "carried" context (dialog frame), with two changes: + // - the "context.turn" will be incremented by 1 + // - the "trigger.type" will be updated to be either "unexpected.phrase" or "unexpected.command" for cases (a) and (b) respectively. + // + // If it contains an implementation of IExeuctorCollection, the carried context changes will be applied, but instead of re-executing + // the full dialog, simply the executors contained in that policy will be executed. - public object? CommandPolicy { get; internal set; } - public object? PhrasePolicy { get; internal set; } - public object? TimeoutPolicy { get; internal set; } + public object? CommandPolicy { get; internal set; } + public object? PhrasePolicy { get; internal set; } + public object? TimeoutPolicy { get; internal set; } - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public void LoadComplete(object parent) - { - YamlParent = parent; + public void LoadComplete(object parent) + { + YamlParent = parent; - (CommandPolicy as ILoadedFromYamlFile)?.LoadComplete(this); - (PhrasePolicy as ILoadedFromYamlFile)?.LoadComplete(this); - (TimeoutPolicy as ILoadedFromYamlFile)?.LoadComplete(this); - } + (CommandPolicy as ILoadedFromYamlFile)?.LoadComplete(this); + (PhrasePolicy as ILoadedFromYamlFile)?.LoadComplete(this); + (TimeoutPolicy as ILoadedFromYamlFile)?.LoadComplete(this); + } - public void Unload() - { - (CommandPolicy as ILoadedFromYamlFile)?.Unload(); - (PhrasePolicy as ILoadedFromYamlFile)?.Unload(); - (TimeoutPolicy as ILoadedFromYamlFile)?.Unload(); + public void Unload() + { + (CommandPolicy as ILoadedFromYamlFile)?.Unload(); + (PhrasePolicy as ILoadedFromYamlFile)?.Unload(); + (TimeoutPolicy as ILoadedFromYamlFile)?.Unload(); + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/WaitExecutor.cs b/src/cs/Command/Executors/WaitExecutor.cs index 61498ee9..d9eabeba 100644 --- a/src/cs/Command/Executors/WaitExecutor.cs +++ b/src/cs/Command/Executors/WaitExecutor.cs @@ -1,126 +1,132 @@ -namespace macaroni; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using YamlDotNet.RepresentationModel; -internal class WaitExecutor : ICommandExecutor, ILoadedFromYamlFile, INotifyCondition +namespace macaroni { - public IConditionCollection? Conditions { get; internal set; } - public string? Timeout { get; internal set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class WaitExecutor : ICommandExecutor, ILoadedFromYamlFile, INotifyCondition { - YamlParent = parent; - (Conditions as ILoadedFromYamlFile)?.LoadComplete(this); - } + public IConditionCollection? Conditions { get; internal set; } + public string? Timeout { get; internal set; } - public void Unload() - { - (Conditions as ILoadedFromYamlFile)?.Unload(); - } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public void ConditionChanged(ICondition condition) - { - CheckWaitingTasks(); - } + public void LoadComplete(object parent) + { + YamlParent = parent; + (Conditions as ILoadedFromYamlFile)?.LoadComplete(this); + } - public ExecutionResult Execute(IExecutionContext context) - { - if (Conditions == null) return ExecutionResult.Completed; - MR.DBG_TRACE_INFO($"-- WAIT: Execute({Conditions?.Count()}, {Timeout}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + public void Unload() + { + (Conditions as ILoadedFromYamlFile)?.Unload(); + } + + public void ConditionChanged(ICondition condition) + { + CheckWaitingTasks(); + } - var satisfied = Conditions!.IsSatisfied(context); - if (!satisfied) + public ExecutionResult Execute(IExecutionContext context) { - var tcs = PrepareToWaitForTask(context, out var timeout, out var checkConditionInterval); + if (Conditions == null) return ExecutionResult.Completed; + MR.DBG_TRACE_INFO($"-- WAIT: Execute({Conditions?.Count()}, {Timeout}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - Task.Run(async () => + var satisfied = Conditions!.IsSatisfied(context); + if (!satisfied) { - while (!tcs.Task.IsCompleted) + var tcs = PrepareToWaitForTask(context, out var timeout, out var checkConditionInterval); + + Task.Run(async () => { - await Task.Delay(checkConditionInterval); - if (Conditions.IsSatisfied(context)) + while (!tcs.Task.IsCompleted) { - tcs.TrySetResult(); + await Task.Delay(checkConditionInterval); + if (Conditions.IsSatisfied(context)) + { + tcs.TrySetResult(true); + } } - } - }); + }); - satisfied = WaitForTask(tcs, timeout); - if (!satisfied) - { - MR.DBG_TRACE_INFO($"-- WAIT: Execute({Conditions?.Count()}, {Timeout}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column}) - Timeout - Stopped"); - return ExecutionResult.Stopped; + satisfied = WaitForTask(tcs, timeout); + if (!satisfied) + { + MR.DBG_TRACE_INFO($"-- WAIT: Execute({Conditions?.Count()}, {Timeout}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column}) - Timeout - Stopped"); + return ExecutionResult.Stopped; + } } - } - - return ExecutionResult.Completed; - } - private TaskCompletionSource PrepareToWaitForTask(IExecutionContext context, out int timeout, out int checkConditionInterval) - { - var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - - var waitFor = new WaitingForTask(context, Conditions!, tcs); - _waitingFor.Add(tcs, waitFor); + return ExecutionResult.Completed; + } - GetTiming(context, out timeout, out checkConditionInterval); + private TaskCompletionSource PrepareToWaitForTask(IExecutionContext context, out int timeout, out int checkConditionInterval) + { + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - return tcs; - } + var waitFor = new WaitingForTask(context, Conditions!, tcs); + _waitingFor.Add(tcs, waitFor); - private bool WaitForTask(TaskCompletionSource tcs, int timeout) - { - bool satisfied = tcs.Task.Wait(timeout); + GetTiming(context, out timeout, out checkConditionInterval); - _waitingFor.Remove(tcs); - tcs.TrySetResult(); + return tcs; + } - return satisfied; - } + private bool WaitForTask(TaskCompletionSource tcs, int timeout) + { + bool satisfied = tcs.Task.Wait(timeout); - private void GetTiming(IExecutionContext context, out int timeoutAsInt, out int checkConditionInterval) - { - var timeout = context.Resolve(Timeout); + _waitingFor.Remove(tcs); + tcs.TrySetResult(true); - if (int.TryParse(timeout, out timeoutAsInt)) - { - checkConditionInterval = timeoutAsInt / 10; + return satisfied; } - else + + private void GetTiming(IExecutionContext context, out int timeoutAsInt, out int checkConditionInterval) { - timeoutAsInt = -1; // infinite - checkConditionInterval = 500; - } - } + var timeout = context.Resolve(Timeout); - private void CheckWaitingTasks() - { - var tasks = _waitingFor.Values.ToList(); - tasks.ForEach(task => task.Check()); - } + if (int.TryParse(timeout, out timeoutAsInt)) + { + checkConditionInterval = timeoutAsInt / 10; + } + else + { + timeoutAsInt = -1; // infinite + checkConditionInterval = 500; + } + } - class WaitingForTask - { - public WaitingForTask(IExecutionContext context, IConditionCollection conditions, TaskCompletionSource source) + private void CheckWaitingTasks() { - _context = context; - _conditions = conditions; - _source = source; + var tasks = _waitingFor.Values.ToList(); + tasks.ForEach(task => task.Check()); } - public bool Check() + class WaitingForTask { - var satisfied = _conditions.IsSatisfied(_context); - if (satisfied) _source.TrySetResult(); - return satisfied; + public WaitingForTask(IExecutionContext context, IConditionCollection conditions, TaskCompletionSource source) + { + _context = context; + _conditions = conditions; + _source = source; + } + + public bool Check() + { + var satisfied = _conditions.IsSatisfied(_context); + if (satisfied) _source.TrySetResult(true); + return satisfied; + } + + private IExecutionContext _context; + private IConditionCollection _conditions; + private TaskCompletionSource _source; } - private IExecutionContext _context; - private IConditionCollection _conditions; - private TaskCompletionSource _source; + private Dictionary, WaitingForTask> _waitingFor = new Dictionary, WaitingForTask>(); } - - private Dictionary _waitingFor = new(); -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/WaitExecutorYamlParser.cs b/src/cs/Command/Executors/WaitExecutorYamlParser.cs index 52f41422..a3376b8b 100644 --- a/src/cs/Command/Executors/WaitExecutorYamlParser.cs +++ b/src/cs/Command/Executors/WaitExecutorYamlParser.cs @@ -1,78 +1,82 @@ -using Microsoft.Extensions.DependencyInjection; +using System; +using System.Linq; +using Microsoft.Extensions.DependencyInjection; +using YamlDotNet.RepresentationModel; -namespace macaroni; - -internal class WaitExecutorYamlParser : YamlParserBase, IExecutorYamlParser +namespace macaroni { - public WaitExecutorYamlParser(IServiceProvider services, ISystemContext context) : base(context) + internal class WaitExecutorYamlParser : YamlParserBase, IExecutorYamlParser { - _serviceProvider = services; - } + public WaitExecutorYamlParser(IServiceProvider services, ISystemContext context) : base(context) + { + _serviceProvider = services; + } - public string Kind { get { return "wait"; } } + public string Kind { get { return "wait"; } } - public ICommandExecutor Parse(string file, YamlMappingNode executor, YamlNode value, IParsedValueWarningChecker? warnings) - { - var scalar = value as YamlScalarNode; - if (scalar != null) return ParseScalar(file, executor, scalar, warnings); + public ICommandExecutor Parse(string file, YamlMappingNode executor, YamlNode value, IParsedValueWarningChecker? warnings) + { + var scalar = value as YamlScalarNode; + if (scalar != null) return ParseScalar(file, executor, scalar, warnings); - var sequence = value as YamlSequenceNode; - if (sequence != null) return ParseSequence(file, executor, sequence, warnings); + var sequence = value as YamlSequenceNode; + if (sequence != null) return ParseSequence(file, executor, sequence, warnings); - var mapping = value as YamlMappingNode; - if (mapping != null) return ParseMapping(file, mapping, null, warnings); + var mapping = value as YamlMappingNode; + if (mapping != null) return ParseMapping(file, mapping, null, warnings); - throw ErrorParsingYamlException(file, value.Start.Line, value.Start.Column, "Unexpected YamlNode type", "EXPECTED: `if: {condition sequence}` and `then: {executor sequence}`"); - } + throw ErrorParsingYamlException(file, value.Start.Line, value.Start.Column, "Unexpected YamlNode type", "EXPECTED: `if: {condition sequence}` and `then: {executor sequence}`"); + } - private ICommandExecutor ParseScalar(string file, YamlMappingNode executor, YamlScalarNode scalar, IParsedValueWarningChecker? warnings) - { - if (executor.Children.Count() != 1) + private ICommandExecutor ParseScalar(string file, YamlMappingNode executor, YamlScalarNode scalar, IParsedValueWarningChecker? warnings) { - throw ErrorParsingYamlException(file, "Unexpected YamlMapping node", "EXPECTED: `delay: (time)` or `wait: (time)`"); - } + if (executor.Children.Count() != 1) + { + throw ErrorParsingYamlException(file, "Unexpected YamlMapping node", "EXPECTED: `delay: (time)` or `wait: (time)`"); + } - string time = RequireScalarStringValueNotNullOrEmpty(file, Kind, scalar, warnings); + string time = RequireScalarStringValueNotNullOrEmpty(file, Kind, scalar, warnings); - RequireNoUnexpectedMappingKeys(file, executor, Kind, Array.Empty()); + RequireNoUnexpectedMappingKeys(file, executor, Kind, Array.Empty()); - return new DelayExecutor() { Time = time, Yaml = scalar, YamlFile = file }; - } + return new DelayExecutor() { Time = time, Yaml = scalar, YamlFile = file }; + } - private ICommandExecutor ParseSequence(string file, YamlMappingNode executor, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) - { - EnsureParsers(); + private ICommandExecutor ParseSequence(string file, YamlMappingNode executor, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) + { + EnsureParsers(); - var conditions = _conditionsParser?.ConditionsFromSequence(file, sequence, warnings); - return ParseMapping(file, executor, conditions, warnings); - } + var conditions = _conditionsParser?.ConditionsFromSequence(file, sequence, warnings); + return ParseMapping(file, executor, conditions, warnings); + } - private ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, IConditionCollection? sequence, IParsedValueWarningChecker? warnings) - { - EnsureParsers(); - - var conditions = sequence ?? _conditionsParser?.CheckForConditions(file, mapping, "conditions", warnings); - var timeout = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "timeout", warnings); + private ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, IConditionCollection? sequence, IParsedValueWarningChecker? warnings) + { + EnsureParsers(); - RequireNoUnexpectedMappingKeys(file, mapping, Kind, new[] { "conditions", "timeout" }); + var conditions = sequence ?? _conditionsParser?.CheckForConditions(file, mapping, "conditions", warnings); + var timeout = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "timeout", warnings); - return new WaitExecutor() - { - Conditions = conditions, - Timeout = timeout, - Yaml = mapping, - YamlFile = file - }; - } + RequireNoUnexpectedMappingKeys(file, mapping, Kind, new[] { "conditions", "timeout" }); - private void EnsureParsers() - { - if (_conditionsParser == null) + return new WaitExecutor() + { + Conditions = conditions, + Timeout = timeout, + Yaml = mapping, + YamlFile = file + }; + } + + private void EnsureParsers() { - _conditionsParser = _serviceProvider.GetRequiredService(); + if (_conditionsParser == null) + { + _conditionsParser = _serviceProvider.GetRequiredService(); + } } - } - private readonly IServiceProvider _serviceProvider; - private IConditionCollectionYamlParser? _conditionsParser; -} + private readonly IServiceProvider _serviceProvider; + private IConditionCollectionYamlParser? _conditionsParser; + } +} \ No newline at end of file diff --git a/src/cs/Command/Executors/WhenExecutor.cs b/src/cs/Command/Executors/WhenExecutor.cs index 55daba66..ba94fb4e 100644 --- a/src/cs/Command/Executors/WhenExecutor.cs +++ b/src/cs/Command/Executors/WhenExecutor.cs @@ -1,67 +1,71 @@ -namespace macaroni; +using System.Linq; +using YamlDotNet.RepresentationModel; -internal class WhenExecutor : IConditionalCommandExecutor, IWhenExecutor, ILoadedFromYamlFile +namespace macaroni { - public IConditionCollection? Conditions { get; internal set; } - public IExecutorCollection? Executors { get; internal set; } - public ITriggerCollection? Expect { get; internal set; } - public IUnexpectedDialogPolicy? Unexpected { get; internal set; } - public string? Continue { get; internal set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class WhenExecutor : IConditionalCommandExecutor, IWhenExecutor, ILoadedFromYamlFile { - YamlParent = parent; + public IConditionCollection? Conditions { get; internal set; } + public IExecutorCollection? Executors { get; internal set; } + public ITriggerCollection? Expect { get; internal set; } + public IUnexpectedDialogPolicy? Unexpected { get; internal set; } + public string? Continue { get; internal set; } - (Conditions as ILoadedFromYamlFile)?.LoadComplete(this); - (Executors as ILoadedFromYamlFile)?.LoadComplete(this); - (Expect as ILoadedFromYamlFile)?.LoadComplete(this); - (Unexpected as ILoadedFromYamlFile)?.LoadComplete(this); - } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public void Unload() - { - (Conditions as ILoadedFromYamlFile)?.Unload(); - (Executors as ILoadedFromYamlFile)?.Unload(); - (Expect as ILoadedFromYamlFile)?.Unload(); - (Unexpected as ILoadedFromYamlFile)?.Unload(); - } + public void LoadComplete(object parent) + { + YamlParent = parent; - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- WHEN: Execute({Executors?.Count()}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + (Conditions as ILoadedFromYamlFile)?.LoadComplete(this); + (Executors as ILoadedFromYamlFile)?.LoadComplete(this); + (Expect as ILoadedFromYamlFile)?.LoadComplete(this); + (Unexpected as ILoadedFromYamlFile)?.LoadComplete(this); + } - if (Conditions != null && Conditions.IsSatisfied(context)) + public void Unload() { - var command = this.GetRequiredParentOrService(); - command.PersistContext(context, Expect, Unexpected); + (Conditions as ILoadedFromYamlFile)?.Unload(); + (Executors as ILoadedFromYamlFile)?.Unload(); + (Expect as ILoadedFromYamlFile)?.Unload(); + (Unexpected as ILoadedFromYamlFile)?.Unload(); + } - var result = Executors?.Execute(context) ?? ExecutionResult.Completed; + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO($"-- WHEN: Execute({Executors?.Count()}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - if (result == ExecutionResult.Stopped) + if (Conditions != null && Conditions.IsSatisfied(context)) { - MR.DBG_TRACE_INFO($"-- WHEN: Execute({Executors?.Count()}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column}) - Stopped"); - return result; - } + var command = this.GetRequiredParentOrService(); + command.PersistContext(context, Expect, Unexpected); - if (result == ExecutionResult.Canceled) - { - MR.DBG_TRACE_INFO($"-- WHEN: Execute({Executors?.Count()}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column}) - Canceled"); + var result = Executors?.Execute(context) ?? ExecutionResult.Completed; + + if (result == ExecutionResult.Stopped) + { + MR.DBG_TRACE_INFO($"-- WHEN: Execute({Executors?.Count()}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column}) - Stopped"); + return result; + } + + if (result == ExecutionResult.Canceled) + { + MR.DBG_TRACE_INFO($"-- WHEN: Execute({Executors?.Count()}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column}) - Canceled"); + return result; + } + + command.PersistContext(context, Expect, Unexpected); + result = Expect?.Count() > 0 + ? ExecutionResult.Yielded + : ExecutionResult.Completed; + + MR.DBG_TRACE_INFO($"-- WHEN: Execute({Executors?.Count()}): {YamlFile}({Yaml?.End.Line},{Yaml?.End.Column}) - {result}"); return result; } - command.PersistContext(context, Expect, Unexpected); - result = Expect?.Count() > 0 - ? ExecutionResult.Yielded - : ExecutionResult.Completed; - - MR.DBG_TRACE_INFO($"-- WHEN: Execute({Executors?.Count()}): {YamlFile}({Yaml?.End.Line},{Yaml?.End.Column}) - {result}"); - return result; + return ExecutionResult.Completed; } - - return ExecutionResult.Completed; } } diff --git a/src/cs/Command/Executors/WhenExecutorYamlParser.cs b/src/cs/Command/Executors/WhenExecutorYamlParser.cs index ee052b93..a820a1e1 100644 --- a/src/cs/Command/Executors/WhenExecutorYamlParser.cs +++ b/src/cs/Command/Executors/WhenExecutorYamlParser.cs @@ -1,208 +1,211 @@ -using Microsoft.Extensions.DependencyInjection; +using System; +using Microsoft.Extensions.DependencyInjection; +using YamlDotNet.RepresentationModel; -namespace macaroni; - -internal class WhenExecutorYamlParser : YamlParserBase, IExecutorYamlParser +namespace macaroni { - public WhenExecutorYamlParser(IServiceProvider services, ISystemContext context) : base(context) - { - _serviceProvider = services; - } - - public string Kind { get { return "when"; } } - - public ICommandExecutor Parse(string file, YamlMappingNode executor, YamlNode value, IParsedValueWarningChecker? warnings) + internal class WhenExecutorYamlParser : YamlParserBase, IExecutorYamlParser { - var sequence = value as YamlSequenceNode; - if (sequence != null) return ParseSequence(file, executor, sequence, warnings); - - var mapping = value as YamlMappingNode; - if (mapping != null) return ParseMapping(file, mapping, warnings); - - throw ErrorParsingYamlException(file, value.Start.Line, value.Start.Column, "Unexpected YamlNode type", "EXPECTED: `when: {condition sequence}` and `execute: {executor sequence}`"); - } - - private ICommandExecutor ParseSequence(string file, YamlMappingNode executor, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) - { - EnsureParsers(); - - var conditions = _conditionsParser?.ConditionsFromSequence(file, sequence, warnings); - var executors = _executorsParser?.CheckForExecutors(file, executor, "execute", warnings); - var triggers = _triggersParser?.CheckForTriggers(file, executor, "expect", warnings); - var unexpected = ParseUnexpected(file, executor, "unexpected", warnings); - var continueValue = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, executor, "continue", warnings); + public WhenExecutorYamlParser(IServiceProvider services, ISystemContext context) : base(context) + { + _serviceProvider = services; + } - RequireNoUnexpectedMappingKeys(file, executor, Kind, new[] { "execute", "expect", "unexpected", "continue" }); + public string Kind { get { return "when"; } } - return new WhenExecutor() + public ICommandExecutor Parse(string file, YamlMappingNode executor, YamlNode value, IParsedValueWarningChecker? warnings) { - Conditions = conditions, - Executors = executors, - Expect = triggers, - Unexpected = unexpected, - Continue = continueValue, - Yaml = executor, - YamlFile = file - }; - } + var sequence = value as YamlSequenceNode; + if (sequence != null) return ParseSequence(file, executor, sequence, warnings); - private ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, IParsedValueWarningChecker? warnings) - { - EnsureParsers(); - - var conditions = _conditionsParser?.CheckForConditions(file, mapping, "conditions", warnings); - var executors = _executorsParser?.CheckForExecutors(file, mapping, "execute", warnings); - var triggers = _triggersParser?.CheckForTriggers(file, mapping, "expect", warnings); - var unexpected = ParseUnexpected(file, mapping, "unexpected", warnings); - var continueValue = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "continue", warnings); + var mapping = value as YamlMappingNode; + if (mapping != null) return ParseMapping(file, mapping, warnings); - RequireNoUnexpectedMappingKeys(file, mapping, Kind, new[] { "conditions", "execute", "expect", "unexpected", "continue" }); + throw ErrorParsingYamlException(file, value.Start.Line, value.Start.Column, "Unexpected YamlNode type", "EXPECTED: `when: {condition sequence}` and `execute: {executor sequence}`"); + } - return new WhenExecutor() + private ICommandExecutor ParseSequence(string file, YamlMappingNode executor, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) { - Conditions = conditions, - Executors = executors, - Expect = triggers, - Unexpected = unexpected, - Continue = continueValue, - Yaml = mapping, - YamlFile = file - }; - } + EnsureParsers(); + + var conditions = _conditionsParser?.ConditionsFromSequence(file, sequence, warnings); + var executors = _executorsParser?.CheckForExecutors(file, executor, "execute", warnings); + var triggers = _triggersParser?.CheckForTriggers(file, executor, "expect", warnings); + var unexpected = ParseUnexpected(file, executor, "unexpected", warnings); + var continueValue = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, executor, "continue", warnings); + + RequireNoUnexpectedMappingKeys(file, executor, Kind, new[] { "execute", "expect", "unexpected", "continue" }); + + return new WhenExecutor() + { + Conditions = conditions, + Executors = executors, + Expect = triggers, + Unexpected = unexpected, + Continue = continueValue, + Yaml = executor, + YamlFile = file + }; + } - private IUnexpectedDialogPolicy? ParseUnexpected(string file, YamlMappingNode mapping, string mappingName, IParsedValueWarningChecker? warnings) - { - var ok = mapping.Children.ContainsKey(mappingName); - if (!ok) return DefaultUnexpectedDialogPolicy(file, mapping); + private ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, IParsedValueWarningChecker? warnings) + { + EnsureParsers(); + + var conditions = _conditionsParser?.CheckForConditions(file, mapping, "conditions", warnings); + var executors = _executorsParser?.CheckForExecutors(file, mapping, "execute", warnings); + var triggers = _triggersParser?.CheckForTriggers(file, mapping, "expect", warnings); + var unexpected = ParseUnexpected(file, mapping, "unexpected", warnings); + var continueValue = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "continue", warnings); + + RequireNoUnexpectedMappingKeys(file, mapping, Kind, new[] { "conditions", "execute", "expect", "unexpected", "continue" }); + + return new WhenExecutor() + { + Conditions = conditions, + Executors = executors, + Expect = triggers, + Unexpected = unexpected, + Continue = continueValue, + Yaml = mapping, + YamlFile = file + }; + } - var node = mapping.Children[mappingName]; - var asScalar = node as YamlScalarNode; - if (asScalar != null) return ParseUnexpectedScalar(file, mapping, mappingName, asScalar); + private IUnexpectedDialogPolicy? ParseUnexpected(string file, YamlMappingNode mapping, string mappingName, IParsedValueWarningChecker? warnings) + { + var ok = mapping.Children.ContainsKey(mappingName); + if (!ok) return DefaultUnexpectedDialogPolicy(file, mapping); - var asSequence = node as YamlSequenceNode; - if (asSequence != null) return ParseUnexpectedSequence(file, mapping, asSequence, warnings); + var node = mapping.Children[mappingName]; + var asScalar = node as YamlScalarNode; + if (asScalar != null) return ParseUnexpectedScalar(file, mapping, mappingName, asScalar); - var asMapping = node as YamlMappingNode; - if (asMapping != null) return ParseUnexpectedMapping(file, asMapping, warnings); + var asSequence = node as YamlSequenceNode; + if (asSequence != null) return ParseUnexpectedSequence(file, mapping, asSequence, warnings); - throw ErrorParsingYamlException(file, node.Start.Line, node.Start.Column, $"Unexpected `{mappingName}` value", $"EXPECTED: `ignore`/`cancel`/`retry` or {{mapping}}"); - } + var asMapping = node as YamlMappingNode; + if (asMapping != null) return ParseUnexpectedMapping(file, asMapping, warnings); - private static IUnexpectedDialogPolicy.Action GetDefaultCommandPolicy() - { - return IUnexpectedDialogPolicy.Action.Cancel; - } - - private static IUnexpectedDialogPolicy.Action GetDefaultPhrasePolicy() - { - return IUnexpectedDialogPolicy.Action.Retry; - } + throw ErrorParsingYamlException(file, node.Start.Line, node.Start.Column, $"Unexpected `{mappingName}` value", $"EXPECTED: `ignore`/`cancel`/`retry` or {{mapping}}"); + } - private static IUnexpectedDialogPolicy.Action GetDefaultTimeoutPolicy() - { - return IUnexpectedDialogPolicy.Action.Cancel; - } + private static IUnexpectedDialogPolicy.Action GetDefaultCommandPolicy() + { + return IUnexpectedDialogPolicy.Action.Cancel; + } - private static IUnexpectedDialogPolicy DefaultUnexpectedDialogPolicy(string file, YamlMappingNode mapping) - { - return new UnexpectedDialogPolicy() + private static IUnexpectedDialogPolicy.Action GetDefaultPhrasePolicy() { - Yaml = mapping, - YamlFile = file, - CommandPolicy = GetDefaultCommandPolicy(), - PhrasePolicy = GetDefaultPhrasePolicy(), - TimeoutPolicy = GetDefaultTimeoutPolicy(), - }; - } + return IUnexpectedDialogPolicy.Action.Retry; + } - private IUnexpectedDialogPolicy? ParseUnexpectedScalar(string file, YamlMappingNode mapping, string parent, YamlScalarNode scalar) - { - var action = ActionFrom(file, mapping, parent, scalar.Value); - return new UnexpectedDialogPolicy() + private static IUnexpectedDialogPolicy.Action GetDefaultTimeoutPolicy() { - Yaml = scalar, - YamlFile = file, - CommandPolicy = action, - PhrasePolicy = action, - TimeoutPolicy = action, - }; - } + return IUnexpectedDialogPolicy.Action.Cancel; + } - private IUnexpectedDialogPolicy? ParseUnexpectedSequence(string file, YamlMappingNode mapping, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) - { - var executors = _executorsParser?.ExecutorsFromSequence(file, sequence, warnings); - return new UnexpectedDialogPolicy() + private static IUnexpectedDialogPolicy DefaultUnexpectedDialogPolicy(string file, YamlMappingNode mapping) { - Yaml = sequence, - YamlFile = file, - CommandPolicy = executors, - PhrasePolicy = executors, - TimeoutPolicy = executors, - }; - } + return new UnexpectedDialogPolicy() + { + Yaml = mapping, + YamlFile = file, + CommandPolicy = GetDefaultCommandPolicy(), + PhrasePolicy = GetDefaultPhrasePolicy(), + TimeoutPolicy = GetDefaultTimeoutPolicy(), + }; + } - private IUnexpectedDialogPolicy? ParseUnexpectedMapping(string file, YamlMappingNode mapping, IParsedValueWarningChecker? warnings) - { - var command = ParseUnexpectedMapping(file, mapping, "command", GetDefaultCommandPolicy(), warnings); - var phrase = ParseUnexpectedMapping(file, mapping, "phrase", GetDefaultPhrasePolicy(), warnings); - var timeout = ParseUnexpectedMapping(file, mapping, "timeout", GetDefaultTimeoutPolicy(), warnings); - RequireNoUnexpectedMappingKeys(file, mapping, "unexpected", new [] { "command", "phrase", "timeout" }); - return new UnexpectedDialogPolicy() + private IUnexpectedDialogPolicy? ParseUnexpectedScalar(string file, YamlMappingNode mapping, string parent, YamlScalarNode scalar) { - Yaml = mapping, - YamlFile = file, - CommandPolicy = command, - PhrasePolicy = phrase, - TimeoutPolicy = timeout, - }; - } + var action = ActionFrom(file, mapping, parent, scalar.Value); + return new UnexpectedDialogPolicy() + { + Yaml = scalar, + YamlFile = file, + CommandPolicy = action, + PhrasePolicy = action, + TimeoutPolicy = action, + }; + } - private object? ParseUnexpectedMapping(string file, YamlMappingNode mapping, string mappingName, IUnexpectedDialogPolicy.Action action, IParsedValueWarningChecker? warnings) - { - var ok = mapping.Children.ContainsKey(mappingName); - if (!ok) return action; + private IUnexpectedDialogPolicy? ParseUnexpectedSequence(string file, YamlMappingNode mapping, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) + { + var executors = _executorsParser?.ExecutorsFromSequence(file, sequence, warnings); + return new UnexpectedDialogPolicy() + { + Yaml = sequence, + YamlFile = file, + CommandPolicy = executors, + PhrasePolicy = executors, + TimeoutPolicy = executors, + }; + } - var node = mapping.Children[mappingName]; - var scalar = node as YamlScalarNode; - if (scalar != null) return ActionFrom(file, mapping, mappingName, scalar.Value); + private IUnexpectedDialogPolicy? ParseUnexpectedMapping(string file, YamlMappingNode mapping, IParsedValueWarningChecker? warnings) + { + var command = ParseUnexpectedMapping(file, mapping, "command", GetDefaultCommandPolicy(), warnings); + var phrase = ParseUnexpectedMapping(file, mapping, "phrase", GetDefaultPhrasePolicy(), warnings); + var timeout = ParseUnexpectedMapping(file, mapping, "timeout", GetDefaultTimeoutPolicy(), warnings); + RequireNoUnexpectedMappingKeys(file, mapping, "unexpected", new[] { "command", "phrase", "timeout" }); + return new UnexpectedDialogPolicy() + { + Yaml = mapping, + YamlFile = file, + CommandPolicy = command, + PhrasePolicy = phrase, + TimeoutPolicy = timeout, + }; + } - var executors = _executorsParser?.CheckForExecutors(file, mapping, mappingName, warnings); - if (executors != null) return executors; + private object? ParseUnexpectedMapping(string file, YamlMappingNode mapping, string mappingName, IUnexpectedDialogPolicy.Action action, IParsedValueWarningChecker? warnings) + { + var ok = mapping.Children.ContainsKey(mappingName); + if (!ok) return action; - throw ErrorParsingYamlException(file, node.Start.Line, node.Start.Column, $"Unexpected `{mappingName}` value", $"EXPECTED: {{sequence of executors}} or `ignore`/`cancel`/`retry`"); - } + var node = mapping.Children[mappingName]; + var scalar = node as YamlScalarNode; + if (scalar != null) return ActionFrom(file, mapping, mappingName, scalar.Value); - private IUnexpectedDialogPolicy.Action ActionFrom(string file, YamlMappingNode mapping, string mappingName, string? value) - { - return value switch - { - "ignore" => IUnexpectedDialogPolicy.Action.Ignore, - "cancel" => IUnexpectedDialogPolicy.Action.Cancel, - "retry" => IUnexpectedDialogPolicy.Action.Retry, - _ => throw ErrorParsingYamlException(file, mapping.Start.Line, mapping.Start.Column, $"When parsing `{mappingName}`, found `{value}`", $"EXPECTED: `ignore`/`cancel`/`retry`") - }; - } + var executors = _executorsParser?.CheckForExecutors(file, mapping, mappingName, warnings); + if (executors != null) return executors; - private void EnsureParsers() - { - if (_conditionsParser == null) - { - _conditionsParser = _serviceProvider.GetRequiredService(); + throw ErrorParsingYamlException(file, node.Start.Line, node.Start.Column, $"Unexpected `{mappingName}` value", $"EXPECTED: {{sequence of executors}} or `ignore`/`cancel`/`retry`"); } - if (_executorsParser == null) + private IUnexpectedDialogPolicy.Action ActionFrom(string file, YamlMappingNode mapping, string mappingName, string? value) { - _executorsParser = _serviceProvider.GetRequiredService(); + return value switch + { + "ignore" => IUnexpectedDialogPolicy.Action.Ignore, + "cancel" => IUnexpectedDialogPolicy.Action.Cancel, + "retry" => IUnexpectedDialogPolicy.Action.Retry, + _ => throw ErrorParsingYamlException(file, mapping.Start.Line, mapping.Start.Column, $"When parsing `{mappingName}`, found `{value}`", $"EXPECTED: `ignore`/`cancel`/`retry`") + }; } - if (_triggersParser == null) + private void EnsureParsers() { - _triggersParser = _serviceProvider.GetRequiredService(); + if (_conditionsParser == null) + { + _conditionsParser = _serviceProvider.GetRequiredService(); + } + + if (_executorsParser == null) + { + _executorsParser = _serviceProvider.GetRequiredService(); + } + + if (_triggersParser == null) + { + _triggersParser = _serviceProvider.GetRequiredService(); + } } - } - private readonly IServiceProvider _serviceProvider; - private IConditionCollectionYamlParser? _conditionsParser; - private IExecutorCollectionYamlParser? _executorsParser; - private ITriggerCollectionYamlParser? _triggersParser; -} + private readonly IServiceProvider _serviceProvider; + private IConditionCollectionYamlParser? _conditionsParser; + private IExecutorCollectionYamlParser? _executorsParser; + private ITriggerCollectionYamlParser? _triggersParser; + } +} \ No newline at end of file diff --git a/src/cs/Command/Executors/WhileExecutor.cs b/src/cs/Command/Executors/WhileExecutor.cs index 1e7ba6b7..70bee96f 100644 --- a/src/cs/Command/Executors/WhileExecutor.cs +++ b/src/cs/Command/Executors/WhileExecutor.cs @@ -1,42 +1,46 @@ -namespace macaroni; +using System.Linq; +using YamlDotNet.RepresentationModel; - -internal class WhileExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public IConditionCollection? Conditions { get; internal set; } - public IExecutorCollection? Executors { get; internal set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + + internal class WhileExecutor : ICommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; + public IConditionCollection? Conditions { get; internal set; } + public IExecutorCollection? Executors { get; internal set; } - (Conditions as ILoadedFromYamlFile)?.LoadComplete(this); - (Executors as ILoadedFromYamlFile)?.LoadComplete(this); - } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public void Unload() - { - (Conditions as ILoadedFromYamlFile)?.Unload(); - (Executors as ILoadedFromYamlFile)?.Unload(); - } + public void LoadComplete(object parent) + { + YamlParent = parent; - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- WHILE: Execute(then={Executors?.Count()}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + (Conditions as ILoadedFromYamlFile)?.LoadComplete(this); + (Executors as ILoadedFromYamlFile)?.LoadComplete(this); + } + + public void Unload() + { + (Conditions as ILoadedFromYamlFile)?.Unload(); + (Executors as ILoadedFromYamlFile)?.Unload(); + } - ExecutionResult? result = ExecutionResult.Completed; - if (Conditions != null) + public ExecutionResult Execute(IExecutionContext context) { - while (Conditions.IsSatisfied(context) && result == ExecutionResult.Completed) + MR.DBG_TRACE_INFO($"-- WHILE: Execute(then={Executors?.Count()}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); + + ExecutionResult? result = ExecutionResult.Completed; + if (Conditions != null) { - result = Executors?.Execute(context); + while (Conditions.IsSatisfied(context) && result == ExecutionResult.Completed) + { + result = Executors?.Execute(context); + } } - } - return result ?? ExecutionResult.Completed; + return result ?? ExecutionResult.Completed; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Executors/WhileExecutorYamlParser.cs b/src/cs/Command/Executors/WhileExecutorYamlParser.cs index 7981ff48..e5f6e495 100644 --- a/src/cs/Command/Executors/WhileExecutorYamlParser.cs +++ b/src/cs/Command/Executors/WhileExecutorYamlParser.cs @@ -1,77 +1,80 @@ -using Microsoft.Extensions.DependencyInjection; +using System; +using Microsoft.Extensions.DependencyInjection; +using YamlDotNet.RepresentationModel; -namespace macaroni; - -internal class WhileExecutorYamlParser : YamlParserBase, IExecutorYamlParser +namespace macaroni { - public WhileExecutorYamlParser(IServiceProvider services, ISystemContext context) : base(context) + internal class WhileExecutorYamlParser : YamlParserBase, IExecutorYamlParser { - _serviceProvider = services; - } + public WhileExecutorYamlParser(IServiceProvider services, ISystemContext context) : base(context) + { + _serviceProvider = services; + } - public string Kind { get { return "while"; } } + public string Kind { get { return "while"; } } - public ICommandExecutor Parse(string file, YamlMappingNode executor, YamlNode value, IParsedValueWarningChecker? warnings) - { - var sequence = value as YamlSequenceNode; - if (sequence != null) return ParseSequence(file, executor, sequence, warnings); + public ICommandExecutor Parse(string file, YamlMappingNode executor, YamlNode value, IParsedValueWarningChecker? warnings) + { + var sequence = value as YamlSequenceNode; + if (sequence != null) return ParseSequence(file, executor, sequence, warnings); - var mapping = value as YamlMappingNode; - if (mapping != null) return ParseMapping(file, mapping, warnings); + var mapping = value as YamlMappingNode; + if (mapping != null) return ParseMapping(file, mapping, warnings); - throw ErrorParsingYamlException(file, value.Start.Line, value.Start.Column, "Unexpected YamlNode type", "EXPECTED: `while: {condition sequence}` and `execute: {executor sequence}`"); - } + throw ErrorParsingYamlException(file, value.Start.Line, value.Start.Column, "Unexpected YamlNode type", "EXPECTED: `while: {condition sequence}` and `execute: {executor sequence}`"); + } - private ICommandExecutor ParseSequence(string file, YamlMappingNode executor, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) - { - EnsureParsers(); + private ICommandExecutor ParseSequence(string file, YamlMappingNode executor, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) + { + EnsureParsers(); - var conditions = _conditionsParser?.ConditionsFromSequence(file, sequence, warnings); - var executors = _executorsParser?.CheckForExecutors(file, executor, "execute", warnings); + var conditions = _conditionsParser?.ConditionsFromSequence(file, sequence, warnings); + var executors = _executorsParser?.CheckForExecutors(file, executor, "execute", warnings); - RequireNoUnexpectedMappingKeys(file, executor, Kind, new[] { "execute" }); + RequireNoUnexpectedMappingKeys(file, executor, Kind, new[] { "execute" }); - return new WhileExecutor() - { - Conditions = conditions, - Executors = executors, - Yaml = executor, - YamlFile = file - }; - } + return new WhileExecutor() + { + Conditions = conditions, + Executors = executors, + Yaml = executor, + YamlFile = file + }; + } - private ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, IParsedValueWarningChecker? warnings) - { - EnsureParsers(); - - var conditions = _conditionsParser?.CheckForConditions(file, mapping, "conditions", warnings); - var executors = _executorsParser?.CheckForExecutors(file, mapping, "execute", warnings); + private ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, IParsedValueWarningChecker? warnings) + { + EnsureParsers(); - RequireNoUnexpectedMappingKeys(file, mapping, Kind, new[] { "conditions", "execute" }); + var conditions = _conditionsParser?.CheckForConditions(file, mapping, "conditions", warnings); + var executors = _executorsParser?.CheckForExecutors(file, mapping, "execute", warnings); - return new WhileExecutor() - { - Conditions = conditions, - Executors = executors, - Yaml = mapping, - YamlFile = file - }; - } + RequireNoUnexpectedMappingKeys(file, mapping, Kind, new[] { "conditions", "execute" }); - private void EnsureParsers() - { - if (_conditionsParser == null) - { - _conditionsParser = _serviceProvider.GetRequiredService(); + return new WhileExecutor() + { + Conditions = conditions, + Executors = executors, + Yaml = mapping, + YamlFile = file + }; } - if (_executorsParser == null) + private void EnsureParsers() { - _executorsParser = _serviceProvider.GetRequiredService(); + if (_conditionsParser == null) + { + _conditionsParser = _serviceProvider.GetRequiredService(); + } + + if (_executorsParser == null) + { + _executorsParser = _serviceProvider.GetRequiredService(); + } } - } - private readonly IServiceProvider _serviceProvider; - private IConditionCollectionYamlParser? _conditionsParser; - private IExecutorCollectionYamlParser? _executorsParser; -} + private readonly IServiceProvider _serviceProvider; + private IConditionCollectionYamlParser? _conditionsParser; + private IExecutorCollectionYamlParser? _executorsParser; + } +} \ No newline at end of file diff --git a/src/cs/Command/Executors/YamlExecutor.cs b/src/cs/Command/Executors/YamlExecutor.cs index 915c0a50..a179b402 100644 --- a/src/cs/Command/Executors/YamlExecutor.cs +++ b/src/cs/Command/Executors/YamlExecutor.cs @@ -1,64 +1,68 @@ -using System.Text.Json; +using System; +using System.IO; +using System.Linq; +using YamlDotNet.RepresentationModel; -namespace macaroni; - -internal class YamlExecutor : ICommandExecutor, ILoadedFromYamlFile +namespace macaroni { - public string? Data { get; set; } - public string? Path { get; set; } - public string? Output { get; set; } - - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class YamlExecutor : ICommandExecutor, ILoadedFromYamlFile { - YamlParent = parent; - } + public string? Data { get; set; } + public string? Path { get; set; } + public string? Output { get; set; } - public void Unload() - { - } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public ExecutionResult Execute(IExecutionContext context) - { - MR.DBG_TRACE_INFO($"-- YAML: Execute({Data}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - - var data = context.Resolve(Data); - var path = context.Resolve(Path) ?? ""; - var output = context.Resolve(Output) ?? ""; + public void LoadComplete(object parent) + { + YamlParent = parent; + } - if (data != null) + public void Unload() { - data = JsonFromYaml(data); - _parser.PopulateContext(context, data, path, output); } - return ExecutionResult.Completed; - } + public ExecutionResult Execute(IExecutionContext context) + { + MR.DBG_TRACE_INFO($"-- YAML: Execute({Data}): {YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"); - private string JsonFromYaml(string data) - { - var stream = new YamlStream(); - stream.Load(new StringReader(data)); - return JsonFromYaml(stream.Documents[0].RootNode); - } + var data = context.Resolve(Data); + var path = context.Resolve(Path) ?? ""; + var output = context.Resolve(Output) ?? ""; - private string JsonFromYaml(YamlNode node) - { - switch (node) + if (data != null) + { + data = JsonFromYaml(data); + _parser.PopulateContext(context, data, path, output); + } + + return ExecutionResult.Completed; + } + + private string JsonFromYaml(string data) { - case YamlScalarNode scalar: - return scalar.Value == null ? "null" : $"\"{scalar.Value}\""; - case YamlSequenceNode sequence: - return $"[{string.Join(",", sequence.Select(JsonFromYaml))}]"; - case YamlMappingNode mapping: - return $"{{{string.Join(",", mapping.Children.Select(c => $"\"{c.Key}\":{JsonFromYaml(c.Value)}"))}}}"; - default: - throw new NotImplementedException(); + var stream = new YamlStream(); + stream.Load(new StringReader(data)); + return JsonFromYaml(stream.Documents[0].RootNode); } - } - private ContextPopulatingJsonParser _parser = new ContextPopulatingJsonParser("yaml"); -} + private string JsonFromYaml(YamlNode node) + { + switch (node) + { + case YamlScalarNode scalar: + return scalar.Value == null ? "null" : $"\"{scalar.Value}\""; + case YamlSequenceNode sequence: + return $"[{string.Join(",", sequence.Select(JsonFromYaml))}]"; + case YamlMappingNode mapping: + return $"{{{string.Join(",", mapping.Children.Select(c => $"\"{c.Key}\":{JsonFromYaml(c.Value)}"))}}}"; + default: + throw new NotImplementedException(); + } + } + + private ContextPopulatingJsonParser _parser = new ContextPopulatingJsonParser("yaml"); + } +} \ No newline at end of file diff --git a/src/cs/Command/Executors/YamlExecutorYamlParser.cs b/src/cs/Command/Executors/YamlExecutorYamlParser.cs index 6aec493a..6e24d512 100644 --- a/src/cs/Command/Executors/YamlExecutorYamlParser.cs +++ b/src/cs/Command/Executors/YamlExecutorYamlParser.cs @@ -1,30 +1,34 @@ -namespace macaroni; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class YamlExecutorYamlParser : ExecutorYamlParserBase +namespace macaroni { - public YamlExecutorYamlParser(ISystemContext context) : base(context) { } - - public override string Kind { get { return "yaml"; } } - public override bool TrySequenceOfStringRhs => false; - - protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) + internal class YamlExecutorYamlParser : ExecutorYamlParserBase { - var yaml = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "data", warnings); - var path = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "path", warnings); - var output = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "output", warnings) ?? path; + public YamlExecutorYamlParser(ISystemContext context) : base(context) { } - var allowed = scalar == null - ? new[] { "path", "output", "data" } - : new[] { "path", "output" }; - RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + public override string Kind { get { return "yaml"; } } + public override bool TrySequenceOfStringRhs => false; - return new YamlExecutor() + protected override ICommandExecutor ParseMapping(string file, YamlMappingNode mapping, string? scalar, IEnumerable? sequence, IParsedValueWarningChecker? warnings) { - Data = yaml, - Path = path, - Output = output, - Yaml = mapping, - YamlFile = file - }; + var yaml = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "data", warnings); + var path = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "path", warnings); + var output = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "output", warnings) ?? path; + + var allowed = scalar == null + ? new[] { "path", "output", "data" } + : new[] { "path", "output" }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + + return new YamlExecutor() + { + Data = yaml, + Path = path, + Output = output, + Yaml = mapping, + YamlFile = file + }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Triggers/CommandTrigger.cs b/src/cs/Command/Triggers/CommandTrigger.cs index 09b21ba0..a77aa22b 100644 --- a/src/cs/Command/Triggers/CommandTrigger.cs +++ b/src/cs/Command/Triggers/CommandTrigger.cs @@ -1,17 +1,20 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class CommandTrigger : ICommandTrigger, ILoadedFromYamlFile +namespace macaroni { - public YamlNode? Yaml { get; internal set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) + internal class CommandTrigger : ICommandTrigger, ILoadedFromYamlFile { - YamlParent = parent; - } + public YamlNode? Yaml { get; internal set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public void Unload() - { + public void LoadComplete(object parent) + { + YamlParent = parent; + } + + public void Unload() + { + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Triggers/HotkeyTrigger.cs b/src/cs/Command/Triggers/HotkeyTrigger.cs index e88a01c0..089170cb 100644 --- a/src/cs/Command/Triggers/HotkeyTrigger.cs +++ b/src/cs/Command/Triggers/HotkeyTrigger.cs @@ -1,28 +1,32 @@ -namespace macaroni; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class HotkeyTrigger : ICommandTrigger, ILoadedFromYamlFile +namespace macaroni { - public HotkeyTrigger(string hotkey) : this(new [] { hotkey }) + internal class HotkeyTrigger : ICommandTrigger, ILoadedFromYamlFile { - } + public HotkeyTrigger(string hotkey) : this(new[] { hotkey }) + { + } - public HotkeyTrigger(IEnumerable hotkeys) - { - Hotkeys = new List(hotkeys); - } + public HotkeyTrigger(IEnumerable hotkeys) + { + Hotkeys = new List(hotkeys); + } - public IEnumerable Hotkeys { get; set; } + public IEnumerable Hotkeys { get; set; } - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) - { - YamlParent = parent; - } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public void Unload() - { + public void LoadComplete(object parent) + { + YamlParent = parent; + } + + public void Unload() + { + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Triggers/HotkeyTriggerCommandSetExtension.cs b/src/cs/Command/Triggers/HotkeyTriggerCommandSetExtension.cs index 43b016f8..992afa30 100644 --- a/src/cs/Command/Triggers/HotkeyTriggerCommandSetExtension.cs +++ b/src/cs/Command/Triggers/HotkeyTriggerCommandSetExtension.cs @@ -1,20 +1,21 @@ -using Microsoft.CognitiveServices.Speech.Intent; +using System.Collections.Generic; +using System.Linq; -namespace macaroni; - -internal class HotkeyTriggerCommandSetExtension : ICommandSetExtension, INotifyCondition, INotifyYamlValues +namespace macaroni { - public void InitCommandSetExtension(ICommandSet commandSet) + internal class HotkeyTriggerCommandSetExtension : ICommandSetExtension, INotifyCondition, INotifyYamlValues { - _commandSet = commandSet; - _commandExecutionService = _commandSet?.GetParentOrService(); - _hotkeyService = _commandSet?.GetParentOrService(); - } + public void InitCommandSetExtension(ICommandSet commandSet) + { + _commandSet = commandSet; + _commandExecutionService = _commandSet?.GetParentOrService(); + _hotkeyService = _commandSet?.GetParentOrService(); + } - public void EnableExtension(bool enabled) - { - EnableHotkeyTriggers(enabled); - } + public void EnableExtension(bool enabled) + { + EnableHotkeyTriggers(enabled); + } public void ValueChanged(IYamlValue value) { @@ -30,135 +31,136 @@ public void ConditionChanged(ICondition condition) MR.DBG_TRACE_INFO($"HotkeyTriggerCommandSetExtension::ConditionChanged({condition.GetType().Name}) ... Done!"); } - private void EnableHotkeyTriggers(bool enabled) - { - if (enabled) - { - ReloadTriggers(); - } - else - { - UnloadTriggers(); - } - } - - private void ReloadTriggers() - { - if (_hotkeyGroupId != null) + private void EnableHotkeyTriggers(bool enabled) { - _hotkeyService?.StopNotify(_hotkeyGroupId, null); - _hotkeyGroupId = null; + if (enabled) + { + ReloadTriggers(); + } + else + { + UnloadTriggers(); + } } - LoadTriggers(); - } - private void LoadTriggers() - { - var id = CreateHotkeyList(out var list); - if (id != null && _hotkeyService != null) + private void ReloadTriggers() { - _hotkeyGroupId = id; - foreach (var hotkey in list) + if (_hotkeyGroupId != null) { - _hotkeyService.StartNotify(_hotkeyGroupId, hotkey.id, hotkey.hotkey, (groupId, hotkeyId, hotkey) => InvokeCommand(id, hotkeyId, hotkey)); + _hotkeyService?.StopNotify(_hotkeyGroupId, null); + _hotkeyGroupId = null; } + LoadTriggers(); } - } - private void UnloadTriggers() - { - if (_hotkeyGroupId != null && _hotkeyService != null) + private void LoadTriggers() { - _hotkeyService.StopNotify(_hotkeyGroupId, null); - _hotkeyGroupId = null; + var id = CreateHotkeyList(out var list); + if (id != null && _hotkeyService != null) + { + _hotkeyGroupId = id; + foreach (var hotkey in list) + { + _hotkeyService.StartNotify(_hotkeyGroupId, hotkey.id, hotkey.hotkey, (groupId, hotkeyId, hotkey) => InvokeCommand(id, hotkeyId, hotkey)); + } + } } - } - - private string? CreateHotkeyList(out IEnumerable hotkeyTriggers) - { - var satisfied = _commandSet?.Conditions?.IsSatisfied(); - var notSatisifed = satisfied != null && !satisfied.Value; - if (_commandSet == null || notSatisifed) + private void UnloadTriggers() { - hotkeyTriggers = Enumerable.Empty(); - return null; + if (_hotkeyGroupId != null && _hotkeyService != null) + { + _hotkeyService.StopNotify(_hotkeyGroupId, null); + _hotkeyGroupId = null; + } } - var list = new List(); - foreach (var command in _commandSet.Commands ?? Enumerable.Empty()) + private string? CreateHotkeyList(out IEnumerable hotkeyTriggers) { - if (command.Triggers == null) continue; - if (!command.IsSatisfied()) continue; + var satisfied = _commandSet?.Conditions?.IsSatisfied(); + var notSatisifed = satisfied != null && !satisfied.Value; - var triggers = command.Triggers.ToList(); - if (command.Expecting != null) + if (_commandSet == null || notSatisifed) { - triggers.AddRange(command.Expecting); + hotkeyTriggers = Enumerable.Empty(); + return null; } - foreach (var item in triggers) + var list = new List(); + foreach (var command in _commandSet.Commands ?? Enumerable.Empty()) { - var trigger = item as HotkeyTrigger; - if (trigger != null) + if (command.Triggers == null) continue; + if (!command.IsSatisfied()) continue; + + var triggers = command.Triggers.ToList(); + if (command.Expecting != null) + { + triggers.AddRange(command.Expecting); + } + + foreach (var item in triggers) { - foreach (var hotkey in trigger.Hotkeys) + var trigger = item as HotkeyTrigger; + if (trigger != null) { - var newHotkey = new Hotkey() { id = command.Id, hotkey = hotkey }; - list.Add(newHotkey); + foreach (var hotkey in trigger.Hotkeys) + { + var newHotkey = new Hotkey() { id = command.Id, hotkey = hotkey }; + list.Add(newHotkey); + } } } } - } - hotkeyTriggers = list; - return list.Count > 0 ? _commandSet.Id : null; - } + hotkeyTriggers = list; + return list.Count > 0 ? _commandSet.Id : null; + } - private void InvokeCommand(string groupId, string hotkeyId, string hotkey) - { - MR.DBG_TRACE_INFO($"--- INVOKING COMMAND: {hotkeyId}, {hotkey}"); + private void InvokeCommand(string groupId, string hotkeyId, string hotkey) + { + MR.DBG_TRACE_INFO($"--- INVOKING COMMAND: {hotkeyId}, {hotkey}"); - var command = GetCommand(hotkeyId); - _commandExecutionService?.Execute(command, context => RegisterResolver(context, hotkey)); + var command = GetCommand(hotkeyId); + _commandExecutionService?.Execute(command, context => RegisterResolver(context, hotkey)); - MR.DBG_TRACE_INFO($"- INVOKING COMMAND: {hotkeyId} ... Done!\n"); - } + MR.DBG_TRACE_INFO($"- INVOKING COMMAND: {hotkeyId} ... Done!\n"); + } - private ICommand? GetCommand(string hotkeyId) - { - return _commandSet?.Commands?.Where(command => command.Id == hotkeyId)?.First(); - } + private ICommand? GetCommand(string hotkeyId) + { + return _commandSet?.Commands?.Where(command => command.Id == hotkeyId)?.First(); + } - private static void RegisterResolver(IExecutionContext context, string hotkey) - { - context.RegisterResolver( - nameof(HotkeyTriggerCommandSetExtension), - name => ResolveContext(hotkey, name)); - } + private static void RegisterResolver(IExecutionContext context, string hotkey) + { + context.RegisterResolver( + nameof(HotkeyTriggerCommandSetExtension), + name => ResolveContext(hotkey, name)); + } - private static object? ResolveContext(string hotkey, string name) - { - if (name == "context.keys") return string.Join('\n', new string[] { + private static object? ResolveContext(string hotkey, string name) + { + if (name == "context.keys") return string.Join('\n', new string[] { "trigger.type", "hotkey.trigger" }); - if (name == "trigger.type") return "hotkey"; - if (name == "hotkey.trigger") return hotkey; + if (name == "trigger.type") return "hotkey"; + if (name == "hotkey.trigger") return hotkey; - return null; - } + return null; + } - internal struct Hotkey - { - internal string id; - internal string hotkey; - } + internal struct Hotkey + { + internal string id; + internal string hotkey; + } - private ICommandSet? _commandSet; - private ICommandExecutionService? _commandExecutionService; + private ICommandSet? _commandSet; + private ICommandExecutionService? _commandExecutionService; - private IHotkeyService? _hotkeyService; - private string? _hotkeyGroupId; -} + private IHotkeyService? _hotkeyService; + private string? _hotkeyGroupId; + } +} \ No newline at end of file diff --git a/src/cs/Command/Triggers/HotkeyTriggerYamlParser.cs b/src/cs/Command/Triggers/HotkeyTriggerYamlParser.cs index 4d10df3c..714a6a89 100644 --- a/src/cs/Command/Triggers/HotkeyTriggerYamlParser.cs +++ b/src/cs/Command/Triggers/HotkeyTriggerYamlParser.cs @@ -1,34 +1,38 @@ -namespace macaroni; +using System; +using YamlDotNet.RepresentationModel; -internal class HotkeyTriggerYamlParser : YamlParserBase, ITriggerYamlParser +namespace macaroni { - public HotkeyTriggerYamlParser(ISystemContext context) : base(context) { } - - public string Kind { get { return "hotkey"; } } - - public ICommandTrigger Parse(string file, YamlMappingNode? trigger, YamlNode value, IParsedValueWarningChecker? warnings) + internal class HotkeyTriggerYamlParser : YamlParserBase, ITriggerYamlParser { - var scalar = value as YamlScalarNode; - if (scalar != null) return ParseScalar(file, trigger, scalar, warnings); + public HotkeyTriggerYamlParser(ISystemContext context) : base(context) { } - var sequence = value as YamlSequenceNode; - if (sequence != null) return ParseSequence(file, trigger, sequence, warnings); + public string Kind { get { return "hotkey"; } } - throw ExpectedSequenceOrStringValueException(file, Kind, value); - } + public ICommandTrigger Parse(string file, YamlMappingNode? trigger, YamlNode value, IParsedValueWarningChecker? warnings) + { + var scalar = value as YamlScalarNode; + if (scalar != null) return ParseScalar(file, trigger, scalar, warnings); - private ICommandTrigger ParseScalar(string file, YamlMappingNode? trigger, YamlScalarNode scalar, IParsedValueWarningChecker? warnings) - { - string hotkey = RequireScalarStringValueNotNullOrEmpty(file, Kind, scalar, warnings); - RequireNoUnexpectedMappingKeys(file, trigger, Kind, Array.Empty()); - return new HotkeyTrigger(hotkey) { Yaml = scalar, YamlFile = file }; - } + var sequence = value as YamlSequenceNode; + if (sequence != null) return ParseSequence(file, trigger, sequence, warnings); - private ICommandTrigger ParseSequence(string file, YamlMappingNode? mapping, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) - { - var hotkeys = RequireSequenceOfStringsNotNullOrEmpty(file, Kind, sequence, warnings); - RequireNoUnexpectedMappingKeys(file, mapping, Kind, Array.Empty()); - return new HotkeyTrigger(hotkeys) { Yaml = sequence, YamlFile = file }; - } + throw ExpectedSequenceOrStringValueException(file, Kind, value); + } + + private ICommandTrigger ParseScalar(string file, YamlMappingNode? trigger, YamlScalarNode scalar, IParsedValueWarningChecker? warnings) + { + string hotkey = RequireScalarStringValueNotNullOrEmpty(file, Kind, scalar, warnings); + RequireNoUnexpectedMappingKeys(file, trigger, Kind, Array.Empty()); + return new HotkeyTrigger(hotkey) { Yaml = scalar, YamlFile = file }; + } -} + private ICommandTrigger ParseSequence(string file, YamlMappingNode? mapping, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) + { + var hotkeys = RequireSequenceOfStringsNotNullOrEmpty(file, Kind, sequence, warnings); + RequireNoUnexpectedMappingKeys(file, mapping, Kind, Array.Empty()); + return new HotkeyTrigger(hotkeys) { Yaml = sequence, YamlFile = file }; + } + + } +} \ No newline at end of file diff --git a/src/cs/Command/Triggers/IntentTrigger.cs b/src/cs/Command/Triggers/IntentTrigger.cs index 8e5dfd90..4896d1b1 100644 --- a/src/cs/Command/Triggers/IntentTrigger.cs +++ b/src/cs/Command/Triggers/IntentTrigger.cs @@ -1,26 +1,29 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class IntentTrigger : IIntentTrigger, ILoadedFromYamlFile +namespace macaroni { - public IntentTrigger(string intentId, string? entityId) + internal class IntentTrigger : IIntentTrigger, ILoadedFromYamlFile { - IntentId = intentId; - EntityId = entityId; - } + public IntentTrigger(string intentId, string? entityId) + { + IntentId = intentId; + EntityId = entityId; + } - public string IntentId { get; set; } - public string? EntityId { get; set; } + public string IntentId { get; set; } + public string? EntityId { get; set; } - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) - { - YamlParent = parent; - } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public void Unload() - { + public void LoadComplete(object parent) + { + YamlParent = parent; + } + + public void Unload() + { + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Triggers/IntentTriggerCommandSetExtension.cs b/src/cs/Command/Triggers/IntentTriggerCommandSetExtension.cs index 9895fa0f..6eaae2e8 100644 --- a/src/cs/Command/Triggers/IntentTriggerCommandSetExtension.cs +++ b/src/cs/Command/Triggers/IntentTriggerCommandSetExtension.cs @@ -1,34 +1,49 @@ -using System.Linq; -using System.Text; +using System.Collections.Generic; +using System.Linq; using macaroni.DataTypes; -using Microsoft.CognitiveServices.Speech; -using Microsoft.CognitiveServices.Speech.Intent; +/* Unmerged change from project 'macaroni_core (net6.0-windows)' +Before: using static macaroni.HotkeyTriggerCommandSetExtension; +After: +using System.Linq; +using System.Text; +using static macaroni.HotkeyTriggerCommandSetExtension; +*/ -namespace macaroni; - -internal class IntentTriggerCommandSetExtension : ICommandSetExtension, INotifyCondition, INotifyYamlValues -{ - public void InitCommandSetExtension(ICommandSet commandSet) - { - _commandSet = commandSet; - _commandExecutionService = _commandSet?.GetParentOrService(); +/* Unmerged change from project 'macaroni_core (netstandard2.1)' +Before: +using static macaroni.HotkeyTriggerCommandSetExtension; +After: +using System.Linq; +using System.Text; +using static macaroni.HotkeyTriggerCommandSetExtension; +*/ - _recognizer = _commandSet?.GetParentOrService(); - _intentGroupId = _commandSet?.Id + "intents" ?? ""; - } - public void EnableExtension(bool enabled) +namespace macaroni +{ + internal class IntentTriggerCommandSetExtension : ICommandSetExtension, INotifyCondition, INotifyYamlValues { - if (enabled) + public void InitCommandSetExtension(ICommandSet commandSet) { - RegisterCallbacks(); + _commandSet = commandSet; + _commandExecutionService = _commandSet?.GetParentOrService(); + + _recognizer = _commandSet?.GetParentOrService(); + _intentGroupId = _commandSet?.Id + "intents" ?? ""; } - else + + public void EnableExtension(bool enabled) { - RemoveIntentCallbacks(); + if (enabled) + { + RegisterCallbacks(); + } + else + { + RemoveIntentCallbacks(); + } } - } public void ValueChanged(IYamlValue value) { @@ -44,121 +59,122 @@ public void ConditionChanged(ICondition condition) MR.DBG_TRACE_INFO($"IntentTriggerCommandSetExtension::ConditionChanged({condition.GetType().Name}) ... Done!"); } - private void RegisterCallbacks() - { - _recognizer?.RemoveIntentCallbackGroup(_intentGroupId); - - List intentTriggers = new List(); - - foreach (var command in _commandSet?.Commands ?? Enumerable.Empty()) + private void RegisterCallbacks() { - if (command.Triggers == null) continue; - if (!command.IsSatisfied()) continue; + _recognizer?.RemoveIntentCallbackGroup(_intentGroupId); - var triggers = command.Triggers.ToList(); + List intentTriggers = new List(); - if (command.Expecting != null) + foreach (var command in _commandSet?.Commands ?? Enumerable.Empty()) { - triggers.AddRange(command.Expecting); - } + if (command.Triggers == null) continue; + if (!command.IsSatisfied()) continue; - foreach (var trigger in triggers) - { - var intentTrigger = trigger as IIntentTrigger; - if (intentTrigger != null) + var triggers = command.Triggers.ToList(); + + if (command.Expecting != null) + { + triggers.AddRange(command.Expecting); + } + + foreach (var trigger in triggers) { - _recognizer?.RegisterIntentCallback(intentTrigger.IntentId, intentTrigger.EntityId, _intentGroupId, x => InvokeCommand(x)); + var intentTrigger = trigger as IIntentTrigger; + if (intentTrigger != null) + { + _recognizer?.RegisterIntentCallback(intentTrigger.IntentId, intentTrigger.EntityId, _intentGroupId, x => InvokeCommand(x)); + } } } } - } - private void RemoveIntentCallbacks() - { - _recognizer?.RemoveIntentCallbackGroup(_intentGroupId); - } + private void RemoveIntentCallbacks() + { + _recognizer?.RemoveIntentCallbackGroup(_intentGroupId); + } - private void InvokeCommand(IntentResult result) - { - MR.DBG_TRACE_INFO($"--- INVOKING COMMAND: {result.IntentId}"); + private void InvokeCommand(IntentResult result) + { + MR.DBG_TRACE_INFO($"--- INVOKING COMMAND: {result.IntentId}"); - var command = GetCommand(result); - _commandExecutionService?.Execute(command, context => RegisterResolver(context, result)); + var command = GetCommand(result); + _commandExecutionService?.Execute(command, context => RegisterResolver(context, result)); - MR.DBG_TRACE_INFO($"- INVOKING COMMAND: {result.IntentId} ... Done!\n"); - } + MR.DBG_TRACE_INFO($"- INVOKING COMMAND: {result.IntentId} ... Done!\n"); + } - private ICommand? GetCommand(IntentResult result) - { - return _commandSet?.Commands?.FirstOrDefault(command => + private ICommand? GetCommand(IntentResult result) { - return null != command?.Expecting?.FirstOrDefault(trigger => FindMatchingTrigger(result, trigger)) || - null != command?.Triggers?.FirstOrDefault(trigger => FindMatchingTrigger(result, trigger)); - }); - } + return _commandSet?.Commands?.FirstOrDefault(command => + { + return null != command?.Expecting?.FirstOrDefault(trigger => FindMatchingTrigger(result, trigger)) || + null != command?.Triggers?.FirstOrDefault(trigger => FindMatchingTrigger(result, trigger)); + }); + } - private static bool FindMatchingTrigger(IntentResult result, ICommandTrigger? trigger) - { - var intentTrigger = trigger as IIntentTrigger; + private static bool FindMatchingTrigger(IntentResult result, ICommandTrigger? trigger) + { + var intentTrigger = trigger as IIntentTrigger; - var intentOk = intentTrigger != null && intentTrigger.IntentId == result.IntentId; - if (!intentOk) return false; + var intentOk = intentTrigger != null && intentTrigger.IntentId == result.IntentId; + if (!intentOk) return false; - var entityOk = intentTrigger!.EntityId == null || result.Entities.ContainsKey(intentTrigger.EntityId); - if (!entityOk) return false; + var entityOk = intentTrigger!.EntityId == null || result.Entities.ContainsKey(intentTrigger.EntityId); + if (!entityOk) return false; - return true; - } + return true; + } - private void RegisterResolver(IExecutionContext context, IntentResult result) - { - context.RegisterResolver( - nameof(IntentTriggerCommandSetExtension), - name => ResolveContext(result, name)); - } + private void RegisterResolver(IExecutionContext context, IntentResult result) + { + context.RegisterResolver( + nameof(IntentTriggerCommandSetExtension), + name => ResolveContext(result, name)); + } - private object? ResolveContext(IntentResult result, string name) - { - if (name == "context.keys") return string.Join('\n', - new string[] { + private object? ResolveContext(IntentResult result, string name) + { + if (name == "context.keys") return string.Join('\n', + new string[] { "trigger.type", "intent.trigger", "result.intentId", "result.text" - } - .Concat(result.Entities.Keys) - .Concat(result.Entities.Keys - .Select(x => $"{x}.json") - .Where(x => TryGetCluEntityJson(result, x, out var json))) - ); + } + .Concat(result.Entities.Keys) + .Concat(result.Entities.Keys + .Select(x => $"{x}.json") + .Where(x => TryGetCluEntityJson(result, x, out var json))) + ); - if (name == "trigger.type") return "intent"; - if (name == "intent.trigger") return result.IntentId; - if (name == "result.intentId") return result.IntentId; - if (name == "result.text") return result.IntentRecognitionResult.Text; + if (name == "trigger.type") return "intent"; + if (name == "intent.trigger") return result.IntentId; + if (name == "result.intentId") return result.IntentId; + if (name == "result.text") return result.IntentRecognitionResult.Text; - if (result.Entities.ContainsKey(name)) return result.Entities[name]; - if (result.Entities.ContainsKey($"{name}*")) return result.Entities[$"{name}*"]; - if (name.EndsWith(".json") && TryGetCluEntityJson(result, name, out var json)) return json; + if (result.Entities.ContainsKey(name)) return result.Entities[name]; + if (result.Entities.ContainsKey($"{name}*")) return result.Entities[$"{name}*"]; + if (name.EndsWith(".json") && TryGetCluEntityJson(result, name, out var json)) return json; - var value = result.IntentRecognitionResult.Properties.GetProperty(name); - if (!string.IsNullOrEmpty(value)) return value; + var value = result.IntentRecognitionResult.Properties.GetProperty(name); + if (!string.IsNullOrEmpty(value)) return value; - return null; - } + return null; + } - private bool TryGetCluEntityJson(IntentResult result, string name, out string? json) - { - json = null; - var check = name.Substring(0, name.Length - ".json".Length); - return result.Entities.ContainsKey(check) && - result.EntitiesJson != null && - result.EntitiesJson.TryGetValue(check, out json); - } + private bool TryGetCluEntityJson(IntentResult result, string name, out string? json) + { + json = null; + var check = name.Substring(0, name.Length - ".json".Length); + return result.Entities.ContainsKey(check) && + result.EntitiesJson != null && + result.EntitiesJson.TryGetValue(check, out json); + } + + private ICommandSet? _commandSet; + private ICommandExecutionService? _commandExecutionService; - private ICommandSet? _commandSet; - private ICommandExecutionService? _commandExecutionService; - - private IIntentRecognizerService? _recognizer; - private string _intentGroupId = ""; -} + private IIntentRecognizerService? _recognizer; + private string _intentGroupId = ""; + } +} \ No newline at end of file diff --git a/src/cs/Command/Triggers/IntentTriggerYamlParser.cs b/src/cs/Command/Triggers/IntentTriggerYamlParser.cs index bfcf9580..8c047a60 100644 --- a/src/cs/Command/Triggers/IntentTriggerYamlParser.cs +++ b/src/cs/Command/Triggers/IntentTriggerYamlParser.cs @@ -1,35 +1,38 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class IntentTriggerYamlParser : YamlParserBase, ITriggerYamlParser +namespace macaroni { - public IntentTriggerYamlParser(ISystemContext context) : base(context) { } - - public string Kind { get { return "intent"; } } - - public ICommandTrigger Parse(string file, YamlMappingNode? trigger, YamlNode value, IParsedValueWarningChecker? warnings) + internal class IntentTriggerYamlParser : YamlParserBase, ITriggerYamlParser { - var scalar = value as YamlScalarNode; - if (scalar != null) return ParseScalar(file, trigger, scalar, warnings); + public IntentTriggerYamlParser(ISystemContext context) : base(context) { } - var mapping = value as YamlMappingNode; - if (mapping != null) return ParseMapping(file, mapping, null, warnings); + public string Kind { get { return "intent"; } } - throw ExpectedMappingOrStringValueException(file, Kind, value); - } + public ICommandTrigger Parse(string file, YamlMappingNode? trigger, YamlNode value, IParsedValueWarningChecker? warnings) + { + var scalar = value as YamlScalarNode; + if (scalar != null) return ParseScalar(file, trigger, scalar, warnings); - private ICommandTrigger ParseScalar(string file, YamlMappingNode? trigger, YamlScalarNode scalar, IParsedValueWarningChecker? warnings) - { - string intentId = RequireScalarStringValueNotNullOrEmpty(file, Kind, scalar, warnings); - return trigger == null - ? new IntentTrigger(intentId, null) { Yaml = scalar, YamlFile = file } - : ParseMapping(file, trigger, intentId, warnings); - } + var mapping = value as YamlMappingNode; + if (mapping != null) return ParseMapping(file, mapping, null, warnings); - private ICommandTrigger ParseMapping(string file, YamlMappingNode mapping, string? scalar, IParsedValueWarningChecker? warnings) - { - var intentId = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "id", warnings); - var entityId = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "entity", warnings); + throw ExpectedMappingOrStringValueException(file, Kind, value); + } + + private ICommandTrigger ParseScalar(string file, YamlMappingNode? trigger, YamlScalarNode scalar, IParsedValueWarningChecker? warnings) + { + string intentId = RequireScalarStringValueNotNullOrEmpty(file, Kind, scalar, warnings); + return trigger == null + ? new IntentTrigger(intentId, null) { Yaml = scalar, YamlFile = file } + : ParseMapping(file, trigger, intentId, warnings); + } + + private ICommandTrigger ParseMapping(string file, YamlMappingNode mapping, string? scalar, IParsedValueWarningChecker? warnings) + { + var intentId = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "id", warnings); + var entityId = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "entity", warnings); - return new IntentTrigger(intentId, entityId) { Yaml = mapping, YamlFile = file }; + return new IntentTrigger(intentId, entityId) { Yaml = mapping, YamlFile = file }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Triggers/MessageTrigger.cs b/src/cs/Command/Triggers/MessageTrigger.cs index 20a40bc0..0f999e4f 100644 --- a/src/cs/Command/Triggers/MessageTrigger.cs +++ b/src/cs/Command/Triggers/MessageTrigger.cs @@ -1,27 +1,30 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class MessageTrigger : IMessageTrigger, ILoadedFromYamlFile +namespace macaroni { - public MessageTrigger(string name, string? value) + internal class MessageTrigger : IMessageTrigger, ILoadedFromYamlFile { - Name = name; - Value = value; - } + public MessageTrigger(string name, string? value) + { + Name = name; + Value = value; + } - public string Name { get; set; } - public string? Value { get; set; } - public string? Scope { get; set; } + public string Name { get; set; } + public string? Value { get; set; } + public string? Scope { get; set; } - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public void LoadComplete(object parent) - { - YamlParent = parent; - } + public void LoadComplete(object parent) + { + YamlParent = parent; + } - public void Unload() - { + public void Unload() + { + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Triggers/MessageTriggerCommandSetExtension.cs b/src/cs/Command/Triggers/MessageTriggerCommandSetExtension.cs index b61bc7b5..26caa98a 100644 --- a/src/cs/Command/Triggers/MessageTriggerCommandSetExtension.cs +++ b/src/cs/Command/Triggers/MessageTriggerCommandSetExtension.cs @@ -1,176 +1,178 @@ -using Microsoft.CognitiveServices.Speech.Intent; +using System.Collections.Generic; +using System.Linq; -namespace macaroni; - -internal class MessageTriggerCommandSetExtension : ICommandSetExtension, INotifyCondition, INotifyYamlValues +namespace macaroni { - public void InitCommandSetExtension(ICommandSet commandSet) - { - _commandSet = commandSet; - _commandExecutionService = _commandSet?.GetParentOrService(); - _messageService = _commandSet?.GetParentOrService(); - } - - public void EnableExtension(bool enabled) - { - EnableMessageTriggers(enabled); - } - - public void ValueChanged(IYamlValue value) + internal class MessageTriggerCommandSetExtension : ICommandSetExtension, INotifyCondition, INotifyYamlValues { - MR.DBG_TRACE_INFO($"MessageTriggerCommandSetExtension::ValueChanged({value.GetType().Name})"); - ReloadTriggers(); - MR.DBG_TRACE_INFO($"MessageTriggerCommandSetExtension::ValueChanged({value.GetType().Name}) ... Done!"); - } + public void InitCommandSetExtension(ICommandSet commandSet) + { + _commandSet = commandSet; + _commandExecutionService = _commandSet?.GetParentOrService(); + _messageService = _commandSet?.GetParentOrService(); + } - public void ConditionChanged(ICondition condition) - { - MR.DBG_TRACE_INFO($"MessageTriggerCommandSetExtension::ConditionChanged({condition.GetType().Name})"); - ReloadTriggers(); - MR.DBG_TRACE_INFO($"MessageTriggerCommandSetExtension::ConditionChanged({condition.GetType().Name}) ... Done!"); - } + public void EnableExtension(bool enabled) + { + EnableMessageTriggers(enabled); + } - private void EnableMessageTriggers(bool enabled) - { - if (enabled) + public void ValueChanged(IYamlValue value) { + MR.DBG_TRACE_INFO($"MessageTriggerCommandSetExtension::ValueChanged({value.GetType().Name})"); ReloadTriggers(); + MR.DBG_TRACE_INFO($"MessageTriggerCommandSetExtension::ValueChanged({value.GetType().Name}) ... Done!"); } - else + + public void ConditionChanged(ICondition condition) { - UnloadTriggers(); + MR.DBG_TRACE_INFO($"MessageTriggerCommandSetExtension::ConditionChanged({condition.GetType().Name})"); + ReloadTriggers(); + MR.DBG_TRACE_INFO($"MessageTriggerCommandSetExtension::ConditionChanged({condition.GetType().Name}) ... Done!"); } - } - private void ReloadTriggers() - { - if (_commandSetId != null) + private void EnableMessageTriggers(bool enabled) { - _messageService?.StopNotify(_commandSetId, null); - _commandSetId = null; + if (enabled) + { + ReloadTriggers(); + } + else + { + UnloadTriggers(); + } } - LoadTriggers(); - } - private void LoadTriggers() - { - var id = CreateMessageItemList(out var list); - if (id != null && _messageService != null) + private void ReloadTriggers() { - _commandSetId = id; - foreach (var message in list) + if (_commandSetId != null) { - _messageService.StartNotify(id, GetMessageItemId(message), message.name, message.value, (commandSetId, messageItemId, name, value) => InvokeCommand(commandSetId, CommandIdFromMessageItemId(messageItemId), name, value)); + _messageService?.StopNotify(_commandSetId, null); + _commandSetId = null; } + LoadTriggers(); } - } - private void UnloadTriggers() - { - if (_commandSetId != null && _messageService != null) + private void LoadTriggers() { - _messageService.StopNotify(_commandSetId, null); - _commandSetId = null; + var id = CreateMessageItemList(out var list); + if (id != null && _messageService != null) + { + _commandSetId = id; + foreach (var message in list) + { + _messageService.StartNotify(id, GetMessageItemId(message), message.name, message.value, (commandSetId, messageItemId, name, value) => InvokeCommand(commandSetId, CommandIdFromMessageItemId(messageItemId), name, value)); + } + } } - } - private static string CommandIdFromMessageItemId(string messageItemId) - { - return messageItemId.Before('|'); - } - - private static string GetMessageItemId(MessageItem message) - { - return $"{message.commandId}|{message.name}|{message.value}"; - } + private void UnloadTriggers() + { + if (_commandSetId != null && _messageService != null) + { + _messageService.StopNotify(_commandSetId, null); + _commandSetId = null; + } + } - private string? CreateMessageItemList(out IEnumerable messageTriggers) - { - var satisfied = _commandSet?.Conditions?.IsSatisfied(); - var notSatisifed = satisfied != null && !satisfied.Value; + private static string CommandIdFromMessageItemId(string messageItemId) + { + return messageItemId.Before('|'); + } - if (_commandSet == null || notSatisifed) + private static string GetMessageItemId(MessageItem message) { - messageTriggers = Enumerable.Empty(); - return null; + return $"{message.commandId}|{message.name}|{message.value}"; } - var list = new List(); - foreach (var command in _commandSet.Commands ?? Enumerable.Empty()) + private string? CreateMessageItemList(out IEnumerable messageTriggers) { - if (command.Triggers == null) continue; - if (!command.IsSatisfied()) continue; + var satisfied = _commandSet?.Conditions?.IsSatisfied(); + var notSatisifed = satisfied != null && !satisfied.Value; - var triggers = command.Triggers.ToList(); - if (command.Expecting != null) + if (_commandSet == null || notSatisifed) { - triggers.AddRange(command.Expecting); + messageTriggers = Enumerable.Empty(); + return null; } - foreach (var item in triggers) + var list = new List(); + foreach (var command in _commandSet.Commands ?? Enumerable.Empty()) { - var trigger = item as MessageTrigger; - if (trigger != null) + if (command.Triggers == null) continue; + if (!command.IsSatisfied()) continue; + + var triggers = command.Triggers.ToList(); + if (command.Expecting != null) { - var message = new MessageItem() { commandId = command.Id, name = trigger.Name, value = trigger.Value }; - list.Add(message); + triggers.AddRange(command.Expecting); + } + + foreach (var item in triggers) + { + var trigger = item as MessageTrigger; + if (trigger != null) + { + var message = new MessageItem() { commandId = command.Id, name = trigger.Name, value = trigger.Value }; + list.Add(message); + } } } - } - messageTriggers = list; - return list.Count > 0 ? _commandSet.Id : null; - } + messageTriggers = list; + return list.Count > 0 ? _commandSet.Id : null; + } - private void InvokeCommand(string id, string messageId, string name, string? value) - { - MR.DBG_TRACE_INFO($"--- INVOKING COMMAND: {messageId}"); + private void InvokeCommand(string id, string messageId, string name, string? value) + { + MR.DBG_TRACE_INFO($"--- INVOKING COMMAND: {messageId}"); - var command = GetCommand(messageId); - _commandExecutionService?.Execute(command, context => RegisterResolver(context, name, value)); + var command = GetCommand(messageId); + _commandExecutionService?.Execute(command, context => RegisterResolver(context, name, value)); - MR.DBG_TRACE_INFO($"- INVOKING COMMAND: {messageId} ... Done!\n"); - } + MR.DBG_TRACE_INFO($"- INVOKING COMMAND: {messageId} ... Done!\n"); + } - private ICommand? GetCommand(string messageId) - { - return _commandSet?.Commands?.Where(command => command.Id == messageId)?.First(); - } + private ICommand? GetCommand(string messageId) + { + return _commandSet?.Commands?.Where(command => command.Id == messageId)?.First(); + } - private static void RegisterResolver(IExecutionContext context, string messageName, string? messageValue) - { - context.RegisterResolver( - nameof(MessageTriggerCommandSetExtension), - name => ResolveContext(messageName, messageValue, name)); - } + private static void RegisterResolver(IExecutionContext context, string messageName, string? messageValue) + { + context.RegisterResolver( + nameof(MessageTriggerCommandSetExtension), + name => ResolveContext(messageName, messageValue, name)); + } - private static object? ResolveContext(string messageName, string? messageValue, string name) - { - if (name == "context.keys") return string.Join('\n', new string[] { + private static object? ResolveContext(string messageName, string? messageValue, string name) + { + if (name == "context.keys") return string.Join('\n', new string[] { "trigger.type", "message.trigger", "message.value", "message.name" }); - if (name == "trigger.type") return "message"; - if (name == "message.trigger") return messageValue; - if (name == "message.value") return messageValue; - if (name == "message.name") return messageName; + if (name == "trigger.type") return "message"; + if (name == "message.trigger") return messageValue; + if (name == "message.value") return messageValue; + if (name == "message.name") return messageName; - return null; - } + return null; + } - internal struct MessageItem - { - internal string commandId; - internal string name; - internal string? value; - } + internal struct MessageItem + { + internal string commandId; + internal string name; + internal string? value; + } - private ICommandSet? _commandSet; - private ICommandExecutionService? _commandExecutionService; + private ICommandSet? _commandSet; + private ICommandExecutionService? _commandExecutionService; - private IBroadcastMessageService? _messageService; - private string? _commandSetId; + private IBroadcastMessageService? _messageService; + private string? _commandSetId; + } } diff --git a/src/cs/Command/Triggers/MessageTriggerYamlParser.cs b/src/cs/Command/Triggers/MessageTriggerYamlParser.cs index 55926c8c..5c77180a 100644 --- a/src/cs/Command/Triggers/MessageTriggerYamlParser.cs +++ b/src/cs/Command/Triggers/MessageTriggerYamlParser.cs @@ -1,36 +1,39 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class MessageTriggerYamlParser : YamlParserBase, ITriggerYamlParser +namespace macaroni { - public MessageTriggerYamlParser(ISystemContext context) : base(context) { } - - public string Kind { get { return "message"; } } - - public ICommandTrigger Parse(string file, YamlMappingNode? trigger, YamlNode value, IParsedValueWarningChecker? warnings) + internal class MessageTriggerYamlParser : YamlParserBase, ITriggerYamlParser { - var scalar = value as YamlScalarNode; - if (scalar != null) return ParseScalar(file, trigger, scalar, warnings); + public MessageTriggerYamlParser(ISystemContext context) : base(context) { } - var mapping = value as YamlMappingNode; - if (mapping != null) return ParseMapping(file, mapping, null, warnings); + public string Kind { get { return "message"; } } - throw ExpectedMappingOrStringValueException(file, Kind, value); - } + public ICommandTrigger Parse(string file, YamlMappingNode? trigger, YamlNode value, IParsedValueWarningChecker? warnings) + { + var scalar = value as YamlScalarNode; + if (scalar != null) return ParseScalar(file, trigger, scalar, warnings); - private ICommandTrigger ParseScalar(string file, YamlMappingNode? trigger, YamlScalarNode scalar, IParsedValueWarningChecker? warnings) - { - string name = RequireScalarStringValueNotNullOrEmpty(file, Kind, scalar, warnings); - return trigger == null - ? new MessageTrigger(name, null) { Yaml = scalar, YamlFile = file } - : ParseMapping(file, trigger, name, warnings); - } + var mapping = value as YamlMappingNode; + if (mapping != null) return ParseMapping(file, mapping, null, warnings); - private ICommandTrigger ParseMapping(string file, YamlMappingNode mapping, string? scalar, IParsedValueWarningChecker? warnings) - { - var name = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "name", warnings); - var value = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "value", warnings); - var scope = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "scope", warnings); + throw ExpectedMappingOrStringValueException(file, Kind, value); + } + + private ICommandTrigger ParseScalar(string file, YamlMappingNode? trigger, YamlScalarNode scalar, IParsedValueWarningChecker? warnings) + { + string name = RequireScalarStringValueNotNullOrEmpty(file, Kind, scalar, warnings); + return trigger == null + ? new MessageTrigger(name, null) { Yaml = scalar, YamlFile = file } + : ParseMapping(file, trigger, name, warnings); + } + + private ICommandTrigger ParseMapping(string file, YamlMappingNode mapping, string? scalar, IParsedValueWarningChecker? warnings) + { + var name = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "name", warnings); + var value = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "value", warnings); + var scope = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "scope", warnings); - return new MessageTrigger(name, value) { Scope = scope, Yaml = mapping, YamlFile = file }; + return new MessageTrigger(name, value) { Scope = scope, Yaml = mapping, YamlFile = file }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Triggers/NuggetTrigger.cs b/src/cs/Command/Triggers/NuggetTrigger.cs index e0f431ab..7ad40659 100644 --- a/src/cs/Command/Triggers/NuggetTrigger.cs +++ b/src/cs/Command/Triggers/NuggetTrigger.cs @@ -1,26 +1,29 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class NuggetTrigger : INuggetTrigger, ILoadedFromYamlFile +namespace macaroni { - public NuggetTrigger(string name, string? parameter) + internal class NuggetTrigger : INuggetTrigger, ILoadedFromYamlFile { - Name = name; - Parameter = parameter; - } + public NuggetTrigger(string name, string? parameter) + { + Name = name; + Parameter = parameter; + } - public string Name { get; set; } - public string? Parameter { get; set; } + public string Name { get; set; } + public string? Parameter { get; set; } - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public void LoadComplete(object parent) - { - YamlParent = parent; - } + public void LoadComplete(object parent) + { + YamlParent = parent; + } - public void Unload() - { + public void Unload() + { + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Triggers/NuggetTriggerCommandSetExtension.cs b/src/cs/Command/Triggers/NuggetTriggerCommandSetExtension.cs index 9f8ab334..a49301cd 100644 --- a/src/cs/Command/Triggers/NuggetTriggerCommandSetExtension.cs +++ b/src/cs/Command/Triggers/NuggetTriggerCommandSetExtension.cs @@ -1,210 +1,214 @@ -namespace macaroni; +using System.Collections.Generic; +using System.Linq; -internal class NuggetTriggerCommandSetExtension : ICommandSetExtension, INotifyCondition, INotifyYamlValues +namespace macaroni { - public void InitCommandSetExtension(ICommandSet commandSet) + internal class NuggetTriggerCommandSetExtension : ICommandSetExtension, INotifyCondition, INotifyYamlValues { - _commandSet = commandSet; - _commandExecutionService = _commandSet?.GetParentOrService(); - _nuggetExecutionService = _commandSet?.GetParentOrService(); - } - - public void EnableExtension(bool enabled) - { - EnableNuggets(enabled); - EnableNuggetTriggers(enabled); - } - - public void ValueChanged(IYamlValue value) - { - MR.DBG_TRACE_INFO($"NuggetTriggerCommandSetExtension::ValueChanged({value.GetType().Name})"); - ReloadTriggers(); - MR.DBG_TRACE_INFO($"NuggetTriggerCommandSetExtension::ValueChanged({value.GetType().Name}) ... Done!"); - } + public void InitCommandSetExtension(ICommandSet commandSet) + { + _commandSet = commandSet; + _commandExecutionService = _commandSet?.GetParentOrService(); + _nuggetExecutionService = _commandSet?.GetParentOrService(); + } - public void ConditionChanged(ICondition condition) - { - MR.DBG_TRACE_INFO($"NuggetTriggerCommandSetExtension::ConditionChanged({condition.GetType().Name})"); - ReloadTriggers(); - MR.DBG_TRACE_INFO($"NuggetTriggerCommandSetExtension::ConditionChanged({condition.GetType().Name}) ... Done!"); - } + public void EnableExtension(bool enabled) + { + EnableNuggets(enabled); + EnableNuggetTriggers(enabled); + } - private void EnableNuggets(bool enabled) - { - if (enabled) + public void ValueChanged(IYamlValue value) { - RegisterNuggets(); + MR.DBG_TRACE_INFO($"NuggetTriggerCommandSetExtension::ValueChanged({value.GetType().Name})"); + ReloadTriggers(); + MR.DBG_TRACE_INFO($"NuggetTriggerCommandSetExtension::ValueChanged({value.GetType().Name}) ... Done!"); } - else + + public void ConditionChanged(ICondition condition) { - UnRegisterNuggets(); + MR.DBG_TRACE_INFO($"NuggetTriggerCommandSetExtension::ConditionChanged({condition.GetType().Name})"); + ReloadTriggers(); + MR.DBG_TRACE_INFO($"NuggetTriggerCommandSetExtension::ConditionChanged({condition.GetType().Name}) ... Done!"); } - } - private void RegisterNuggets() - { - var id = _commandSet?.Id; - if (id != null) + private void EnableNuggets(bool enabled) { - var nuggets = _commandSet?.Nuggets; - if (nuggets?.Count() > 0) + if (enabled) + { + RegisterNuggets(); + } + else { - _nuggetExecutionService?.RegisterNuggets(id, nuggets); + UnRegisterNuggets(); } } - } - private void UnRegisterNuggets() - { - var id = _commandSet?.Id; - if (id != null) + private void RegisterNuggets() { - _nuggetExecutionService?.UnRegisterNuggets(id); + var id = _commandSet?.Id; + if (id != null) + { + var nuggets = _commandSet?.Nuggets; + if (nuggets?.Count() > 0) + { + _nuggetExecutionService?.RegisterNuggets(id, nuggets); + } + } } - } - private void EnableNuggetTriggers(bool enabled) - { - if (enabled) + + private void UnRegisterNuggets() { - ReloadTriggers(); + var id = _commandSet?.Id; + if (id != null) + { + _nuggetExecutionService?.UnRegisterNuggets(id); + } } - else + private void EnableNuggetTriggers(bool enabled) { - UnloadTriggers(); + if (enabled) + { + ReloadTriggers(); + } + else + { + UnloadTriggers(); + } } - } - private void ReloadTriggers() - { - if (_commandSetId != null) + private void ReloadTriggers() { - _nuggetExecutionService?.StopNotify(_commandSetId, null); - _commandSetId = null; + if (_commandSetId != null) + { + _nuggetExecutionService?.StopNotify(_commandSetId, null); + _commandSetId = null; + } + LoadTriggers(); } - LoadTriggers(); - } - private void LoadTriggers() - { - var commandSetId = CreateTriggerItemList(out var list); - if (commandSetId != null && _nuggetExecutionService != null) + private void LoadTriggers() { - _commandSetId = commandSetId; - foreach (var trigger in list) + var commandSetId = CreateTriggerItemList(out var list); + if (commandSetId != null && _nuggetExecutionService != null) { - _nuggetExecutionService.StartNotify(commandSetId, GetTriggerItemId(trigger), trigger.name, trigger.parameter, (commandSetId, triggerItemId, name, parameter, context) => InvokeCommand(commandSetId, CommandIdFromTriggerItemId(triggerItemId), name, parameter, context)); + _commandSetId = commandSetId; + foreach (var trigger in list) + { + _nuggetExecutionService.StartNotify(commandSetId, GetTriggerItemId(trigger), trigger.name, trigger.parameter, (commandSetId, triggerItemId, name, parameter, context) => InvokeCommand(commandSetId, CommandIdFromTriggerItemId(triggerItemId), name, parameter, context)); + } } } - } - private void UnloadTriggers() - { - if (_commandSetId != null && _nuggetExecutionService != null) + private void UnloadTriggers() { - _nuggetExecutionService.StopNotify(_commandSetId, null); - _commandSetId = null; + if (_commandSetId != null && _nuggetExecutionService != null) + { + _nuggetExecutionService.StopNotify(_commandSetId, null); + _commandSetId = null; + } } - } - - private static string CommandIdFromTriggerItemId(string triggerItemId) - { - return triggerItemId.Before('|'); - } - - private static string GetTriggerItemId(TriggerItem trigger) - { - return $"{trigger.commandId}|{trigger.name}|{trigger.parameter}"; - } - private string? CreateTriggerItemList(out IEnumerable nuggetTriggers) - { - var satisfied = _commandSet?.Conditions?.IsSatisfied(); - var notSatisfied = satisfied != null && !satisfied.Value; + private static string CommandIdFromTriggerItemId(string triggerItemId) + { + return triggerItemId.Before('|'); + } - if (_commandSet == null || notSatisfied) + private static string GetTriggerItemId(TriggerItem trigger) { - nuggetTriggers = Enumerable.Empty(); - return null; + return $"{trigger.commandId}|{trigger.name}|{trigger.parameter}"; } - var list = new List(); - foreach (var command in _commandSet.Commands ?? Enumerable.Empty()) + private string? CreateTriggerItemList(out IEnumerable nuggetTriggers) { - if (command.Triggers == null) continue; - if (!command.IsSatisfied()) continue; + var satisfied = _commandSet?.Conditions?.IsSatisfied(); + var notSatisfied = satisfied != null && !satisfied.Value; - var triggers = command.Triggers.ToList(); - if (command.Expecting != null) + if (_commandSet == null || notSatisfied) { - triggers.AddRange(command.Expecting); + nuggetTriggers = Enumerable.Empty(); + return null; } - foreach (var item in triggers) + var list = new List(); + foreach (var command in _commandSet.Commands ?? Enumerable.Empty()) { - var nuggetTrigger = item as NuggetTrigger; - if (nuggetTrigger != null) + if (command.Triggers == null) continue; + if (!command.IsSatisfied()) continue; + + var triggers = command.Triggers.ToList(); + if (command.Expecting != null) { - var triggerItem = new TriggerItem() { commandId = command.Id, name = nuggetTrigger.Name, parameter = nuggetTrigger.Parameter }; - list.Add(triggerItem); + triggers.AddRange(command.Expecting); + } + + foreach (var item in triggers) + { + var nuggetTrigger = item as NuggetTrigger; + if (nuggetTrigger != null) + { + var triggerItem = new TriggerItem() { commandId = command.Id, name = nuggetTrigger.Name, parameter = nuggetTrigger.Parameter }; + list.Add(triggerItem); + } } } - } - nuggetTriggers = list; - return list.Count > 0 ? _commandSet.Id : null; - } + nuggetTriggers = list; + return list.Count > 0 ? _commandSet.Id : null; + } - private void InvokeCommand(string id, string commandId, string name, string? parameter, IResolutionContext nuggetChainContext) - { - MR.DBG_TRACE_INFO($"--- INVOKING COMMAND: {commandId}"); + private void InvokeCommand(string id, string commandId, string name, string? parameter, IResolutionContext nuggetChainContext) + { + MR.DBG_TRACE_INFO($"--- INVOKING COMMAND: {commandId}"); - var command = GetCommand(commandId); - _commandExecutionService?.Execute(command, context => RegisterResolver(context, name, parameter, nuggetChainContext)); + var command = GetCommand(commandId); + _commandExecutionService?.Execute(command, context => RegisterResolver(context, name, parameter, nuggetChainContext)); - MR.DBG_TRACE_INFO($"- INVOKING COMMAND: {commandId} ... Done!\n"); - } + MR.DBG_TRACE_INFO($"- INVOKING COMMAND: {commandId} ... Done!\n"); + } - private ICommand? GetCommand(string triggerId) - { - return _commandSet?.Commands?.Where(command => command.Id == triggerId)?.First(); - } + private ICommand? GetCommand(string triggerId) + { + return _commandSet?.Commands?.Where(command => command.Id == triggerId)?.First(); + } - private static void RegisterResolver(IExecutionContext context, string nuggetName, string? nuggetParameter, IResolutionContext nuggetChainContext) - { - context.RegisterResolver( - nameof(NuggetTriggerCommandSetExtension), - name => ResolveContext(nuggetName, nuggetParameter, name, nuggetChainContext)); - } + private static void RegisterResolver(IExecutionContext context, string nuggetName, string? nuggetParameter, IResolutionContext nuggetChainContext) + { + context.RegisterResolver( + nameof(NuggetTriggerCommandSetExtension), + name => ResolveContext(nuggetName, nuggetParameter, name, nuggetChainContext)); + } - private static object? ResolveContext(string nuggetName, string? nuggetParameter, string name, IResolutionContext nuggetChainContext) - { - if (name == "context.keys") return string.Join('\n', - new string[] { + private static object? ResolveContext(string nuggetName, string? nuggetParameter, string name, IResolutionContext nuggetChainContext) + { + if (name == "context.keys") return string.Join('\n', + new string[] { "trigger.type", "nugget.trigger", "nugget.parameter", "nugget.name" - } - .Concat((nuggetChainContext.Get("context.keys", "") as string)?.Split('\n') ?? Enumerable.Empty())); + } + .Concat((nuggetChainContext.Get("context.keys", "") as string)?.Split('\n') ?? Enumerable.Empty())); - if (name == "trigger.type") return "nugget"; - if (name == "nugget.trigger") return nuggetName; - if (name == "nugget.parameter") return nuggetParameter; - if (name == "nugget.name") return nuggetName; + if (name == "trigger.type") return "nugget"; + if (name == "nugget.trigger") return nuggetName; + if (name == "nugget.parameter") return nuggetParameter; + if (name == "nugget.name") return nuggetName; - return nuggetChainContext.Get(name, null); - } + return nuggetChainContext.Get(name, null); + } - internal struct TriggerItem - { - internal string commandId; - internal string name; - internal string? parameter; - } + internal struct TriggerItem + { + internal string commandId; + internal string name; + internal string? parameter; + } - private ICommandSet? _commandSet; - private ICommandExecutionService? _commandExecutionService; + private ICommandSet? _commandSet; + private ICommandExecutionService? _commandExecutionService; - private INuggetExecutionService? _nuggetExecutionService; - private string? _commandSetId; -} + private INuggetExecutionService? _nuggetExecutionService; + private string? _commandSetId; + } +} \ No newline at end of file diff --git a/src/cs/Command/Triggers/NuggetTriggerYamlParser.cs b/src/cs/Command/Triggers/NuggetTriggerYamlParser.cs index 3e2e05f1..8d9f1dd0 100644 --- a/src/cs/Command/Triggers/NuggetTriggerYamlParser.cs +++ b/src/cs/Command/Triggers/NuggetTriggerYamlParser.cs @@ -1,40 +1,43 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class NuggetTriggerYamlParser : YamlParserBase, ITriggerYamlParser +namespace macaroni { - public NuggetTriggerYamlParser(ISystemContext context) : base(context) { } - - public string Kind { get { return "nugget"; } } - - public ICommandTrigger Parse(string file, YamlMappingNode? trigger, YamlNode value, IParsedValueWarningChecker? warnings) + internal class NuggetTriggerYamlParser : YamlParserBase, ITriggerYamlParser { - var scalar = value as YamlScalarNode; - if (scalar != null) return ParseScalar(file, trigger, scalar, warnings); + public NuggetTriggerYamlParser(ISystemContext context) : base(context) { } - var mapping = value as YamlMappingNode; - if (mapping != null) return ParseMapping(file, mapping, null, warnings); + public string Kind { get { return "nugget"; } } - throw ExpectedMappingOrStringValueException(file, Kind, value); - } + public ICommandTrigger Parse(string file, YamlMappingNode? trigger, YamlNode value, IParsedValueWarningChecker? warnings) + { + var scalar = value as YamlScalarNode; + if (scalar != null) return ParseScalar(file, trigger, scalar, warnings); - private ICommandTrigger ParseScalar(string file, YamlMappingNode? trigger, YamlScalarNode scalar, IParsedValueWarningChecker? warnings) - { - string name = RequireScalarStringValueNotNullOrEmpty(file, Kind, scalar, warnings); - return trigger == null - ? new NuggetTrigger(name, null) { Yaml = scalar, YamlFile = file } - : ParseMapping(file, trigger, name, warnings); - } + var mapping = value as YamlMappingNode; + if (mapping != null) return ParseMapping(file, mapping, null, warnings); - private ICommandTrigger ParseMapping(string file, YamlMappingNode mapping, string? scalar, IParsedValueWarningChecker? warnings) - { - var name = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "name", warnings); - var parameter = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "parameter", warnings); + throw ExpectedMappingOrStringValueException(file, Kind, value); + } + + private ICommandTrigger ParseScalar(string file, YamlMappingNode? trigger, YamlScalarNode scalar, IParsedValueWarningChecker? warnings) + { + string name = RequireScalarStringValueNotNullOrEmpty(file, Kind, scalar, warnings); + return trigger == null + ? new NuggetTrigger(name, null) { Yaml = scalar, YamlFile = file } + : ParseMapping(file, trigger, name, warnings); + } + + private ICommandTrigger ParseMapping(string file, YamlMappingNode mapping, string? scalar, IParsedValueWarningChecker? warnings) + { + var name = scalar ?? RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "name", warnings); + var parameter = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "parameter", warnings); - var allowed = scalar == null - ? new[] { "parameter", "name" } - : new[] { "parameter" }; - RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); + var allowed = scalar == null + ? new[] { "parameter", "name" } + : new[] { "parameter" }; + RequireNoUnexpectedMappingKeys(file, mapping, Kind, allowed); - return new NuggetTrigger(name, parameter) { Yaml = mapping, YamlFile = file }; + return new NuggetTrigger(name, parameter) { Yaml = mapping, YamlFile = file }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Triggers/PhraseTrigger.cs b/src/cs/Command/Triggers/PhraseTrigger.cs index a82f6dfa..eca2996a 100644 --- a/src/cs/Command/Triggers/PhraseTrigger.cs +++ b/src/cs/Command/Triggers/PhraseTrigger.cs @@ -1,28 +1,32 @@ -namespace macaroni; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class PhraseTrigger : IPhraseTrigger, ILoadedFromYamlFile +namespace macaroni { - public PhraseTrigger(string phrase) : this(new [] { phrase }) + internal class PhraseTrigger : IPhraseTrigger, ILoadedFromYamlFile { - } + public PhraseTrigger(string phrase) : this(new[] { phrase }) + { + } - public PhraseTrigger(IEnumerable phrases) - { - Phrases = new List(phrases); - } + public PhraseTrigger(IEnumerable phrases) + { + Phrases = new List(phrases); + } - public IEnumerable Phrases { get; set; } + public IEnumerable Phrases { get; set; } - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) - { - YamlParent = parent; - } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public void Unload() - { + public void LoadComplete(object parent) + { + YamlParent = parent; + } + + public void Unload() + { + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Triggers/PhraseTriggerCommandSetExtension.cs b/src/cs/Command/Triggers/PhraseTriggerCommandSetExtension.cs index 2653dec5..83014263 100644 --- a/src/cs/Command/Triggers/PhraseTriggerCommandSetExtension.cs +++ b/src/cs/Command/Triggers/PhraseTriggerCommandSetExtension.cs @@ -1,22 +1,23 @@ -using System.Linq; +using System.Collections.Generic; +using System.Linq; using macaroni.DataTypes; using Microsoft.CognitiveServices.Speech.Intent; -namespace macaroni; - -internal class PhraseTriggerCommandSetExtension : ICommandSetExtension, INotifyCondition, INotifyYamlValues +namespace macaroni { - public void InitCommandSetExtension(ICommandSet commandSet) + internal class PhraseTriggerCommandSetExtension : ICommandSetExtension, INotifyCondition, INotifyYamlValues { - _commandSet = commandSet; - _commandExecutionService = _commandSet?.GetParentOrService(); - _recognizer = _commandSet?.GetParentOrService(); - } + public void InitCommandSetExtension(ICommandSet commandSet) + { + _commandSet = commandSet; + _commandExecutionService = _commandSet?.GetParentOrService(); + _recognizer = _commandSet?.GetParentOrService(); + } - public void EnableExtension(bool enabled) - { - EnablePhraseTriggers(enabled); - } + public void EnableExtension(bool enabled) + { + EnablePhraseTriggers(enabled); + } public void ValueChanged(IYamlValue value) { @@ -32,217 +33,240 @@ public void ConditionChanged(ICondition condition) MR.DBG_TRACE_INFO($"PhraseTriggerCommandSetExtension::ConditionChanged({condition.GetType().Name}) ... Done!"); } - private void EnablePhraseTriggers(bool enabled) - { - if (enabled) - { - ReloadPatternMatchingModel(); - } - else + private void EnablePhraseTriggers(bool enabled) { - UnloadPatternMatchingModel(); + if (enabled) + { + ReloadPatternMatchingModel(); + } + else + { + UnloadPatternMatchingModel(); + } } - } - private void ReloadPatternMatchingModel() - { - if (_model != null) + private void ReloadPatternMatchingModel() { - _recognizer?.UnloadPatternMatchingModel(_model); - _model = null; + if (_model != null) + { + _recognizer?.UnloadPatternMatchingModel(_model); + _model = null; + } + LoadPatternMatchingModel(_recognizer); } - LoadPatternMatchingModel(_recognizer); - } - private void LoadPatternMatchingModel(IIntentRecognizerService? recognizer) - { - var model = CreatePatternMatchingModel(); - if (model != null) + private void LoadPatternMatchingModel(IIntentRecognizerService? recognizer) { - recognizer?.LoadPatternMatchingModel(model, x => InvokeCommand(x)); - _model = model; + var model = CreatePatternMatchingModel(); + if (model != null) + { + recognizer?.LoadPatternMatchingModel(model, x => InvokeCommand(x)); + _model = model; + } } - } - private void UnloadPatternMatchingModel() - { - if (_model != null) + private void UnloadPatternMatchingModel() { - _recognizer?.UnloadPatternMatchingModel(_model); - _model = null; + if (_model != null) + { + _recognizer?.UnloadPatternMatchingModel(_model); + _model = null; + } } - } - private PatternMatchingModel? CreatePatternMatchingModel() - { - var satisfied = _commandSet?.Conditions?.IsSatisfied(); - if (satisfied != null && !satisfied.Value) return null; + private PatternMatchingModel? CreatePatternMatchingModel() + { + var satisfied = _commandSet?.Conditions?.IsSatisfied(); + if (satisfied != null && !satisfied.Value) return null; - var modelId = _commandSet?.Id; - var model = new PatternMatchingModel(modelId); + var modelId = _commandSet?.Id; + var model = new PatternMatchingModel(modelId); - AddIntents(model); - AddEntities(model); + AddIntents(model); + AddEntities(model); - return model.Intents.Count > 0 ? model : null; - } + return model.Intents.Count > 0 ? model : null; + } - private void AddIntents(PatternMatchingModel model) - { - foreach (var command in _commandSet?.Commands ?? Enumerable.Empty()) + private void AddIntents(PatternMatchingModel model) { - if (command.Triggers == null) continue; - if (!command.IsSatisfied()) continue; - - var triggers = command.Triggers.ToList(); - if (command.Expecting != null) + foreach (var command in _commandSet?.Commands ?? Enumerable.Empty()) { - triggers.AddRange(command.Expecting); - } + if (command.Triggers == null) continue; + if (!command.IsSatisfied()) continue; - var phrases = new List(); - foreach (var item in triggers) - { - var trigger = item as IPhraseTrigger; - if (trigger != null) + var triggers = command.Triggers.ToList(); + if (command.Expecting != null) { - phrases.AddRange(trigger.Phrases); + triggers.AddRange(command.Expecting); } - } - if (phrases.Count > 0) - { - var intent = new PatternMatchingIntent(command.Id, phrases); - model.Intents.Add(intent); + var phrases = new List(); + foreach (var item in triggers) + { + var trigger = item as IPhraseTrigger; + if (trigger != null) + { + phrases.AddRange(trigger.Phrases); + } + } + + if (phrases.Count > 0) + { + var intent = new PatternMatchingIntent(command.Id, phrases); + model.Intents.Add(intent); + } } } - } - private void AddEntities(PatternMatchingModel model) - { - var ids = model.Intents - .SelectMany(intent => intent.Phrases) - .SelectMany(phrase => ExtractEntityNames(phrase)) - .Distinct(); + private void AddEntities(PatternMatchingModel model) + { + var ids = model.Intents + .SelectMany(intent => intent.Phrases) + .SelectMany(phrase => ExtractEntityNames(phrase)) + .Distinct(); - AddIntegerEntities(model, ids); - AddListEntities(model, ids); - } + AddIntegerEntities(model, ids); + AddListEntities(model, ids); + } - private IEnumerable ExtractEntityNames(string phrase) - { - var i = phrase.IndexOf("{"); - while (i >= 0) + private IEnumerable ExtractEntityNames(string phrase) { - var end = phrase.IndexOf("}", i); - var name = phrase.Substring(i + 1, end - i - 1); - yield return name; + var i = phrase.IndexOf("{"); + while (i >= 0) + { + var end = phrase.IndexOf("}", i); + var name = phrase.Substring(i + 1, end - i - 1); + yield return name; - i = phrase.IndexOf("{", end); + i = phrase.IndexOf("{", end); + } + yield break; } - yield break; - } - private static void AddIntegerEntities(PatternMatchingModel model, IEnumerable ids) - { - var intIds = ids.Where(id => id.StartsWith('#')).ToList(); - intIds.ForEach(id => model.Entities.Add(PatternMatchingEntity.CreateIntegerEntity(id))); - } + private static void AddIntegerEntities(PatternMatchingModel model, IEnumerable ids) + { + var intIds = ids.Where(id => id.StartsWith('#')).ToList(); + intIds.ForEach(id => model.Entities.Add(PatternMatchingEntity.CreateIntegerEntity(id))); + } - private void AddListEntities(PatternMatchingModel model, IEnumerable ids) - { - var values = _commandSet?.Values; - if (values != null) + private void AddListEntities(PatternMatchingModel model, IEnumerable ids) { - AddFuzzyListEntities(model, ids, values); - AddNonFuzzyListEntities(model, ids, values); + var values = _commandSet?.Values; + if (values != null) + { + AddFuzzyListEntities(model, ids, values); + AddNonFuzzyListEntities(model, ids, values); + } } - } - private static void AddNonFuzzyListEntities(PatternMatchingModel model, IEnumerable ids, IYamlValueCollection values) - { - var notFuzzy = ids - .Where(id => !id.EndsWith('*')) - .Where(id => values.ContainsKey(id)) - .Select(id => values[id]); - foreach (var v in notFuzzy) - { - var phrases = v.ToStrings()?.Select(x => x.Before(':')); - phrases = phrases?.Take(_maxPhrasesInListEntity); - - var list = PatternMatchingEntity.CreateListEntity(v.Name, EntityMatchMode.Strict, phrases); - model.Entities.Add(list); + private static void AddNonFuzzyListEntities(PatternMatchingModel model, IEnumerable ids, IYamlValueCollection values) + { + var notFuzzy = ids + .Where(id => !id.EndsWith('*')) + .Where(id => values.ContainsKey(id)) + .Select(id => values[id]); + foreach (var v in notFuzzy) + { + var phrases = v.ToStrings()?.Select(x => x.Before(':')); + phrases = phrases?.Take(_maxPhrasesInListEntity); + + var list = PatternMatchingEntity.CreateListEntity(v.Name, EntityMatchMode.Strict, phrases); + model.Entities.Add(list); + } } - } - private static void AddFuzzyListEntities(PatternMatchingModel model, IEnumerable ids, IYamlValueCollection values) - { - var fuzzy = ids - .Where(id => id.EndsWith('*')) - .Where(id => values.ContainsKey(id.TrimEnd('*'))) - .Select(id => values[id.Trim('*')]); - foreach (var v in fuzzy) - { - var phrases = v.ToStrings()?.Select(x => x.Before(':')); - phrases = phrases?.Take(_maxPhrasesInListEntity); - - var list = PatternMatchingEntity.CreateListEntity(v.Name, EntityMatchMode.Fuzzy, phrases); - model.Entities.Add(list); + private static void AddFuzzyListEntities(PatternMatchingModel model, IEnumerable ids, IYamlValueCollection values) + { + var fuzzy = ids + .Where(id => id.EndsWith('*')) + .Where(id => values.ContainsKey(id.TrimEnd('*'))) + .Select(id => values[id.Trim('*')]); + foreach (var v in fuzzy) + { + var phrases = v.ToStrings()?.Select(x => x.Before(':')); + + /* Unmerged change from project 'macaroni_core (net6.0-windows)' + Before: + phrases = phrases?.Take(_maxPhrasesInListEntity); + + var list = PatternMatchingEntity.CreateListEntity(v.Name, EntityMatchMode.Fuzzy, phrases); + After: + phrases = phrases?.Take(_maxPhrasesInListEntity); + + var list = PatternMatchingEntity.CreateListEntity(v.Name, EntityMatchMode.Fuzzy, phrases); + */ + + /* Unmerged change from project 'macaroni_core (netstandard2.1)' + Before: + phrases = phrases?.Take(_maxPhrasesInListEntity); + + var list = PatternMatchingEntity.CreateListEntity(v.Name, EntityMatchMode.Fuzzy, phrases); + After: + phrases = phrases?.Take(_maxPhrasesInListEntity); + + var list = PatternMatchingEntity.CreateListEntity(v.Name, EntityMatchMode.Fuzzy, phrases); + */ + phrases = phrases?.Take(_maxPhrasesInListEntity); + + var list = PatternMatchingEntity.CreateListEntity(v.Name, EntityMatchMode.Fuzzy, phrases); + model.Entities.Add(list); + } } - } - private void InvokeCommand(IntentResult result) - { - MR.DBG_TRACE_INFO($"--- INVOKING COMMAND: {result.IntentId}"); + private void InvokeCommand(IntentResult result) + { + MR.DBG_TRACE_INFO($"--- INVOKING COMMAND: {result.IntentId}"); - var command = GetCommand(result); - _commandExecutionService?.Execute(command, context => RegisterResolver(context, result)); + var command = GetCommand(result); + _commandExecutionService?.Execute(command, context => RegisterResolver(context, result)); - MR.DBG_TRACE_INFO($"- INVOKING COMMAND: {result.IntentId} ... Done!\n"); - } + MR.DBG_TRACE_INFO($"- INVOKING COMMAND: {result.IntentId} ... Done!\n"); + } - private ICommand? GetCommand(IntentResult result) - { - return _commandSet?.Commands?.FirstOrDefault(command => command?.Id == result.IntentId, null); - } + private ICommand? GetCommand(IntentResult result) + { + return _commandSet?.Commands?.FirstOrDefault(command => command?.Id == result.IntentId); + } - private static string RegisterResolver(IExecutionContext context, IntentResult result) - { - return context.RegisterResolver( - nameof(PhraseTriggerCommandSetExtension), - name => ResolveContext(result, name)); - } + private static string RegisterResolver(IExecutionContext context, IntentResult result) + { + return context.RegisterResolver( + nameof(PhraseTriggerCommandSetExtension), + name => ResolveContext(result, name)); + } - private static object? ResolveContext(IntentResult result, string name) - { - if (name == "context.keys") return string.Join('\n', - new string[] { + private static object? ResolveContext(IntentResult result, string name) + { + if (name == "context.keys") return string.Join('\n', + new string[] { "trigger.type", "phrase.trigger", "result.text", - } - .Concat(result.Entities.Keys) - ); + } + .Concat(result.Entities.Keys) + ); - if (name == "trigger.type") return "phrase"; - if (name == "phrase.trigger") return result.IntentRecognitionResult.Text; - if (name == "result.text") return result.IntentRecognitionResult.Text; + if (name == "trigger.type") return "phrase"; + if (name == "phrase.trigger") return result.IntentRecognitionResult.Text; + if (name == "result.text") return result.IntentRecognitionResult.Text; - if (result.Entities.ContainsKey(name)) return result.Entities[name]; - if (result.Entities.ContainsKey($"{name}*")) return result.Entities[$"{name}*"]; + if (result.Entities.ContainsKey(name)) return result.Entities[name]; + if (result.Entities.ContainsKey($"{name}*")) return result.Entities[$"{name}*"]; - var value = result.IntentRecognitionResult.Properties.GetProperty(name); - if (!string.IsNullOrEmpty(value)) return value; + var value = result.IntentRecognitionResult.Properties.GetProperty(name); + if (!string.IsNullOrEmpty(value)) return value; - return null; - } + return null; + } - private ICommandSet? _commandSet; - private ICommandExecutionService? _commandExecutionService; + private ICommandSet? _commandSet; + private ICommandExecutionService? _commandExecutionService; - private IIntentRecognizerService? _recognizer; - private PatternMatchingModel? _model; + private IIntentRecognizerService? _recognizer; + private PatternMatchingModel? _model; - private const int _maxPhrasesInListEntity = 1000; -} + private const int _maxPhrasesInListEntity = 1000; + } +} \ No newline at end of file diff --git a/src/cs/Command/Triggers/PhraseTriggerYamlParser.cs b/src/cs/Command/Triggers/PhraseTriggerYamlParser.cs index a66ba1b1..d466d1b6 100644 --- a/src/cs/Command/Triggers/PhraseTriggerYamlParser.cs +++ b/src/cs/Command/Triggers/PhraseTriggerYamlParser.cs @@ -1,33 +1,37 @@ -namespace macaroni; +using System; +using YamlDotNet.RepresentationModel; -internal class PhraseTriggerYamlParser : YamlParserBase, ITriggerYamlParser +namespace macaroni { - public PhraseTriggerYamlParser(ISystemContext context) : base(context) { } - - public string Kind { get { return "phrase"; } } - - public ICommandTrigger Parse(string file, YamlMappingNode? trigger, YamlNode value, IParsedValueWarningChecker? warnings) + internal class PhraseTriggerYamlParser : YamlParserBase, ITriggerYamlParser { - var scalar = value as YamlScalarNode; - if (scalar != null) return ParseScalar(file, trigger, scalar, warnings); + public PhraseTriggerYamlParser(ISystemContext context) : base(context) { } - var sequence = value as YamlSequenceNode; - if (sequence != null) return ParseSequence(file, trigger, sequence, warnings); + public string Kind { get { return "phrase"; } } - throw ExpectedSequenceOrStringValueException(file, Kind, value); - } + public ICommandTrigger Parse(string file, YamlMappingNode? trigger, YamlNode value, IParsedValueWarningChecker? warnings) + { + var scalar = value as YamlScalarNode; + if (scalar != null) return ParseScalar(file, trigger, scalar, warnings); - private ICommandTrigger ParseScalar(string file, YamlMappingNode? trigger, YamlScalarNode scalar, IParsedValueWarningChecker? warnings) - { - string phrase = RequireScalarStringValueNotNullOrEmpty(file, Kind, scalar, warnings); - RequireNoUnexpectedMappingKeys(file, trigger, Kind, Array.Empty()); - return new PhraseTrigger(phrase) { Yaml = scalar, YamlFile = file }; - } + var sequence = value as YamlSequenceNode; + if (sequence != null) return ParseSequence(file, trigger, sequence, warnings); - private ICommandTrigger ParseSequence(string file, YamlMappingNode? trigger, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) - { - var phrases = RequireSequenceOfStringsNotNullOrEmpty(file, Kind, sequence, warnings); - RequireNoUnexpectedMappingKeys(file, trigger, Kind, Array.Empty()); - return new PhraseTrigger(phrases) { Yaml = sequence, YamlFile = file }; + throw ExpectedSequenceOrStringValueException(file, Kind, value); + } + + private ICommandTrigger ParseScalar(string file, YamlMappingNode? trigger, YamlScalarNode scalar, IParsedValueWarningChecker? warnings) + { + string phrase = RequireScalarStringValueNotNullOrEmpty(file, Kind, scalar, warnings); + RequireNoUnexpectedMappingKeys(file, trigger, Kind, Array.Empty()); + return new PhraseTrigger(phrase) { Yaml = scalar, YamlFile = file }; + } + + private ICommandTrigger ParseSequence(string file, YamlMappingNode? trigger, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) + { + var phrases = RequireSequenceOfStringsNotNullOrEmpty(file, Kind, sequence, warnings); + RequireNoUnexpectedMappingKeys(file, trigger, Kind, Array.Empty()); + return new PhraseTrigger(phrases) { Yaml = sequence, YamlFile = file }; + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Triggers/TriggerCollection.cs b/src/cs/Command/Triggers/TriggerCollection.cs index d7c11d9d..c60709df 100644 --- a/src/cs/Command/Triggers/TriggerCollection.cs +++ b/src/cs/Command/Triggers/TriggerCollection.cs @@ -1,26 +1,30 @@ -namespace macaroni; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class TriggerCollection : List, ITriggerCollection, ILoadedFromYamlFile +namespace macaroni { - public TriggerCollection(IEnumerable triggers) : base(triggers) + internal class TriggerCollection : List, ITriggerCollection, ILoadedFromYamlFile { - } + public TriggerCollection(IEnumerable triggers) : base(triggers) + { + } - public YamlNode? Yaml { get; internal set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) - { - YamlParent = parent; - if (Yaml == null) Yaml = (parent as ILoadedFromYamlFile)?.Yaml; - if (YamlFile == null) YamlFile = (parent as ILoadedFromYamlFile)?.YamlFile; + public YamlNode? Yaml { get; internal set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - this.ForEach(x => (x as ILoadedFromYamlFile)?.LoadComplete(this)); - } + public void LoadComplete(object parent) + { + YamlParent = parent; + if (Yaml == null) Yaml = (parent as ILoadedFromYamlFile)?.Yaml; + if (YamlFile == null) YamlFile = (parent as ILoadedFromYamlFile)?.YamlFile; - public void Unload() - { - this.ForEach(x => (x as ILoadedFromYamlFile)?.Unload()); + this.ForEach(x => (x as ILoadedFromYamlFile)?.LoadComplete(this)); + } + + public void Unload() + { + this.ForEach(x => (x as ILoadedFromYamlFile)?.Unload()); + } } -} +} \ No newline at end of file diff --git a/src/cs/Command/Triggers/TriggerCollectionYamlParser.cs b/src/cs/Command/Triggers/TriggerCollectionYamlParser.cs index 430fbd78..a919fbdc 100644 --- a/src/cs/Command/Triggers/TriggerCollectionYamlParser.cs +++ b/src/cs/Command/Triggers/TriggerCollectionYamlParser.cs @@ -1,35 +1,38 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class TriggerCollectionYamlParser : YamlParserBase, ITriggerCollectionYamlParser +namespace macaroni { - public TriggerCollectionYamlParser(ITriggerFactory factory, ISystemContext context) : base(context) + internal class TriggerCollectionYamlParser : YamlParserBase, ITriggerCollectionYamlParser { - _factory = factory; - } - - public ITriggerCollection? CheckForTriggers(string file, YamlMappingNode mapping, string triggersMappingName, IParsedValueWarningChecker? warnings) - { - var sequence = mapping.Children.ContainsKey(triggersMappingName) - ? mapping.Children[triggersMappingName] as YamlSequenceNode - : null; - return sequence != null - ? TriggersFromSequence(file, sequence, warnings) - : null; - } + public TriggerCollectionYamlParser(ITriggerFactory factory, ISystemContext context) : base(context) + { + _factory = factory; + } - public ITriggerCollection TriggersFromSequence(string file, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) - { - var triggers = RequireSequenceOf(file, sequence, - "trigger", - (file, node) => _factory.TriggerFromYamlNode(file, node, warnings), - (file, node) => ErrorUnexpectedNode(file, node, _factory.GetValidTriggerMappingTypes())); + public ITriggerCollection? CheckForTriggers(string file, YamlMappingNode mapping, string triggersMappingName, IParsedValueWarningChecker? warnings) + { + var sequence = mapping.Children.ContainsKey(triggersMappingName) + ? mapping.Children[triggersMappingName] as YamlSequenceNode + : null; + return sequence != null + ? TriggersFromSequence(file, sequence, warnings) + : null; + } - return new TriggerCollection(triggers) + public ITriggerCollection TriggersFromSequence(string file, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) { - Yaml = sequence, - YamlFile = file - }; - } + var triggers = RequireSequenceOf(file, sequence, + "trigger", + (file, node) => _factory.TriggerFromYamlNode(file, node, warnings), + (file, node) => ErrorUnexpectedNode(file, node, _factory.GetValidTriggerMappingTypes())); - private readonly ITriggerFactory _factory; -} + return new TriggerCollection(triggers) + { + Yaml = sequence, + YamlFile = file + }; + } + + private readonly ITriggerFactory _factory; + } +} \ No newline at end of file diff --git a/src/cs/Command/Triggers/TriggerFactory.cs b/src/cs/Command/Triggers/TriggerFactory.cs index d2ed3703..7d0e9f00 100644 --- a/src/cs/Command/Triggers/TriggerFactory.cs +++ b/src/cs/Command/Triggers/TriggerFactory.cs @@ -1,98 +1,103 @@ -using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.DependencyInjection; +using YamlDotNet.RepresentationModel; -namespace macaroni; - -internal class TriggerFactory : YamlParserBase, ITriggerFactory +namespace macaroni { - public TriggerFactory(IServiceProvider serviceProvider, IEnumerable parsers, ISystemContext context) : base(context) + internal class TriggerFactory : YamlParserBase, ITriggerFactory { - _serviceProvider = serviceProvider; - _parsers = parsers; - } + public TriggerFactory(IServiceProvider serviceProvider, IEnumerable parsers, ISystemContext context) : base(context) + { + _serviceProvider = serviceProvider; + _parsers = parsers; + } - public bool IsInvalidTriggerNode(YamlMappingNode mapping) - { - var count = mapping.Children - .Count(x => _validTriggerMappingTypeKeys - .Contains((x.Key as YamlScalarNode)?.Value)); - return count == 0; - } + public bool IsInvalidTriggerNode(YamlMappingNode mapping) + { + var count = mapping.Children + .Count(x => _validTriggerMappingTypeKeys + .Contains((x.Key as YamlScalarNode)?.Value)); + return count == 0; + } - public ICommandTrigger TriggerFromYamlNode(string file, YamlNode node, IParsedValueWarningChecker? warnings) - { - var mapping = node as YamlMappingNode; - if (mapping != null) + public ICommandTrigger TriggerFromYamlNode(string file, YamlNode node, IParsedValueWarningChecker? warnings) { - if (IsInvalidTriggerNode(mapping) && IsInvalidConditionNode(mapping)) + var mapping = node as YamlMappingNode; + if (mapping != null) + { + if (IsInvalidTriggerNode(mapping) && IsInvalidConditionNode(mapping)) + { + var expected = GetValidTriggerMappingTypes(); + throw ErrorParsingYamlException(file, mapping.Start.Line, mapping.Start.Column, "Unexpected node mapping", $"EXPECTED: {expected}"); + } + + return ParseTriggerFromMapping(file, mapping, warnings); + } + + var scalar = node as YamlScalarNode; + if (scalar != null) { - var expected = GetValidTriggerMappingTypes(); - throw ErrorParsingYamlException(file, mapping.Start.Line, mapping.Start.Column, "Unexpected node mapping", $"EXPECTED: {expected}"); + return TriggerFromScalar(file, scalar, warnings); } - return ParseTriggerFromMapping(file, mapping, warnings); + throw ErrorParsingYamlException(file, node.Start.Line, node.Start.Column, "Unexpected node", $"EXPECTED: {GetValidTriggerMappingTypes()}, or (string)"); } - var scalar = node as YamlScalarNode; - if (scalar != null) + public string GetValidTriggerMappingTypes() { - return TriggerFromScalar(file, scalar, warnings); + return string.Join(", ", _validTriggerMappingTypeKeys); } - throw ErrorParsingYamlException(file, node.Start.Line, node.Start.Column, "Unexpected node", $"EXPECTED: {GetValidTriggerMappingTypes()}, or (string)"); - } - - public string GetValidTriggerMappingTypes() - { - return string.Join(", ", _validTriggerMappingTypeKeys); - } - - private ICommandTrigger ParseTriggerFromMapping(string file, YamlMappingNode mapping, IParsedValueWarningChecker? warnings) - { - foreach (var parser in _parsers) + private ICommandTrigger ParseTriggerFromMapping(string file, YamlMappingNode mapping, IParsedValueWarningChecker? warnings) { - if (mapping.Children.ContainsKey(parser.Kind)) + foreach (var parser in _parsers) { - return parser.Parse(file, mapping, mapping.Children[parser.Kind], warnings); + if (mapping.Children.ContainsKey(parser.Kind)) + { + return parser.Parse(file, mapping, mapping.Children[parser.Kind], warnings); + } } - } - EnsureConditionFactory(); - if (!_conditionFactory!.IsInvalidConditionNode(mapping)) - { - var condition = _conditionFactory.ConditionFromYamlNode(file, mapping, warnings); - IEnumerable conditions = new[] { condition }; + EnsureConditionFactory(); + if (!_conditionFactory!.IsInvalidConditionNode(mapping)) + { + var condition = _conditionFactory.ConditionFromYamlNode(file, mapping, warnings); + IEnumerable conditions = new[] { condition }; - var collection = ActivatorUtilities.CreateInstance(_serviceProvider, conditions); - return ActivatorUtilities.CreateInstance(_serviceProvider, collection); - } + var collection = ActivatorUtilities.CreateInstance(_serviceProvider, conditions); + return ActivatorUtilities.CreateInstance(_serviceProvider, collection); + } - return new CommandTrigger() { Yaml = mapping, YamlFile = file }; - } + return new CommandTrigger() { Yaml = mapping, YamlFile = file }; + } - private ICommandTrigger TriggerFromScalar(string file, YamlScalarNode scalar, IParsedValueWarningChecker? warnings) - { - var parser = _parsers.Where(x => x.Kind == "phrase").First(); - return parser != null - ? parser.Parse(file, null, scalar, warnings) - : new CommandTrigger() { Yaml = scalar, YamlFile = file }; - } + private ICommandTrigger TriggerFromScalar(string file, YamlScalarNode scalar, IParsedValueWarningChecker? warnings) + { + var parser = _parsers.Where(x => x.Kind == "phrase").First(); + return parser != null + ? parser.Parse(file, null, scalar, warnings) + : new CommandTrigger() { Yaml = scalar, YamlFile = file }; + } - private bool IsInvalidConditionNode(YamlMappingNode mapping) - { - EnsureConditionFactory(); - return _conditionFactory!.IsInvalidConditionNode(mapping); - } + private bool IsInvalidConditionNode(YamlMappingNode mapping) + { + EnsureConditionFactory(); + return _conditionFactory!.IsInvalidConditionNode(mapping); + } - private void EnsureConditionFactory() - { - if (_conditionFactory == null) + private void EnsureConditionFactory() { - _conditionFactory = _serviceProvider.GetRequiredService(); + if (_conditionFactory == null) + { + _conditionFactory = _serviceProvider.GetRequiredService(); + } } - } - private IServiceProvider _serviceProvider; - private IEnumerable _parsers; - private IConditionFactory? _conditionFactory; - private static IEnumerable _validTriggerMappingTypeKeys = new string[] { "phrase", "intent", "hotkey", "message", "publish", "when", "nugget" }; -} + private IServiceProvider _serviceProvider; + private IEnumerable _parsers; + private IConditionFactory? _conditionFactory; + private static IEnumerable _validTriggerMappingTypeKeys = new string[] { "phrase", "intent", "hotkey", "message", "publish", "when", "nugget" }; + } +} \ No newline at end of file diff --git a/src/cs/Command/Triggers/WhenTrigger.cs b/src/cs/Command/Triggers/WhenTrigger.cs index 6b1c2bf5..5de98ae5 100644 --- a/src/cs/Command/Triggers/WhenTrigger.cs +++ b/src/cs/Command/Triggers/WhenTrigger.cs @@ -1,85 +1,89 @@ -namespace macaroni; +using System.Linq; +using YamlDotNet.RepresentationModel; -internal class WhenTrigger : IWhenTrigger, ILoadedFromYamlFile, INotifyCondition +namespace macaroni { - public WhenTrigger(IConditionCollection? conditions = null) + internal class WhenTrigger : IWhenTrigger, ILoadedFromYamlFile, INotifyCondition { - Conditions = conditions; - } + public WhenTrigger(IConditionCollection? conditions = null) + { + Conditions = conditions; + } - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public IConditionCollection? Conditions { get; internal set; } + public IConditionCollection? Conditions { get; internal set; } - public void LoadComplete(object parent) - { - MR.TRACE_VERBOSE("When LoadComplete..."); + public void LoadComplete(object parent) + { + MR.TRACE_VERBOSE("When LoadComplete..."); - YamlParent = parent; - if (Yaml == null) Yaml = (parent as ILoadedFromYamlFile)?.Yaml; - if (YamlFile == null) YamlFile = (parent as ILoadedFromYamlFile)?.YamlFile; + YamlParent = parent; + if (Yaml == null) Yaml = (parent as ILoadedFromYamlFile)?.Yaml; + if (YamlFile == null) YamlFile = (parent as ILoadedFromYamlFile)?.YamlFile; - if (!this.IsEditorDesignMode()) - { - _commandExecutionService = this.GetRequiredParentOrService(); + if (!this.IsEditorDesignMode()) + { + _commandExecutionService = this.GetRequiredParentOrService(); - (Conditions as ILoadedFromYamlFile)?.LoadComplete(this); - _satisfied = CheckConditions(); + (Conditions as ILoadedFromYamlFile)?.LoadComplete(this); + _satisfied = CheckConditions(); + } } - } - public void Unload() - { - (Conditions as ILoadedFromYamlFile)?.Unload(); - } + public void Unload() + { + (Conditions as ILoadedFromYamlFile)?.Unload(); + } - public void ConditionChanged(ICondition condition) - { - MR.DBG_TRACE_VERBOSE("ConditionChanged..."); - var satisfied = CheckConditions(); - var changed = _satisfied != satisfied; - _satisfied = satisfied; + public void ConditionChanged(ICondition condition) + { + MR.DBG_TRACE_VERBOSE("ConditionChanged..."); + var satisfied = CheckConditions(); + var changed = _satisfied != satisfied; + _satisfied = satisfied; + + if (changed && satisfied) + { + var command = this.GetRequiredParentOrService(); + InvokeCommand(command); + } + } - if (changed && satisfied) + private bool CheckConditions() { - var command = this.GetRequiredParentOrService(); - InvokeCommand(command); + return Conditions != null && Conditions.IsSatisfied(null); } - } - private bool CheckConditions() - { - return Conditions != null && Conditions.IsSatisfied(null); - } + private void InvokeCommand(ICommand? command) + { + if (command != null && command.IsSatisfied(null)) + { + MR.DBG_TRACE_INFO($"--- INVOKING COMMAND: conditions true={Conditions?.Count()} ..."); + _commandExecutionService?.Execute(command, context => RegisterResolver(context)); + MR.DBG_TRACE_INFO($"--- INVOKING COMMAND: conditions true={Conditions?.Count()} ... Done!"); + } + } - private void InvokeCommand(ICommand? command) - { - if (command != null && command.IsSatisfied(null)) + private static string RegisterResolver(IExecutionContext context) { - MR.DBG_TRACE_INFO($"--- INVOKING COMMAND: conditions true={Conditions?.Count()} ..."); - _commandExecutionService?.Execute(command, context => RegisterResolver(context)); - MR.DBG_TRACE_INFO($"--- INVOKING COMMAND: conditions true={Conditions?.Count()} ... Done!"); + return context.RegisterResolver( + nameof(WhenTrigger), + name => ResolveContext(name)); } - } - private static string RegisterResolver(IExecutionContext context) - { - return context.RegisterResolver( - nameof(WhenTrigger), - name => ResolveContext(name)); - } + private static object? ResolveContext(string name) + { + if (name == "context.keys") return "trigger.type"; - private static object? ResolveContext(string name) - { - if (name == "context.keys") return "trigger.type"; + return (name == "trigger.type") + ? "when" + : null; + } - return (name == "trigger.type") - ? "when" - : null; + private bool _satisfied; + private ICommandExecutionService? _commandExecutionService; } - - private bool _satisfied; - private ICommandExecutionService? _commandExecutionService; -} +} \ No newline at end of file diff --git a/src/cs/Command/Triggers/WhenTriggerYamlParser.cs b/src/cs/Command/Triggers/WhenTriggerYamlParser.cs index e75a4051..239e34f2 100644 --- a/src/cs/Command/Triggers/WhenTriggerYamlParser.cs +++ b/src/cs/Command/Triggers/WhenTriggerYamlParser.cs @@ -1,46 +1,49 @@ -using Microsoft.Extensions.DependencyInjection; +using System; +using Microsoft.Extensions.DependencyInjection; +using YamlDotNet.RepresentationModel; -namespace macaroni; - -internal class WhenTriggerYamlParser : YamlParserBase, ITriggerYamlParser +namespace macaroni { - public WhenTriggerYamlParser(IServiceProvider services, ISystemContext context) : base(context) + internal class WhenTriggerYamlParser : YamlParserBase, ITriggerYamlParser { - _serviceProvider = services; - } + public WhenTriggerYamlParser(IServiceProvider services, ISystemContext context) : base(context) + { + _serviceProvider = services; + } - public string Kind { get { return "when"; } } + public string Kind { get { return "when"; } } - public ICommandTrigger Parse(string file, YamlMappingNode? trigger, YamlNode value, IParsedValueWarningChecker? warnings) - { - var sequence = value as YamlSequenceNode; - if (sequence != null) return ParseSequence(file, trigger, sequence, warnings); + public ICommandTrigger Parse(string file, YamlMappingNode? trigger, YamlNode value, IParsedValueWarningChecker? warnings) + { + var sequence = value as YamlSequenceNode; + if (sequence != null) return ParseSequence(file, trigger, sequence, warnings); - throw ErrorParsingYamlException(file, value.Start.Line, value.Start.Column, "Unexpected YamlNode type", "EXPECTED: `when: {condition sequence}`"); - } + throw ErrorParsingYamlException(file, value.Start.Line, value.Start.Column, "Unexpected YamlNode type", "EXPECTED: `when: {condition sequence}`"); + } - private ICommandTrigger ParseSequence(string file, YamlMappingNode? trigger, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) - { - EnsureParsers(); + private ICommandTrigger ParseSequence(string file, YamlMappingNode? trigger, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) + { + EnsureParsers(); - RequireNoUnexpectedMappingKeys(file, trigger, Kind, Array.Empty()); + RequireNoUnexpectedMappingKeys(file, trigger, Kind, Array.Empty()); - return new WhenTrigger() - { - Conditions = _conditionsParser?.ConditionsFromSequence(file, sequence, warnings), - Yaml = sequence, - YamlFile = file - }; - } + return new WhenTrigger() + { + Conditions = _conditionsParser?.ConditionsFromSequence(file, sequence, warnings), + Yaml = sequence, + YamlFile = file + }; + } - private void EnsureParsers() - { - if (_conditionsParser == null) + private void EnsureParsers() { - _conditionsParser = _serviceProvider.GetRequiredService(); + if (_conditionsParser == null) + { + _conditionsParser = _serviceProvider.GetRequiredService(); + } } - } - private readonly IServiceProvider _serviceProvider; - private IConditionCollectionYamlParser? _conditionsParser; -} + private readonly IServiceProvider _serviceProvider; + private IConditionCollectionYamlParser? _conditionsParser; + } +} \ No newline at end of file diff --git a/src/cs/CommandSet/CommandSet.cs b/src/cs/CommandSet/CommandSet.cs index f7b2132c..673c5f64 100644 --- a/src/cs/CommandSet/CommandSet.cs +++ b/src/cs/CommandSet/CommandSet.cs @@ -1,180 +1,185 @@ -using Microsoft.CognitiveServices.Speech.Intent; +using System; +using System.Collections.Generic; +using System.Linq; using Microsoft.Extensions.DependencyInjection; +using YamlDotNet.RepresentationModel; -namespace macaroni; - -internal class CommandSet : ICommandSet, IServiceProvider, INotifyYamlValues, ICommandSite, ILoadedFromYamlFile +namespace macaroni { - public CommandSet() + + internal class CommandSet : ICommandSet, IServiceProvider, INotifyYamlValues, ICommandSite, ILoadedFromYamlFile { - } + public CommandSet() + { + } - public string Id { get { return GetId(); }} - public string? Keyword { get; internal set; } + public string Id { get { return GetId(); } } + public string? Keyword { get; internal set; } - public INuggetCollection? Nuggets { get; internal set; } - public IYamlValueCollection? Values { get; internal set; } - public IConditionCollection? Conditions { get; internal set; } - public IEnumerable? Commands { get; internal set; } + public INuggetCollection? Nuggets { get; internal set; } + public IYamlValueCollection? Values { get; internal set; } + public IConditionCollection? Conditions { get; internal set; } + public IEnumerable? Commands { get; internal set; } - public IEnumerable? Warnings { get; internal set; } + public IEnumerable? Warnings { get; internal set; } - public object? GetService(Type serviceType) - { - return serviceType == typeof(ILocalContext) - ? EnsureCommandSetContext() - : null; - } + public object? GetService(Type serviceType) + { + return serviceType == typeof(ILocalContext) + ? EnsureCommandSetContext() + : null; + } - public YamlNode? Yaml { get; internal set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } + public YamlNode? Yaml { get; internal set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - void ILoadedFromYamlFile.LoadComplete(object parent) - { - YamlParent = parent; + void ILoadedFromYamlFile.LoadComplete(object parent) + { + YamlParent = parent; - (Values as ILoadedFromYamlFile)?.LoadComplete(this); - (Conditions as ILoadedFromYamlFile)?.LoadComplete(this); + (Values as ILoadedFromYamlFile)?.LoadComplete(this); + (Conditions as ILoadedFromYamlFile)?.LoadComplete(this); - foreach (var command in Commands ?? Enumerable.Empty()) - { - var loaded = command as ILoadedFromYamlFile; - loaded?.LoadComplete(this); + foreach (var command in Commands ?? Enumerable.Empty()) + { + var loaded = command as ILoadedFromYamlFile; + loaded?.LoadComplete(this); + } + + foreach (var nugget in Nuggets ?? Enumerable.Empty()) + { + var loaded = nugget as ILoadedFromYamlFile; + loaded?.LoadComplete(this); + } } - foreach (var nugget in Nuggets ?? Enumerable.Empty()) + public void Unload() { - var loaded = nugget as ILoadedFromYamlFile; - loaded?.LoadComplete(this); - } - } + (Values as ILoadedFromYamlFile)?.Unload(); + (Conditions as ILoadedFromYamlFile)?.Unload(); - public void Unload() - { - (Values as ILoadedFromYamlFile)?.Unload(); - (Conditions as ILoadedFromYamlFile)?.Unload(); + foreach (var command in Commands ?? Enumerable.Empty()) + { + var loaded = command as ILoadedFromYamlFile; + loaded?.Unload(); + } - foreach (var command in Commands ?? Enumerable.Empty()) - { - var loaded = command as ILoadedFromYamlFile; - loaded?.Unload(); + foreach (var nugget in Nuggets ?? Enumerable.Empty()) + { + var loaded = nugget as ILoadedFromYamlFile; + loaded?.Unload(); + } } - foreach (var nugget in Nuggets ?? Enumerable.Empty()) + void ICommandSet.StartCommandSet(ICommandSystemService commandSystem) { - var loaded = nugget as ILoadedFromYamlFile; - loaded?.Unload(); + _commandSystem = commandSystem; + EnableExtensions(true); } - } - - void ICommandSet.StartCommandSet(ICommandSystemService commandSystem) - { - _commandSystem = commandSystem; - EnableExtensions(true); - } - void ICommandSet.StopCommandSet() - { - EnableExtensions(false); - Unload(); - } - - void INotifyYamlValues.ValueChanged(IYamlValue value) - { - MR.DBG_TRACE_INFO($"CommandSet:ValueChanged: {value.GetType().Name}"); - EnsureInitExtensions(); - foreach (var extension in _extensions ?? Enumerable.Empty()) + void ICommandSet.StopCommandSet() { - var notify = extension as INotifyYamlValues; - notify?.ValueChanged(value); + EnableExtensions(false); + Unload(); } - MR.DBG_TRACE_INFO($"CommandSet: ValueChanged: {value.GetType().Name} ... Done!\n"); - } - void INotifyCondition.ConditionChanged(ICondition condition) - { - MR.DBG_TRACE_INFO($"CommandSet: ConditionChanged: {condition.GetType().Name}"); - EnsureInitExtensions(); - foreach (var extension in _extensions ?? Enumerable.Empty()) + void INotifyYamlValues.ValueChanged(IYamlValue value) { - var notify = extension as INotifyCondition; - notify?.ConditionChanged(condition); + MR.DBG_TRACE_INFO($"CommandSet:ValueChanged: {value.GetType().Name}"); + EnsureInitExtensions(); + foreach (var extension in _extensions ?? Enumerable.Empty()) + { + var notify = extension as INotifyYamlValues; + notify?.ValueChanged(value); + } + MR.DBG_TRACE_INFO($"CommandSet: ValueChanged: {value.GetType().Name} ... Done!\n"); } - MR.DBG_TRACE_INFO($"CommandSet: ConditionChanged: {condition.GetType().Name} ... Done!\n"); - } - IExecutionContext ICommandSet.CreateExecutionContext() - { - var context = (this as ICommandSet).GetRequiredParentOrService(); - context.RegisterResolver(nameof(ICommandSet), key => EnsureCommandSetContext()?.Get(key, null)); - return context; - } + void INotifyCondition.ConditionChanged(ICondition condition) + { + MR.DBG_TRACE_INFO($"CommandSet: ConditionChanged: {condition.GetType().Name}"); + EnsureInitExtensions(); + foreach (var extension in _extensions ?? Enumerable.Empty()) + { + var notify = extension as INotifyCondition; + notify?.ConditionChanged(condition); + } + MR.DBG_TRACE_INFO($"CommandSet: ConditionChanged: {condition.GetType().Name} ... Done!\n"); + } - private void EnableExtensions(bool enabled) - { - EnsureInitExtensions(); - foreach (var extension in _extensions ?? Enumerable.Empty()) + IExecutionContext ICommandSet.CreateExecutionContext() { - extension.EnableExtension(enabled); + var context = (this as ICommandSet).GetRequiredParentOrService(); + context.RegisterResolver(nameof(ICommandSet), key => EnsureCommandSetContext()?.Get(key, null)); + return context; } - } - private void EnsureInitExtensions() - { - if (_extensions == null) + private void EnableExtensions(bool enabled) { - _extensions = _commandSystem?.Services.GetServices(); + EnsureInitExtensions(); foreach (var extension in _extensions ?? Enumerable.Empty()) { - extension.InitCommandSetExtension(this); + extension.EnableExtension(enabled); } } - } - private ILocalContext? EnsureCommandSetContext() - { - if (_commandSetContext == null) + private void EnsureInitExtensions() { - _commandSetContext = _commandSystem?.Services.GetRequiredService(); - _commandSetContext?.RegisterResolver(nameof(ILocalContext), name => ResolveContext(name)); + if (_extensions == null) + { + _extensions = _commandSystem?.Services.GetServices(); + foreach (var extension in _extensions ?? Enumerable.Empty()) + { + extension.InitCommandSetExtension(this); + } + } } - return _commandSetContext; - } + private ILocalContext? EnsureCommandSetContext() + { + if (_commandSetContext == null) + { + _commandSetContext = _commandSystem?.Services.GetRequiredService(); + _commandSetContext?.RegisterResolver(nameof(ILocalContext), name => ResolveContext(name)); + } - private object? ResolveContext(string name) - { - return Values == null ? null - : Values.TryGetValue(name, out var value) ? value.Value - : name.StartsWith("values.") ? ResolveContext(name.Substring("values.".Length)) - : null; - } + return _commandSetContext; + } - private string GetId() - { - if (_id == null) + private object? ResolveContext(string name) { - _id = Yaml != null ? GetYamlId() : GetNextSequentialId(); - _id = _id.Replace("\\", "/"); + return Values == null ? null + : Values.TryGetValue(name, out var value) ? value.Value + : name.StartsWith("values.") ? ResolveContext(name.Substring("values.".Length)) + : null; } - return _id; - } - private string GetYamlId() - { - return $"{YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"; - } + private string GetId() + { + if (_id == null) + { + _id = Yaml != null ? GetYamlId() : GetNextSequentialId(); + _id = _id.Replace("\\", "/"); + } + return _id; + } - private string GetNextSequentialId() - { - _nextSequentialId++; - return $"CommandSet{_nextSequentialId}"; - } + private string GetYamlId() + { + return $"{YamlFile}({Yaml?.Start.Line},{Yaml?.Start.Column})"; + } - private string? _id; - private static int _nextSequentialId = 0; - private ICommandSystemService? _commandSystem; - private ILocalContext? _commandSetContext; - private IEnumerable? _extensions; -} + private string GetNextSequentialId() + { + _nextSequentialId++; + return $"CommandSet{_nextSequentialId}"; + } + + private string? _id; + private static int _nextSequentialId = 0; + private ICommandSystemService? _commandSystem; + private ILocalContext? _commandSetContext; + private IEnumerable? _extensions; + } +} \ No newline at end of file diff --git a/src/cs/CommandSet/CommandSetFactories/CommandSetFactoryHost.cs b/src/cs/CommandSet/CommandSetFactories/CommandSetFactoryHost.cs index a111a1a5..d016ab7a 100644 --- a/src/cs/CommandSet/CommandSetFactories/CommandSetFactoryHost.cs +++ b/src/cs/CommandSet/CommandSetFactories/CommandSetFactoryHost.cs @@ -1,23 +1,29 @@ -using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; -namespace macaroni; - -internal class CommandSetFactoryHost : StartStopHelperBackgroundService +namespace macaroni { - public CommandSetFactoryHost(IServiceProvider services) : base(services) - { - _commandSetFactories = _services.GetServices(); - } - override protected Task StartAsync() + internal class CommandSetFactoryHost : StartStopHelperBackgroundService { - return Task.WhenAll(_commandSetFactories.Select(x => x.StartAsync())); - } + public CommandSetFactoryHost(IServiceProvider services) : base(services) + { + _commandSetFactories = _services.GetServices(); + } - override protected Task StopAsync() - { - return Task.WhenAll(_commandSetFactories.Select(x => x.StopAsync())); - } + override protected Task StartAsync() + { + return Task.WhenAll(_commandSetFactories.Select(x => x.StartAsync())); + } - private IEnumerable _commandSetFactories; -} + override protected Task StopAsync() + { + return Task.WhenAll(_commandSetFactories.Select(x => x.StopAsync())); + } + + private IEnumerable _commandSetFactories; + } +} \ No newline at end of file diff --git a/src/cs/CommandSet/CommandSetFactories/DefaultFileFolderCommandSetFactory.cs b/src/cs/CommandSet/CommandSetFactories/DefaultFileFolderCommandSetFactory.cs index 8b15fbf6..da7fc03f 100644 --- a/src/cs/CommandSet/CommandSetFactories/DefaultFileFolderCommandSetFactory.cs +++ b/src/cs/CommandSet/CommandSetFactories/DefaultFileFolderCommandSetFactory.cs @@ -1,16 +1,19 @@ using Microsoft.Extensions.DependencyInjection; +using System; -namespace macaroni; - -internal class DefaultFileFolderCommandSetFactory : FileFolderCommandSetFactory +namespace macaroni { - public DefaultFileFolderCommandSetFactory(IServiceProvider services) : - base(services, GetMacrosFolder(services)) - { - } - private static string GetMacrosFolder(IServiceProvider services) + internal class DefaultFileFolderCommandSetFactory : FileFolderCommandSetFactory { - return services.GetRequiredService().Get("folders.macros", null) as string ?? "."; + public DefaultFileFolderCommandSetFactory(IServiceProvider services) : + base(services, GetMacrosFolder(services)) + { + } + + private static string GetMacrosFolder(IServiceProvider services) + { + return services.GetRequiredService().Get("folders.macros", null) as string ?? "."; + } } -} +} \ No newline at end of file diff --git a/src/cs/CommandSet/CommandSetFactories/FileFolderCommandSetFactory.cs b/src/cs/CommandSet/CommandSetFactories/FileFolderCommandSetFactory.cs index f1dfe159..2ebee29f 100644 --- a/src/cs/CommandSet/CommandSetFactories/FileFolderCommandSetFactory.cs +++ b/src/cs/CommandSet/CommandSetFactories/FileFolderCommandSetFactory.cs @@ -1,62 +1,66 @@ using Microsoft.Extensions.DependencyInjection; +using System; +using System.IO; +using System.Threading.Tasks; -namespace macaroni; - -internal class FileFolderCommandSetFactory : ICommandSetFactory +namespace macaroni { - public FileFolderCommandSetFactory(IServiceProvider services, string macroFolder, string macroFilter = "*.mac") : - this(services.GetRequiredService(), - services.GetRequiredService(), - macroFolder, macroFilter) + internal class FileFolderCommandSetFactory : ICommandSetFactory { - } + public FileFolderCommandSetFactory(IServiceProvider services, string macroFolder, string macroFilter = "*.mac") : + this(services.GetRequiredService(), + services.GetRequiredService(), + macroFolder, macroFilter) + { + } - public FileFolderCommandSetFactory(ICommandSystemService commandSystem, IFileMonitoringService fileMonitor, string macroFolder, string macroFilter) - { - _commandSystem = commandSystem; + public FileFolderCommandSetFactory(ICommandSystemService commandSystem, IFileMonitoringService fileMonitor, string macroFolder, string macroFilter) + { + _commandSystem = commandSystem; - _fileMonitor = fileMonitor; - _filter = macroFilter; - _path = macroFolder; - } + _fileMonitor = fileMonitor; + _filter = macroFilter; + _path = macroFolder; + } - public Task StartAsync() - { - _fileMonitor.StartNotify( - _path, - _filter, - newFile => FoundFile(newFile), - changedFile => FileChanged(changedFile), - deletedFile => FileDeleted(deletedFile)); - - return Task.CompletedTask; - } + public Task StartAsync() + { + _fileMonitor.StartNotify( + _path, + _filter, + newFile => FoundFile(newFile), + changedFile => FileChanged(changedFile), + deletedFile => FileDeleted(deletedFile)); - public Task StopAsync() - { - _fileMonitor?.StopNotify(); - return Task.CompletedTask; - } + return Task.CompletedTask; + } - private void FoundFile(FileInfo file) - { - _ = _commandSystem.LoadFileAsync(file.FullName); - } + public Task StopAsync() + { + _fileMonitor?.StopNotify(); + return Task.CompletedTask; + } - private void FileChanged(FileInfo file) - { - _ = _commandSystem.UnloadFileAsync(file.FullName); - _ = _commandSystem.LoadFileAsync(file.FullName); - } + private void FoundFile(FileInfo file) + { + _ = _commandSystem.LoadFileAsync(file.FullName); + } - private void FileDeleted(FileInfo file) - { - _ = _commandSystem.UnloadFileAsync(file.FullName); - } + private void FileChanged(FileInfo file) + { + _ = _commandSystem.UnloadFileAsync(file.FullName); + _ = _commandSystem.LoadFileAsync(file.FullName); + } - private readonly ICommandSystemService _commandSystem; + private void FileDeleted(FileInfo file) + { + _ = _commandSystem.UnloadFileAsync(file.FullName); + } - private readonly string _path; - private readonly string _filter; - private readonly IFileMonitoringService _fileMonitor; -} + private readonly ICommandSystemService _commandSystem; + + private readonly string _path; + private readonly string _filter; + private readonly IFileMonitoringService _fileMonitor; + } +} \ No newline at end of file diff --git a/src/cs/CommandSet/CommandSetFactories/TextReaderCommandSetFactory.cs b/src/cs/CommandSet/CommandSetFactories/TextReaderCommandSetFactory.cs index d0edf77c..6e119193 100644 --- a/src/cs/CommandSet/CommandSetFactories/TextReaderCommandSetFactory.cs +++ b/src/cs/CommandSet/CommandSetFactories/TextReaderCommandSetFactory.cs @@ -1,32 +1,36 @@ using Microsoft.Extensions.DependencyInjection; +using System; +using System.IO; +using System.Threading.Tasks; -namespace macaroni; - -internal class TextReaderCommandSetFactory : ICommandSetFactory +namespace macaroni { - public TextReaderCommandSetFactory(IServiceProvider services, string documentName, TextReader reader) + internal class TextReaderCommandSetFactory : ICommandSetFactory { - _commandSystem = services.GetRequiredService(); - _name = documentName; - _reader = reader; - } + public TextReaderCommandSetFactory(IServiceProvider services, string documentName, TextReader reader) + { + _commandSystem = services.GetRequiredService(); + _name = documentName; + _reader = reader; + } - public Task StartAsync() - { - return Task.Run(() => + public Task StartAsync() { - _commandSystem.LoadFileAsync(_name, _reader); - }); - } + return Task.Run(() => + { + _commandSystem.LoadFileAsync(_name, _reader); + }); + } - public Task StopAsync() - { - _commandSystem.UnloadFileAsync(_name); - return Task.CompletedTask; - } + public Task StopAsync() + { + _commandSystem.UnloadFileAsync(_name); + return Task.CompletedTask; + } - private readonly ICommandSystemService _commandSystem; + private readonly ICommandSystemService _commandSystem; - private readonly string _name; - private readonly TextReader _reader; -} + private readonly string _name; + private readonly TextReader _reader; + } +} \ No newline at end of file diff --git a/src/cs/CommandSet/CommandSetYamlParser.cs b/src/cs/CommandSet/CommandSetYamlParser.cs index bf4d1b1d..d2beafb3 100644 --- a/src/cs/CommandSet/CommandSetYamlParser.cs +++ b/src/cs/CommandSet/CommandSetYamlParser.cs @@ -1,214 +1,220 @@ -namespace macaroni; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using YamlDotNet.RepresentationModel; -internal class CommandSetYamlParser : YamlParserBase, ICommandSetYamlParser +namespace macaroni { - public CommandSetYamlParser(ICommandSystemService commandSystem, IYamlValueCollectionYamlParser valuesParser, IConditionCollectionYamlParser conditionsParser, ITriggerCollectionYamlParser triggersParser, IExecutorCollectionYamlParser executorsParser, INuggetCollectionYamlParser nuggetsParser, ISystemContext context) : base(context) + internal class CommandSetYamlParser : YamlParserBase, ICommandSetYamlParser { - _commandSystem = commandSystem; - _valuesParser = valuesParser; - - _conditionsParser = conditionsParser; - _triggersParser = triggersParser; - _executorsParser = executorsParser; - - _nuggetsParser = nuggetsParser; - } - - public IEnumerable Parse(string file) - { - var fi = new FileInfo(file); - if (!fi.Exists) throw ErrorParsingYamlException(file, "File not found"); + public CommandSetYamlParser(ICommandSystemService commandSystem, IYamlValueCollectionYamlParser valuesParser, IConditionCollectionYamlParser conditionsParser, ITriggerCollectionYamlParser triggersParser, IExecutorCollectionYamlParser executorsParser, INuggetCollectionYamlParser nuggetsParser, ISystemContext context) : base(context) + { + _commandSystem = commandSystem; + _valuesParser = valuesParser; - file = fi.FullName; - using var reader = File.OpenText(file); + _conditionsParser = conditionsParser; + _triggersParser = triggersParser; + _executorsParser = executorsParser; - return Parse(file, reader); - } + _nuggetsParser = nuggetsParser; + } - public IEnumerable Parse(string documentName, TextReader reader) - { - var parsed = ParseYamlStream(documentName, reader); - return LoadCommandSets(documentName, parsed); - } + public IEnumerable Parse(string file) + { + var fi = new FileInfo(file); + if (!fi.Exists) throw ErrorParsingYamlException(file, "File not found"); - private IEnumerable LoadCommandSets(string file, YamlStream parsed) - { - var commandSets = CommandSetsFromYamlStream(file, parsed); + file = fi.FullName; + using var reader = File.OpenText(file); - foreach (var commandSet in commandSets) - { - var loaded = commandSet as ILoadedFromYamlFile; - loaded?.LoadComplete(_commandSystem); + return Parse(file, reader); } - return commandSets; - } - - private IEnumerable CommandSetsFromYamlStream(string file, YamlStream parsed) - { - var commandSets = new List(); - foreach (var document in parsed.Documents) + public IEnumerable Parse(string documentName, TextReader reader) { - var fromDocument = CommandSetFromYamlDocument(file, document); - commandSets.Add(fromDocument); + var parsed = ParseYamlStream(documentName, reader); + return LoadCommandSets(documentName, parsed); } - return commandSets; - } - private ICommandSet CommandSetFromYamlDocument(string file, YamlDocument document) - { - var root = document.RootNode; - var sequence = root as YamlSequenceNode; - if (sequence != null) return CommandSetFromRootYamlSequence(file, sequence); - - var mapping = root as YamlMappingNode; - if (mapping != null) return CommandSetFromRootYamlMapping(file, mapping); + private IEnumerable LoadCommandSets(string file, YamlStream parsed) + { + var commandSets = CommandSetsFromYamlStream(file, parsed); - throw ErrorParsingYamlException(file, root.Start.Line, root.Start.Column, $"Unexpected node type ({root.GetType().Name})", "EXPECTED: `execute: {sequence}` or `commands: {sequence}`"); - } + foreach (var commandSet in commandSets) + { + var loaded = commandSet as ILoadedFromYamlFile; + loaded?.LoadComplete(_commandSystem); + } - private ICommandSet CommandSetFromRootYamlSequence(string file, YamlSequenceNode sequence) - { - var keyword = string.Empty; + return commandSets; + } - var commands = CommandsFromYamlSequence(file, sequence, null); - return new CommandSet() { Keyword = keyword, Commands = commands, Yaml = sequence, YamlFile = file }; - } + private IEnumerable CommandSetsFromYamlStream(string file, YamlStream parsed) + { + var commandSets = new List(); + foreach (var document in parsed.Documents) + { + var fromDocument = CommandSetFromYamlDocument(file, document); + commandSets.Add(fromDocument); + } + return commandSets; + } - private ICommandSet CommandSetFromRootYamlMapping(string file, YamlMappingNode mapping) - { - var keyword = GetScalarString(file, mapping, "keyword", null, null); - var values = _valuesParser.CheckForValues(file, mapping, "values", null); + private ICommandSet CommandSetFromYamlDocument(string file, YamlDocument document) + { + var root = document.RootNode; + var sequence = root as YamlSequenceNode; + if (sequence != null) return CommandSetFromRootYamlSequence(file, sequence); - var warnings = CreateParsedValueWarningChecker(values); + var mapping = root as YamlMappingNode; + if (mapping != null) return CommandSetFromRootYamlMapping(file, mapping); - var conditions = _conditionsParser.CheckForConditions(file, mapping, "conditions", warnings); - var nuggets = _nuggetsParser.CheckForNuggets(file, mapping, "nuggets"); + throw ErrorParsingYamlException(file, root.Start.Line, root.Start.Column, $"Unexpected node type ({root.GetType().Name})", "EXPECTED: `execute: {sequence}` or `commands: {sequence}`"); + } - var commands = CheckForCommands(file, mapping, "commands", warnings); - if (commands != null) + private ICommandSet CommandSetFromRootYamlSequence(string file, YamlSequenceNode sequence) { - return new CommandSet() { Nuggets = nuggets, Values = values, Conditions = conditions, Keyword = keyword, Commands = commands, Yaml = mapping, YamlFile = file, Warnings = warnings?.Warnings }; + var keyword = string.Empty; + + var commands = CommandsFromYamlSequence(file, sequence, null); + return new CommandSet() { Keyword = keyword, Commands = commands, Yaml = sequence, YamlFile = file }; } - var command = CheckForCommand(file, mapping, warnings); - if (command != null) + private ICommandSet CommandSetFromRootYamlMapping(string file, YamlMappingNode mapping) { - return new CommandSet() { Nuggets = nuggets, Values = values, Conditions = conditions, Keyword = keyword, Commands = new[] { command }, Yaml = mapping, YamlFile = file, Warnings = warnings?.Warnings }; - } + var keyword = GetScalarString(file, mapping, "keyword", null, null); + var values = _valuesParser.CheckForValues(file, mapping, "values", null); - throw ErrorParsingYamlException(file, mapping.Start.Line, mapping.Start.Column, "Unexpected YamlMappingNode", "EXPECTED: `execute: {sequence}` or `commands: {sequence}`"); - } + var warnings = CreateParsedValueWarningChecker(values); - private static ParsedValueWarningChecker? CreateParsedValueWarningChecker(IYamlValueCollection? values) - { - var externs = values?.ContainsKey("extern") == true - ? values["extern"]?.Value as IEnumerable - : null; + var conditions = _conditionsParser.CheckForConditions(file, mapping, "conditions", warnings); + var nuggets = _nuggetsParser.CheckForNuggets(file, mapping, "nuggets"); - externs = externs ?? Enumerable.Empty(); - return new ParsedValueWarningChecker(externs); - } + var commands = CheckForCommands(file, mapping, "commands", warnings); + if (commands != null) + { + return new CommandSet() { Nuggets = nuggets, Values = values, Conditions = conditions, Keyword = keyword, Commands = commands, Yaml = mapping, YamlFile = file, Warnings = warnings?.Warnings }; + } - private IEnumerable? CheckForCommands(string file, YamlMappingNode mapping, string commandsMappingName, IParsedValueWarningChecker? warnings) - { - var sequence = mapping.Children.ContainsKey(commandsMappingName) - ? mapping.Children[commandsMappingName] as YamlSequenceNode - : null; - return sequence != null - ? CommandsFromYamlSequence(file, sequence, warnings) - : null; - } + var command = CheckForCommand(file, mapping, warnings); + if (command != null) + { + return new CommandSet() { Nuggets = nuggets, Values = values, Conditions = conditions, Keyword = keyword, Commands = new[] { command }, Yaml = mapping, YamlFile = file, Warnings = warnings?.Warnings }; + } - private IEnumerable CommandsFromYamlSequence(string file, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) - { - var commands = RequireSequenceOf(file, sequence, - "command", - (file, node) => CommandFromYamlNode(file, node, warnings), - (file, node) => ErrorUnexpectedNode(file, node, "{command sequence}")); + throw ErrorParsingYamlException(file, mapping.Start.Line, mapping.Start.Column, "Unexpected YamlMappingNode", "EXPECTED: `execute: {sequence}` or `commands: {sequence}`"); + } - return commands; - } + private static ParsedValueWarningChecker? CreateParsedValueWarningChecker(IYamlValueCollection? values) + { + var externs = values?.ContainsKey("extern") == true + ? values["extern"]?.Value as IEnumerable + : null; - private ICommand CommandFromYamlNode(string file, YamlNode node, IParsedValueWarningChecker? warnings) - { - var mapping = node as YamlMappingNode; - if (mapping != null) + externs = externs ?? Enumerable.Empty(); + return new ParsedValueWarningChecker(externs); + } + + private IEnumerable? CheckForCommands(string file, YamlMappingNode mapping, string commandsMappingName, IParsedValueWarningChecker? warnings) { - var command = CheckForCommand(file, mapping, warnings); - if (command != null) return command; + var sequence = mapping.Children.ContainsKey(commandsMappingName) + ? mapping.Children[commandsMappingName] as YamlSequenceNode + : null; + return sequence != null + ? CommandsFromYamlSequence(file, sequence, warnings) + : null; } - var message = $"Unexpected node type ({node.GetType().Name})"; - var expected = "{a command, e.g. `triggers: {sequence}` AND `execute: {sequence}}"; - throw ErrorParsingYamlException(file, node.Start.Line, node.Start.Column, message, expected); - } + private IEnumerable CommandsFromYamlSequence(string file, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) + { + var commands = RequireSequenceOf(file, sequence, + "command", + (file, node) => CommandFromYamlNode(file, node, warnings), + (file, node) => ErrorUnexpectedNode(file, node, "{command sequence}")); - private ICommand? CheckForCommand(string file, YamlMappingNode mapping, IParsedValueWarningChecker? warnings) - { - return mapping.Children.ContainsKey("triggers") && mapping.Children.ContainsKey("execute") - ? CommandFromYamlMapping(file, mapping, warnings) - : null; - } + return commands; + } - private ICommand CommandFromYamlMapping(string file, YamlMappingNode mapping, IParsedValueWarningChecker? warnings) - { - var invalid = mapping.Children.Where(x => IsInvalidCommandChildNodeMappingKey(x.Key)); - if (invalid.Count() > 0) + private ICommand CommandFromYamlNode(string file, YamlNode node, IParsedValueWarningChecker? warnings) { - var first = invalid.First(); - var key = (first.Key as YamlScalarNode)?.Value ?? first.Key.ToString(); - var expected = GetValidCommandChildrenTypes(); - var message = - $" FOUND: {key}\n" + - $"EXPECTED: {expected}"; - throw ErrorParsingYamlException(file, first.Key.Start.Line, first.Key.Start.Column, "Unexpected node mapping", message); + var mapping = node as YamlMappingNode; + if (mapping != null) + { + var command = CheckForCommand(file, mapping, warnings); + if (command != null) return command; + } + + var message = $"Unexpected node type ({node.GetType().Name})"; + var expected = "{a command, e.g. `triggers: {sequence}` AND `execute: {sequence}}"; + throw ErrorParsingYamlException(file, node.Start.Line, node.Start.Column, message, expected); } - var name = GetScalarString(file, mapping, "name", null, warnings) ?? GetDefaultCommandName(); - - var example = GetScalarStrings(file, mapping, "example", warnings); - var examples = GetScalarStrings(file, mapping, "examples", warnings) ?? example; + private ICommand? CheckForCommand(string file, YamlMappingNode mapping, IParsedValueWarningChecker? warnings) + { + return mapping.Children.ContainsKey("triggers") && mapping.Children.ContainsKey("execute") + ? CommandFromYamlMapping(file, mapping, warnings) + : null; + } - var conditions = _conditionsParser.CheckForConditions(file, mapping, "conditions", warnings); - var triggers = _triggersParser.CheckForTriggers(file, mapping, "triggers", warnings); - var executors = _executorsParser.CheckForExecutors(file, mapping, "execute", warnings); + private ICommand CommandFromYamlMapping(string file, YamlMappingNode mapping, IParsedValueWarningChecker? warnings) + { + var invalid = mapping.Children.Where(x => IsInvalidCommandChildNodeMappingKey(x.Key)); + if (invalid.Count() > 0) + { + var first = invalid.First(); + var key = (first.Key as YamlScalarNode)?.Value ?? first.Key.ToString(); + var expected = GetValidCommandChildrenTypes(); + var message = + $" FOUND: {key}\n" + + $"EXPECTED: {expected}"; + throw ErrorParsingYamlException(file, first.Key.Start.Line, first.Key.Start.Column, "Unexpected node mapping", message); + } + + var name = GetScalarString(file, mapping, "name", null, warnings) ?? GetDefaultCommandName(); + + var example = GetScalarStrings(file, mapping, "example", warnings); + var examples = GetScalarStrings(file, mapping, "examples", warnings) ?? example; + + var conditions = _conditionsParser.CheckForConditions(file, mapping, "conditions", warnings); + var triggers = _triggersParser.CheckForTriggers(file, mapping, "triggers", warnings); + var executors = _executorsParser.CheckForExecutors(file, mapping, "execute", warnings); + + return new Command() + { + Name = name, + Examples = examples, + Conditions = conditions, + Triggers = triggers, + Executors = executors, + + Yaml = mapping, + YamlFile = file + }; + } - return new Command() + private string GetDefaultCommandName() { - Name = name, - Examples = examples, - Conditions = conditions, - Triggers = triggers, - Executors = executors, + return string.Empty; + } - Yaml = mapping, - YamlFile = file - }; - } + private static string GetValidCommandChildrenTypes() + { + return string.Join(", ", _validCommandNodeMappingKeys); + } - private string GetDefaultCommandName() - { - return string.Empty; - } + private bool IsInvalidCommandChildNodeMappingKey(YamlNode child) + { + var key = (child as YamlScalarNode)?.Value; + return string.IsNullOrEmpty(key) || !_validCommandNodeMappingKeys.Contains(key); + } - private static string GetValidCommandChildrenTypes() - { - return string.Join(", ", _validCommandNodeMappingKeys); - } + private readonly ICommandSystemService _commandSystem; + private readonly IYamlValueCollectionYamlParser _valuesParser; + private readonly IConditionCollectionYamlParser _conditionsParser; + private readonly ITriggerCollectionYamlParser _triggersParser; + private readonly IExecutorCollectionYamlParser _executorsParser; + private readonly INuggetCollectionYamlParser _nuggetsParser; - private bool IsInvalidCommandChildNodeMappingKey(YamlNode child) - { - var key = (child as YamlScalarNode)?.Value; - return string.IsNullOrEmpty(key) || !_validCommandNodeMappingKeys.Contains(key); + private static IEnumerable _validCommandNodeMappingKeys = new string[] { "name", "example", "examples", "conditions", "triggers", "execute" }; } - - private readonly ICommandSystemService _commandSystem; - private readonly IYamlValueCollectionYamlParser _valuesParser; - private readonly IConditionCollectionYamlParser _conditionsParser; - private readonly ITriggerCollectionYamlParser _triggersParser; - private readonly IExecutorCollectionYamlParser _executorsParser; - private readonly INuggetCollectionYamlParser _nuggetsParser; - - private static IEnumerable _validCommandNodeMappingKeys = new string[] { "name", "example", "examples", "conditions", "triggers", "execute" }; -} +} \ No newline at end of file diff --git a/src/cs/CommandSet/YamlValues/DynamicFileListYamlValue.cs b/src/cs/CommandSet/YamlValues/DynamicFileListYamlValue.cs index f51f51b5..464c7feb 100644 --- a/src/cs/CommandSet/YamlValues/DynamicFileListYamlValue.cs +++ b/src/cs/CommandSet/YamlValues/DynamicFileListYamlValue.cs @@ -1,84 +1,88 @@ -using System.Diagnostics; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using YamlDotNet.RepresentationModel; -namespace macaroni; - -internal class DynamicFileListYamlValue : IYamlValue, ILoadedFromYamlFile +namespace macaroni { - public DynamicFileListYamlValue(string name) + internal class DynamicFileListYamlValue : IYamlValue, ILoadedFromYamlFile { - Name = name; - } - - public string? Folder { get; set; } - public string? Pattern { get; set; } - public string? Recursive { get; set; } - public string? ExpandPhrases { get; set; } + public DynamicFileListYamlValue(string name) + { + Name = name; + } - public YamlNode? Yaml { get; set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } + public string? Folder { get; set; } + public string? Pattern { get; set; } + public string? Recursive { get; set; } + public string? ExpandPhrases { get; set; } - public string Name { get; internal set; } - public object? Value => _values; + public YamlNode? Yaml { get; set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public void LoadComplete(object parent) - { - YamlParent = parent; + public string Name { get; internal set; } + public object? Value => _values; - if (!this.IsEditorDesignMode()) + public void LoadComplete(object parent) { - var commandSet = this.GetRequiredParentOrService(); - var context = commandSet.CreateExecutionContext(); - - var folder = context.Resolve(Folder) ?? "."; - var pattern = context.Resolve(Pattern) ?? "*.*"; - var recursive = context.Resolve(Recursive) ?? "true"; - var expandPhrases = context.Resolve(ExpandPhrases) ?? "false"; - - _fileMonitor = this.GetRequiredParentOrService(); - _fileMonitor.StartNotify( - folder, - pattern, - _ => {}, - _ => {}, - _ => {}, - updatedFileList => UpdateFileList(updatedFileList, expandPhrases == "true")); + YamlParent = parent; + + if (!this.IsEditorDesignMode()) + { + var commandSet = this.GetRequiredParentOrService(); + var context = commandSet.CreateExecutionContext(); + + var folder = context.Resolve(Folder) ?? "."; + var pattern = context.Resolve(Pattern) ?? "*.*"; + var recursive = context.Resolve(Recursive) ?? "true"; + var expandPhrases = context.Resolve(ExpandPhrases) ?? "false"; + + _fileMonitor = this.GetRequiredParentOrService(); + _fileMonitor.StartNotify( + folder, + pattern, + _ => { }, + _ => { }, + _ => { }, + updatedFileList => UpdateFileList(updatedFileList, expandPhrases == "true")); + } } - } - public void Unload() - { - } + public void Unload() + { + } - private void UpdateFileList(IEnumerable updatedFileList, bool expandPhrases) - { - if (_files == null || !_files.SetEquals(updatedFileList)) + private void UpdateFileList(IEnumerable updatedFileList, bool expandPhrases) { - var firstUpdate = _files == null; + if (_files == null || !_files.SetEquals(updatedFileList)) + { + var firstUpdate = _files == null; - _files = updatedFileList.ToHashSet(); - _values = updatedFileList.SelectMany(x => NameValueSyntaxFromFileInfo(x, expandPhrases)).ToList(); + _files = updatedFileList.ToHashSet(); + _values = updatedFileList.SelectMany(x => NameValueSyntaxFromFileInfo(x, expandPhrases)).ToList(); - if (!firstUpdate) NotifyValueChanged(); + if (!firstUpdate) NotifyValueChanged(); + } } - } - private static IEnumerable NameValueSyntaxFromFileInfo(FileInfo x, bool expandPhrases) - { - yield return $"{x.Name}: {x.FullName}"; - if (expandPhrases) + private static IEnumerable NameValueSyntaxFromFileInfo(FileInfo x, bool expandPhrases) { - yield return $"{Path.GetFileNameWithoutExtension(x.Name)}: {x.FullName}"; + yield return $"{x.Name}: {x.FullName}"; + if (expandPhrases) + { + yield return $"{Path.GetFileNameWithoutExtension(x.Name)}: {x.FullName}"; + } } - } - private void NotifyValueChanged() - { - var notify = YamlParent as INotifyYamlValues; - notify?.ValueChanged(this); - } + private void NotifyValueChanged() + { + var notify = YamlParent as INotifyYamlValues; + notify?.ValueChanged(this); + } - private HashSet? _files; - private IEnumerable? _values; - private IFileMonitoringService? _fileMonitor; -} + private HashSet? _files; + private IEnumerable? _values; + private IFileMonitoringService? _fileMonitor; + } +} \ No newline at end of file diff --git a/src/cs/CommandSet/YamlValues/DynamicFileListYamlValueYamlParser.cs b/src/cs/CommandSet/YamlValues/DynamicFileListYamlValueYamlParser.cs index 26da0fb2..25faa826 100644 --- a/src/cs/CommandSet/YamlValues/DynamicFileListYamlValueYamlParser.cs +++ b/src/cs/CommandSet/YamlValues/DynamicFileListYamlValueYamlParser.cs @@ -1,51 +1,54 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class DynamicFileListYamlValueYamlParser : YamlParserBase, IYamlValueYamlParser +namespace macaroni { - public DynamicFileListYamlValueYamlParser(ISystemContext context) : base(context) { } - - public string Kind { get { return "files"; } } - - public IYamlValue Parse(string file, string name, YamlNode value, IParsedValueWarningChecker? warnings) + internal class DynamicFileListYamlValueYamlParser : YamlParserBase, IYamlValueYamlParser { - var scalar = value as YamlScalarNode; - if (scalar != null) return ParseScalar(file, name, scalar, warnings); - - var mapping = value as YamlMappingNode; - if (mapping != null) return ParseMapping(file, name, mapping, warnings); + public DynamicFileListYamlValueYamlParser(ISystemContext context) : base(context) { } - throw ExpectedMappingOrStringValueException(file, Kind, value); - } + public string Kind { get { return "files"; } } - private IYamlValue ParseScalar(string file, string name, YamlScalarNode scalar, IParsedValueWarningChecker? warnings) - { - return new DynamicFileListYamlValue(name) + public IYamlValue Parse(string file, string name, YamlNode value, IParsedValueWarningChecker? warnings) { - Folder = RequireScalarStringValueNotNullOrEmpty(file, Kind, scalar, warnings), - Yaml = scalar, - YamlFile = file - }; - } + var scalar = value as YamlScalarNode; + if (scalar != null) return ParseScalar(file, name, scalar, warnings); - private IYamlValue ParseMapping(string file, string name, YamlMappingNode mapping, IParsedValueWarningChecker? warnings) - { - var folder = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "folder", warnings); - var pattern = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "pattern", warnings); - var recursive = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "recursive", warnings); - var expandPhrases = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "expandPhrases", warnings); + var mapping = value as YamlMappingNode; + if (mapping != null) return ParseMapping(file, name, mapping, warnings); - var recursiveOk = bool.TryParse(recursive, out bool recursiveValue); + throw ExpectedMappingOrStringValueException(file, Kind, value); + } - var value = new DynamicFileListYamlValue(name) + private IYamlValue ParseScalar(string file, string name, YamlScalarNode scalar, IParsedValueWarningChecker? warnings) + { + return new DynamicFileListYamlValue(name) + { + Folder = RequireScalarStringValueNotNullOrEmpty(file, Kind, scalar, warnings), + Yaml = scalar, + YamlFile = file + }; + } + + private IYamlValue ParseMapping(string file, string name, YamlMappingNode mapping, IParsedValueWarningChecker? warnings) { - Folder = folder, - Pattern = pattern, - Recursive = recursiveOk ? recursiveValue.ToString() : null, - ExpandPhrases = expandPhrases, - Yaml = mapping, - YamlFile = file - }; - - return value; + var folder = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "folder", warnings); + var pattern = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "pattern", warnings); + var recursive = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "recursive", warnings); + var expandPhrases = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "expandPhrases", warnings); + + var recursiveOk = bool.TryParse(recursive, out bool recursiveValue); + + var value = new DynamicFileListYamlValue(name) + { + Folder = folder, + Pattern = pattern, + Recursive = recursiveOk ? recursiveValue.ToString() : null, + ExpandPhrases = expandPhrases, + Yaml = mapping, + YamlFile = file + }; + + return value; + } } -} +} \ No newline at end of file diff --git a/src/cs/CommandSet/YamlValues/StaticStringYamlValue.cs b/src/cs/CommandSet/YamlValues/StaticStringYamlValue.cs index d91d0be5..d52f3b19 100644 --- a/src/cs/CommandSet/YamlValues/StaticStringYamlValue.cs +++ b/src/cs/CommandSet/YamlValues/StaticStringYamlValue.cs @@ -1,3 +1,6 @@ +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; + namespace macaroni { public class StaticStringYamlValue : IYamlValue, ILoadedFromYamlFile @@ -16,12 +19,12 @@ public StaticStringYamlValue(string name, IEnumerable? values) string IYamlValue.Name { get => _name; } - object? IYamlValue.Value { get => _value != null ? _value : _values; } + object? IYamlValue.Value { get => _value != null ? (object?)_value : _values; } public YamlNode? Yaml { get; set; } public string? YamlFile { get; internal set; } public object? YamlParent { get; internal set; } - + public void LoadComplete(object parent) { YamlParent = parent; diff --git a/src/cs/CommandSet/YamlValues/YamlValueCollection.cs b/src/cs/CommandSet/YamlValues/YamlValueCollection.cs index d860c14f..d9511dbb 100644 --- a/src/cs/CommandSet/YamlValues/YamlValueCollection.cs +++ b/src/cs/CommandSet/YamlValues/YamlValueCollection.cs @@ -1,40 +1,44 @@ -namespace macaroni; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class YamlValueCollection : Dictionary, IYamlValueCollection, INotifyYamlValues, ILoadedFromYamlFile +namespace macaroni { - public YamlValueCollection(IDictionary values) : base(values) + internal class YamlValueCollection : Dictionary, IYamlValueCollection, INotifyYamlValues, ILoadedFromYamlFile { - } + public YamlValueCollection(IDictionary values) : base(values) + { + } - public YamlNode? Yaml { get; internal set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) - { - YamlParent = parent; - if (Yaml == null) Yaml = (parent as ILoadedFromYamlFile)?.Yaml; - if (YamlFile == null) YamlFile = (parent as ILoadedFromYamlFile)?.YamlFile; + public YamlNode? Yaml { get; internal set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - foreach (var value in this.Values) + public void LoadComplete(object parent) { - (value as ILoadedFromYamlFile)?.LoadComplete(this); - (value.Value as ILoadedFromYamlFile)?.LoadComplete(this); + YamlParent = parent; + if (Yaml == null) Yaml = (parent as ILoadedFromYamlFile)?.Yaml; + if (YamlFile == null) YamlFile = (parent as ILoadedFromYamlFile)?.YamlFile; + + foreach (var value in this.Values) + { + (value as ILoadedFromYamlFile)?.LoadComplete(this); + (value.Value as ILoadedFromYamlFile)?.LoadComplete(this); + } } - } - public void Unload() - { - foreach (var value in this.Values) + public void Unload() { - (value as ILoadedFromYamlFile)?.Unload(); - (value.Value as ILoadedFromYamlFile)?.Unload(); + foreach (var value in this.Values) + { + (value as ILoadedFromYamlFile)?.Unload(); + (value.Value as ILoadedFromYamlFile)?.Unload(); + } } - } - public void ValueChanged(IYamlValue value) - { - var notify = YamlParent as INotifyYamlValues; - notify?.ValueChanged(value); + public void ValueChanged(IYamlValue value) + { + var notify = YamlParent as INotifyYamlValues; + notify?.ValueChanged(value); + } } -} +} \ No newline at end of file diff --git a/src/cs/CommandSet/YamlValues/YamlValueCollectionYamlParser.cs b/src/cs/CommandSet/YamlValues/YamlValueCollectionYamlParser.cs index 1876ef92..9867c4ad 100644 --- a/src/cs/CommandSet/YamlValues/YamlValueCollectionYamlParser.cs +++ b/src/cs/CommandSet/YamlValues/YamlValueCollectionYamlParser.cs @@ -1,38 +1,42 @@ -namespace macaroni; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class YamlValueCollectionYamlParser : YamlParserBase, IYamlValueCollectionYamlParser +namespace macaroni { - public YamlValueCollectionYamlParser(IYamlValueFactory factory, ISystemContext context) : base(context) + internal class YamlValueCollectionYamlParser : YamlParserBase, IYamlValueCollectionYamlParser { - _factory = factory; - } - - public IYamlValueCollection? CheckForValues(string file, YamlMappingNode mapping, string valuesMappingName, IParsedValueWarningChecker? warnings) - { - var values = mapping.Children.ContainsKey(valuesMappingName) - ? mapping.Children[valuesMappingName] as YamlMappingNode - : null; - return values != null - ? ValuesFromYamlMapping(file, values, warnings) - : null; - } + public YamlValueCollectionYamlParser(IYamlValueFactory factory, ISystemContext context) : base(context) + { + _factory = factory; + } - public IYamlValueCollection ValuesFromYamlMapping(string file, YamlMappingNode mapping, IParsedValueWarningChecker? warnings) - { - var values = new Dictionary(); + public IYamlValueCollection? CheckForValues(string file, YamlMappingNode mapping, string valuesMappingName, IParsedValueWarningChecker? warnings) + { + var values = mapping.Children.ContainsKey(valuesMappingName) + ? mapping.Children[valuesMappingName] as YamlMappingNode + : null; + return values != null + ? ValuesFromYamlMapping(file, values, warnings) + : null; + } - foreach (var node in mapping.Children) + public IYamlValueCollection ValuesFromYamlMapping(string file, YamlMappingNode mapping, IParsedValueWarningChecker? warnings) { - var name = (node.Key as YamlScalarNode)?.Value; - var value = name != null - ? _factory.ValueFromYamlNode(file, name, node.Value, warnings) - : throw ExpectedStringValue(file, node.Key); + var values = new Dictionary(); - values.Add(value.Name, value); + foreach (var node in mapping.Children) + { + var name = (node.Key as YamlScalarNode)?.Value; + var value = name != null + ? _factory.ValueFromYamlNode(file, name, node.Value, warnings) + : throw ExpectedStringValue(file, node.Key); + + values.Add(value.Name, value); + } + + return new YamlValueCollection(values) { Yaml = mapping, YamlFile = file, }; } - return new YamlValueCollection(values) { Yaml = mapping, YamlFile = file, }; + private IYamlValueFactory _factory; } - - private IYamlValueFactory _factory; -} +} \ No newline at end of file diff --git a/src/cs/CommandSet/YamlValues/YamlValueFactory.cs b/src/cs/CommandSet/YamlValues/YamlValueFactory.cs index 61337139..82a32c36 100644 --- a/src/cs/CommandSet/YamlValues/YamlValueFactory.cs +++ b/src/cs/CommandSet/YamlValues/YamlValueFactory.cs @@ -1,67 +1,72 @@ -namespace macaroni; +using System.Collections.Generic; +using System.Linq; +using YamlDotNet.RepresentationModel; -internal class YamlValueFactory : YamlParserBase, IYamlValueFactory +namespace macaroni { - public YamlValueFactory(IEnumerable parsers, ISystemContext context) : base(context) + internal class YamlValueFactory : YamlParserBase, IYamlValueFactory { - _parsers = parsers; - } - - public IYamlValue ValueFromYamlNode(string file, string name, YamlNode node, IParsedValueWarningChecker? warnings) - { - var scalar = node as YamlScalarNode; - if (scalar != null) + public YamlValueFactory(IEnumerable parsers, ISystemContext context) : base(context) { - return new StaticStringYamlValue(name, scalar.Value) { Yaml = node, YamlFile = file }; + _parsers = parsers; } - var sequence = node as YamlSequenceNode; - if (sequence != null) + public IYamlValue ValueFromYamlNode(string file, string name, YamlNode node, IParsedValueWarningChecker? warnings) { - return new StaticStringYamlValue(name, GetScalarStrings(file, sequence, warnings)) { Yaml = node, YamlFile = file }; - } + var scalar = node as YamlScalarNode; + if (scalar != null) + { + return new StaticStringYamlValue(name, scalar.Value) { Yaml = node, YamlFile = file }; + } - var mapping = node as YamlMappingNode; - if (mapping != null) - { - if (IsInvalidValueNode(mapping)) + var sequence = node as YamlSequenceNode; + if (sequence != null) { - var expected = GetValidValueMappingTypes(); - throw ErrorParsingYamlException(file, mapping.Start.Line, mapping.Start.Column, "Unexpected node mapping", $"EXPECTED: {expected}"); + return new StaticStringYamlValue(name, GetScalarStrings(file, sequence, warnings)) { Yaml = node, YamlFile = file }; } - return ParseValueFromMapping(file, name, mapping, warnings); - } + var mapping = node as YamlMappingNode; + if (mapping != null) + { + if (IsInvalidValueNode(mapping)) + { + var expected = GetValidValueMappingTypes(); + throw ErrorParsingYamlException(file, mapping.Start.Line, mapping.Start.Column, "Unexpected node mapping", $"EXPECTED: {expected}"); + } - throw ExpectedSequenceOrStringValueException(file, name, node); - } + return ParseValueFromMapping(file, name, mapping, warnings); + } - private bool IsInvalidValueNode(YamlMappingNode mapping) - { - var count = mapping.Children - .Count(x => _validValueMappingTypeKeys - .Contains((x.Key as YamlScalarNode)?.Value)); - return count == 0; - } + throw ExpectedSequenceOrStringValueException(file, name, node); + } - private IYamlValue ParseValueFromMapping(string file, string name, YamlMappingNode mapping, IParsedValueWarningChecker? warnings) - { - foreach (var parser in _parsers) + private bool IsInvalidValueNode(YamlMappingNode mapping) + { + var count = mapping.Children + .Count(x => _validValueMappingTypeKeys + .Contains((x.Key as YamlScalarNode)?.Value)); + return count == 0; + } + + private IYamlValue ParseValueFromMapping(string file, string name, YamlMappingNode mapping, IParsedValueWarningChecker? warnings) { - if (mapping.Children.ContainsKey(parser.Kind)) + foreach (var parser in _parsers) { - return parser.Parse(file, name, mapping.Children[parser.Kind], warnings); + if (mapping.Children.ContainsKey(parser.Kind)) + { + return parser.Parse(file, name, mapping.Children[parser.Kind], warnings); + } } + + return new StaticStringYamlValue(name, mapping.ToString()) { Yaml = mapping, YamlFile = file }; } - return new StaticStringYamlValue(name, mapping.ToString()) { Yaml = mapping, YamlFile = file }; - } + public string GetValidValueMappingTypes() + { + return string.Join(", ", _validValueMappingTypeKeys); + } - public string GetValidValueMappingTypes() - { - return string.Join(", ", _validValueMappingTypeKeys); + private IEnumerable _parsers; + private static IEnumerable _validValueMappingTypeKeys = new string[] { "files" }; } - - private IEnumerable _parsers; - private static IEnumerable _validValueMappingTypeKeys = new string[] { "files" }; -} +} \ No newline at end of file diff --git a/src/cs/CommandSystem/CommandSystem.cs b/src/cs/CommandSystem/CommandSystem.cs index c1e69792..db188c5b 100644 --- a/src/cs/CommandSystem/CommandSystem.cs +++ b/src/cs/CommandSystem/CommandSystem.cs @@ -1,216 +1,216 @@ -global using System; -global using System.Collections.Generic; -global using System.IO; -global using System.Linq; -global using System.Net.Http; -global using System.Threading; -global using System.Threading.Tasks; -using macaroni.Interfaces; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; - -namespace macaroni; - -public class CommandSystem : ICommandSystem +using Microsoft.Extensions.Hosting; +namespace macaroni { - public static ICommandSystemBuilder CreateBuilder() + public class CommandSystem : ICommandSystem { - var builder = new CommandSystemBuilder(); - return builder.ConfigureServices((context, services) => + public static ICommandSystemBuilder CreateBuilder() { - // command system - services.AddSingleton(); - services.AddSingleton(services => services.GetRequiredService()); - services.AddHostedService(services => services.GetRequiredService()); - - // command system settings - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - - // command system critical services - services.AddHostedService(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - - services.AddSingleton(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - - services.AddTransient(); - services.AddTransient(); - - services.AddSingleton(); - services.AddTransient(); - - // command set host, factory, and parser - services.AddHostedService(); - services.AddTransient(); - - // conditions/triggers/executor extensions - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - - // conditions/triggers/executors/values/nuggets collections and parsers - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - - // value factory and parsers - services.AddTransient(); - services.AddTransient(); - - // condition factory and parsers - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - - // trigger factory and parsers - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - - // executors factory and parsers - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - - // generic services (typically overridden by platform specific implementations) - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - - }); - } + var builder = new CommandSystemBuilder(); + return builder.ConfigureServices((context, services) => + { + // command system + services.AddSingleton(); + services.AddSingleton(services => services.GetRequiredService()); + services.AddHostedService(services => services.GetRequiredService()); + + // command system settings + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + + // command system critical services + services.AddHostedService(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + + services.AddSingleton(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + + services.AddTransient(); + services.AddTransient(); + + services.AddSingleton(); + services.AddTransient(); + + // command set host, factory, and parser + services.AddHostedService(); + services.AddTransient(); + + // conditions/triggers/executor extensions + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + + // conditions/triggers/executors/values/nuggets collections and parsers + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + + // value factory and parsers + services.AddTransient(); + services.AddTransient(); + + // condition factory and parsers + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + + // trigger factory and parsers + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + + // executors factory and parsers + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + + // generic services (typically overridden by platform specific implementations) + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + + }); + } + + internal CommandSystem(IHost host) + { + _host = host; + } - internal CommandSystem(IHost host) - { - _host = host; - } + public IServiceProvider Services => _host.Services; - public IServiceProvider Services => _host.Services; + public void Dispose() + { + _host.Dispose(); + } - public void Dispose() - { - _host.Dispose(); - } + public Task StartAsync(CancellationToken cancellationToken = default) => _host.StartAsync(cancellationToken); + public Task StopAsync(CancellationToken cancellationToken = default) => _host.StopAsync(cancellationToken); - public Task StartAsync(CancellationToken cancellationToken = default) => _host.StartAsync(cancellationToken); - public Task StopAsync(CancellationToken cancellationToken = default) => _host.StopAsync(cancellationToken); + public void SetContext(string name, object value) + { + var context = _host.Services.GetRequiredService(); + context.Set(name, value); + } - public void SetContext(string name, object value) - { - var context = _host.Services.GetRequiredService(); - context.Set(name, value); - } + public void BroadcastMessage(string name, string? value) + { + var broadcastService = Services.GetRequiredService(); + broadcastService.BroadcastMessage(name, value, null); + } - public void BroadcastMessage(string name, string? value) - { - var broadcastService = Services.GetRequiredService(); - broadcastService.BroadcastMessage(name, value, null); - } + public void EmulateSpeechRecognition(string text) + { + var service = Services.GetRequiredService(); + service.Emulate(text); + } - public void EmulateSpeechRecognition(string text) - { - var service = Services.GetRequiredService(); - service.Emulate(text); + private readonly IHost _host; } - - private readonly IHost _host; -} +} \ No newline at end of file diff --git a/src/cs/CommandSystem/CommandSystemService.cs b/src/cs/CommandSystem/CommandSystemService.cs index 032b094b..200f8a85 100644 --- a/src/cs/CommandSystem/CommandSystemService.cs +++ b/src/cs/CommandSystem/CommandSystemService.cs @@ -1,37 +1,42 @@ -using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; -namespace macaroni; - -internal class CommandSystemService : StartStopHelperBackgroundService, ICommandSystemService +namespace macaroni { - public CommandSystemService(IServiceProvider services) : base(services) + internal class CommandSystemService : StartStopHelperBackgroundService, ICommandSystemService { - EnsureStartLogging(services); - - MR.TRACE_INFO("Creating CommandSystemService"); - _serviceProvider = services; - _commandSets = new(); - } + public CommandSystemService(IServiceProvider services) : base(services) + { + EnsureStartLogging(services); - public IServiceProvider Services { get => _serviceProvider; } + MR.TRACE_INFO("Creating CommandSystemService"); + _serviceProvider = services; + _commandSets = new Dictionary>(); + } - protected override Task StartAsync() - { - var osd = Services.GetService(); - osd?.DisplayText("Starting macaroni...", "SYSTEM", true); + public IServiceProvider Services { get => _serviceProvider; } - return Task.CompletedTask; - } + protected override Task StartAsync() + { + var osd = Services.GetService(); + osd?.DisplayText("Starting macaroni...", "SYSTEM", true); - protected override Task StopAsync() - { - return Task.CompletedTask; - } + return Task.CompletedTask; + } - public Task LoadFileAsync(string file) - { - var parser = _serviceProvider.GetRequiredService(); + protected override Task StopAsync() + { + return Task.CompletedTask; + } + + public Task LoadFileAsync(string file) + { + var parser = _serviceProvider.GetRequiredService(); try { @@ -47,12 +52,12 @@ public Task LoadFileAsync(string file) BroadcastParsingException(new FileParseException($"ERROR: Parsing {file}", file, ex)); } - return Task.CompletedTask; - } + return Task.CompletedTask; + } - public Task LoadFileAsync(string documentName, TextReader reader) - { - var parser = _serviceProvider.GetRequiredService(); + public Task LoadFileAsync(string documentName, TextReader reader) + { + var parser = _serviceProvider.GetRequiredService(); try { @@ -68,96 +73,96 @@ public Task LoadFileAsync(string documentName, TextReader reader) BroadcastParsingException(new FileParseException($"ERROR: Parsing {documentName}", documentName, ex)); } - return Task.CompletedTask; - } - - public Task UnloadFileAsync(string file) - { - RemoveCommandSets(file); - return Task.CompletedTask; - } - - public IEnumerable? GetTips() - { - var tips = _commandSets - .SelectMany(kvp => kvp.Value) - .SelectMany(cs => cs.Commands ?? Enumerable.Empty()) - .Where(command => command.Name != null && command.Examples?.Count() > 0) - .Select(command => - $"{command.Name}" + - "\n\n" + - (command.Examples!.Count() == 1 ? "EXAMPLE:" : "EXAMPLE(s):") + - "\n" + - string.Join("\n", command.Examples!.Select(x => $"- {x}"))); - return tips; - } + return Task.CompletedTask; + } - private void AddCommandSets(IEnumerable commandSets) - { - foreach (var commandSet in commandSets) + public Task UnloadFileAsync(string file) { - AddCommandSet(commandSet); + RemoveCommandSets(file); + return Task.CompletedTask; } - } - private void AddCommandSet(ICommandSet commandSet) - { - string key = KeyFromCommandSet(commandSet); + public IEnumerable? GetTips() + { + var tips = _commandSets + .SelectMany(kvp => kvp.Value) + .SelectMany(cs => cs.Commands ?? Enumerable.Empty()) + .Where(command => command.Name != null && command.Examples?.Count() > 0) + .Select(command => + $"{command.Name}" + + "\n\n" + + (command.Examples!.Count() == 1 ? "EXAMPLE:" : "EXAMPLE(s):") + + "\n" + + string.Join("\n", command.Examples!.Select(x => $"- {x}"))); + return tips; + } - lock (_commandSets) + private void AddCommandSets(IEnumerable commandSets) { - if (!_commandSets.ContainsKey(key)) + foreach (var commandSet in commandSets) { - _commandSets[key] = new List(); + AddCommandSet(commandSet); } - _commandSets[key].Add(commandSet); } - commandSet.StartCommandSet(this); - } + private void AddCommandSet(ICommandSet commandSet) + { + string key = KeyFromCommandSet(commandSet); - private static string KeyFromCommandSet(ICommandSet commandSet) - { - var fromYaml = commandSet as ILoadedFromYamlFile; - return fromYaml?.YamlFile ?? commandSet.Id; - } + lock (_commandSets) + { + if (!_commandSets.ContainsKey(key)) + { + _commandSets[key] = new List(); + } + _commandSets[key].Add(commandSet); + } - private void RemoveCommandSets(string file) - { - if (_commandSets.TryGetValue(file, out var commandSetsForFile)) + commandSet.StartCommandSet(this); + } + + private static string KeyFromCommandSet(ICommandSet commandSet) { - commandSetsForFile.ForEach(x => x.StopCommandSet()); + var fromYaml = commandSet as ILoadedFromYamlFile; + return fromYaml?.YamlFile ?? commandSet.Id; } - lock (_commandSets) + private void RemoveCommandSets(string file) { - if (_commandSets.ContainsKey(file)) + if (_commandSets.TryGetValue(file, out var commandSetsForFile)) + { + commandSetsForFile.ForEach(x => x.StopCommandSet()); + } + + lock (_commandSets) { - _commandSets.Remove(file); + if (_commandSets.ContainsKey(file)) + { + _commandSets.Remove(file); + } } } - } - private static string GetParseErrorMessage(string file, Exception ex) - { - var lines = ex.Message.Split('\n'); - var error = lines[0]; - var context = lines.Count() > 1 && lines[1].Contains("FILE:") - ? lines[1].Trim() - : file; - - var slash = context.LastIndexOfAny(new[] { '/', '\\' }); - var paren = context.LastIndexOf('('); - context = (slash != -1 && paren != -1) - ? context.Substring(slash + 1) + "\n\n" - : slash != -1 - ? "in " + context.Substring(slash + 1) + "\n\n" - : "in " + file + "\n\n"; - - var message = string.Join("\n", lines.Skip(2).Select(line => line.Trim())).Trim(); - message = $"{error}\n\n{context}{message}"; - return message; - } + private static string GetParseErrorMessage(string file, Exception ex) + { + var lines = ex.Message.Split('\n'); + var error = lines[0]; + var context = lines.Count() > 1 && lines[1].Contains("FILE:") + ? lines[1].Trim() + : file; + + var slash = context.LastIndexOfAny(new[] { '/', '\\' }); + var paren = context.LastIndexOf('('); + context = (slash != -1 && paren != -1) + ? context.Substring(slash + 1) + "\n\n" + : slash != -1 + ? "in " + context.Substring(slash + 1) + "\n\n" + : "in " + file + "\n\n"; + + var message = string.Join("\n", lines.Skip(2).Select(line => line.Trim())).Trim(); + message = $"{error}\n\n{context}{message}"; + return message; + } private void BroadcastParsingException(FileParseException ex) { @@ -165,24 +170,25 @@ private void BroadcastParsingException(FileParseException ex) broadcast.BroadcastException(ExceptionKind.Parsing, ex); } - private static void EnsureStartLogging(IServiceProvider services) - { - try + private static void EnsureStartLogging(IServiceProvider services) { - var logFilePath = services.GetRequiredService()?.GetNamedState("__macaroni.logFilePath"); - if (!string.IsNullOrEmpty(logFilePath)) + try { - var logFileName = Path.Combine(logFilePath, $"macaroni.carbon-{DateTime.Now.ToFileTime()}.log"); - MR.DBG_TRACE_INFO($"Logging to {logFileName}..."); - Microsoft.CognitiveServices.Speech.Diagnostics.Logging.FileLogger.Start(logFileName); + var logFilePath = services.GetRequiredService()?.GetNamedState("__macaroni.logFilePath"); + if (!string.IsNullOrEmpty(logFilePath)) + { + var logFileName = Path.Combine(logFilePath, $"macaroni.carbon-{DateTime.Now.ToFileTime()}.log"); + MR.DBG_TRACE_INFO($"Logging to {logFileName}..."); + Microsoft.CognitiveServices.Speech.Diagnostics.Logging.FileLogger.Start(logFileName); + } + } + catch (Exception ex) + { + MR.DBG_TRACE_ERROR($"Failed to start logging: {ex.Message}"); } } - catch (Exception ex) - { - MR.DBG_TRACE_ERROR($"Failed to start logging: {ex.Message}"); - } - } - private readonly IServiceProvider _serviceProvider; - private readonly Dictionary> _commandSets; -} + private readonly IServiceProvider _serviceProvider; + private readonly Dictionary> _commandSets; + } +} \ No newline at end of file diff --git a/src/cs/CommandSystem/DeveloperSettings.cs b/src/cs/CommandSystem/DeveloperSettings.cs index 74b2abe0..9acb3941 100644 --- a/src/cs/CommandSystem/DeveloperSettings.cs +++ b/src/cs/CommandSystem/DeveloperSettings.cs @@ -1,82 +1,84 @@ -using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; -namespace macaroni; - -internal class DeveloperSettings : Dictionary, IDeveloperSettings +namespace macaroni { - public DeveloperSettings() - { - Init(); - } - - public void Set(string name, string value) + internal class DeveloperSettings : Dictionary, IDeveloperSettings { - try + public DeveloperSettings() { - this[name] = value; + Init(); } - catch (Exception) + + public void Set(string name, string value) { + try + { + this[name] = value; + } + catch (Exception) + { + } } - } - public string? Get(string name, string? defaultValue = null) - { - return this.ContainsKey(name) ? this[name] : defaultValue; - } - - private void Init() - { - // DEVELOPER: To ensure that we're not waiting for Azure KeyVault or connectivity to the internet, update your - // local source to set `developer=true` and replace `UPDATE_KEY_HERE` placeholders with actual keys that work. - - var developer = false; // !!IMPORTANT!! DO NOT CHECK IN this file with developer set to TRUE - if (developer) + public string? Get(string name, string? defaultValue = null) { - this.Add("KEY_VAULT_CLIENT_SECRET", "UPDATE_SECRET_HERE"); - this.Add("CLU_KEY", "UPDATE_KEY_HERE"); - this.Add("OPEN_AI_KEY", "UPDATE_KEY_HERE"); - this.Add("SPEECH_KEY", "UPDATE_KEY_HERE"); - this.Add("TRANSLATOR_KEY", "UPDATE_KEY_HERE"); - this.Add("VISION_KEY", "UPDATE_KEY_HERE"); - - this.Add("CLU_DEPLOYMENT_NAME", "v1"); - this.Add("CLU_ENDPOINT", "https://internal-gm-dev.cognitiveservices.azure.com"); - this.Add("CLU_PROJECT_NAME", "GM-Orchestrator"); - this.Add("OPEN_AI_DEPLOYMENT", "robch-southcentral-oai-txtdav002"); - this.Add("OPEN_AI_ENDPOINT", "https://robch-openai.openai.azure.com/"); - this.Add("SPEECH_REGION", "westus"); - this.Add("SPEECH_RECOGNITION_ENDPOINT", ""); - this.Add("SPEECH_SYNTHESIS_ENDPOINT", ""); - this.Add("SPEECH_CUSTOM_RECOGNITION_ENDPOINT_ID", ""); - this.Add("SPEECH_CUSTOM_SYNTHESIS_ENDPOINT_ID", ""); - this.Add("TRANSLATOR_ENDPOINT", "https://api.cognitive.microsofttranslator.com/"); - this.Add("TRANSLATOR_REGION", "westus"); - this.Add("VISION_DEFAULT_LANGUAGE", "en"); - this.Add("VISION_ENDPOINT", "https://carbon-vision.cognitiveservices.azure.com"); + return this.ContainsKey(name) ? this[name] : defaultValue; } - // DEVELOPER: To use Embedded speech (SR and TTS), update your local source to set `embedded=true` and replace - // `UPDATE_PATH_HERE` placeholders with appropriate locations where the model data files can be found - - var embedded = false; // !!!IMPORTANT!!!: DO NOT CHECK IN this file with embedded set to TRUE - if (embedded) // also update true/false in `csproj` files + private void Init() { - if (OS.IsWindows()) + // DEVELOPER: To ensure that we're not waiting for Azure KeyVault or connectivity to the internet, update your + // local source to set `developer=true` and replace `UPDATE_KEY_HERE` placeholders with actual keys that work. + + var developer = false; // !!IMPORTANT!! DO NOT CHECK IN this file with developer set to TRUE + if (developer) { - this.Add("EMBEDDED_SPEECH_RECOGNITION_MODEL_PATH", @"UPDATE_PATH_HERE"); // e.g. @"D:\src\macaroni\external\embedded_sr_model_FP_en-US_V8_onnx"); - this.Add("EMBEDDED_SPEECH_SYNTHESIS_VOICE_PATH", @"UPDATE_PATH_HERE"); // e.g. @"D:\src\macaroni\external\embedded_tts_mark_sps"); + this.Add("KEY_VAULT_CLIENT_SECRET", "UPDATE_SECRET_HERE"); + this.Add("CLU_KEY", "UPDATE_KEY_HERE"); + this.Add("OPEN_AI_KEY", "UPDATE_KEY_HERE"); + this.Add("SPEECH_KEY", "UPDATE_KEY_HERE"); + this.Add("TRANSLATOR_KEY", "UPDATE_KEY_HERE"); + this.Add("VISION_KEY", "UPDATE_KEY_HERE"); + + this.Add("CLU_DEPLOYMENT_NAME", "v1"); + this.Add("CLU_ENDPOINT", "https://internal-gm-dev.cognitiveservices.azure.com"); + this.Add("CLU_PROJECT_NAME", "GM-Orchestrator"); + this.Add("OPEN_AI_DEPLOYMENT", "robch-southcentral-oai-txtdav002"); + this.Add("OPEN_AI_ENDPOINT", "https://robch-openai.openai.azure.com/"); + this.Add("SPEECH_REGION", "westus"); + this.Add("SPEECH_RECOGNITION_ENDPOINT", ""); + this.Add("SPEECH_SYNTHESIS_ENDPOINT", ""); + this.Add("SPEECH_CUSTOM_RECOGNITION_ENDPOINT_ID", ""); + this.Add("SPEECH_CUSTOM_SYNTHESIS_ENDPOINT_ID", ""); + this.Add("TRANSLATOR_ENDPOINT", "https://api.cognitive.microsofttranslator.com/"); + this.Add("TRANSLATOR_REGION", "westus"); + this.Add("VISION_DEFAULT_LANGUAGE", "en"); + this.Add("VISION_ENDPOINT", "https://carbon-vision.cognitiveservices.azure.com"); } - else + + // DEVELOPER: To use Embedded speech (SR and TTS), update your local source to set `embedded=true` and replace + // `UPDATE_PATH_HERE` placeholders with appropriate locations where the model data files can be found + + var embedded = false; // !!!IMPORTANT!!!: DO NOT CHECK IN this file with embedded set to TRUE + if (embedded) // also update true/false in `csproj` files { - this.Add("EMBEDDED_SPEECH_RECOGNITION_MODEL_PATH", @"UPDATE_PATH_HERE"); // e.g. @"/data/user/0/com.companyname.maui/files/embedded/sr"); - this.Add("EMBEDDED_SPEECH_SYNTHESIS_VOICE_PATH", @"UPDATE_PATH_HERE"); // e.g. @"/data/user/0/com.companyname.maui/files/embedded/tts"); - } + if (OS.IsWindows()) + { + this.Add("EMBEDDED_SPEECH_RECOGNITION_MODEL_PATH", @"UPDATE_PATH_HERE"); // e.g. @"D:\src\macaroni\external\embedded_sr_model_FP_en-US_V8_onnx"); + this.Add("EMBEDDED_SPEECH_SYNTHESIS_VOICE_PATH", @"UPDATE_PATH_HERE"); // e.g. @"D:\src\macaroni\external\embedded_tts_mark_sps"); + } + else + { + this.Add("EMBEDDED_SPEECH_RECOGNITION_MODEL_PATH", @"UPDATE_PATH_HERE"); // e.g. @"/data/user/0/com.companyname.maui/files/embedded/sr"); + this.Add("EMBEDDED_SPEECH_SYNTHESIS_VOICE_PATH", @"UPDATE_PATH_HERE"); // e.g. @"/data/user/0/com.companyname.maui/files/embedded/tts"); + } - this.Add("EMBEDDED_SPEECH_RECOGNITION_MODEL_NAME", "Microsoft Speech Recognizer en-US FP Model V8"); - this.Add("EMBEDDED_SPEECH_SYNTHESIS_VOICE_NAME", "Microsoft Server Speech Text to Speech Voice (en-US, Mark, Apollo)"); - this.Add("EMBEDDED_SPEECH_RECOGNITION_MODEL_KEY", ""); - this.Add("EMBEDDED_SPEECH_SYNTHESIS_VOICE_KEY", ""); + this.Add("EMBEDDED_SPEECH_RECOGNITION_MODEL_NAME", "Microsoft Speech Recognizer en-US FP Model V8"); + this.Add("EMBEDDED_SPEECH_SYNTHESIS_VOICE_NAME", "Microsoft Server Speech Text to Speech Voice (en-US, Mark, Apollo)"); + this.Add("EMBEDDED_SPEECH_RECOGNITION_MODEL_KEY", ""); + this.Add("EMBEDDED_SPEECH_SYNTHESIS_VOICE_KEY", ""); + } } } -} +} \ No newline at end of file diff --git a/src/cs/CommandSystem/SecretSettings.cs b/src/cs/CommandSystem/SecretSettings.cs index 81f8a51d..8c07ee58 100644 --- a/src/cs/CommandSystem/SecretSettings.cs +++ b/src/cs/CommandSystem/SecretSettings.cs @@ -1,18 +1,22 @@ -namespace macaroni; +using System; +using System.Collections.Generic; -internal class SecretSettings : ISecretSettings +namespace macaroni { - public SecretSettings(IList>> settings) + internal class SecretSettings : ISecretSettings { - _settings = new(settings); - } + public SecretSettings(IList>> settings) + { + _settings = new Dictionary>(settings); + } - public bool TryGet(string name, out string? value) - { - var func = _settings.ContainsKey(name) ? _settings[name] : null; - value = func != null ? func.Invoke() : null; - return value != null; - } + public bool TryGet(string name, out string? value) + { + var func = _settings.ContainsKey(name) ? _settings[name] : null; + value = func != null ? func.Invoke() : null; + return value != null; + } - private Dictionary> _settings; -} + private Dictionary> _settings; + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemBuilder/CommandSystemBuilder.cs b/src/cs/CommandSystemBuilder/CommandSystemBuilder.cs index e31eaaba..723566ac 100644 --- a/src/cs/CommandSystemBuilder/CommandSystemBuilder.cs +++ b/src/cs/CommandSystemBuilder/CommandSystemBuilder.cs @@ -1,178 +1,181 @@ -global using Microsoft.Extensions.Hosting; -global using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -namespace macaroni; - -public class CommandSystemBuilder : ICommandSystemBuilder +namespace macaroni { - private IHostBuilder _builder; - - internal CommandSystemBuilder() + public class CommandSystemBuilder : ICommandSystemBuilder { - _builder = Host.CreateDefaultBuilder(); - } + private IHostBuilder _builder; - public IDictionary Properties => _builder.Properties; + internal CommandSystemBuilder() + { + _builder = Host.CreateDefaultBuilder(); + } - public ICommandSystem Build() - { - var components = ConfigComponentBuilder.Build(_componentBuilders); - components.Configure(this); + public IDictionary Properties => _builder.Properties; - var logging = ConfigLoggingBuilder.Build(_loggingBuilders); + public ICommandSystem Build() + { + var components = ConfigComponentBuilder.Build(_componentBuilders); + components.Configure(this); - var source = ConfigSourceBuilder.Build(_sourceBuilders); - var secret = ConfigSecretBuilder.Build(_secretBuilders); + var logging = ConfigLoggingBuilder.Build(_loggingBuilders); - var resolver = ConfigResolverBuilder.Build(_resolverBuilders); - var message = ConfigMessageBuilder.Build(_messageBuilders); + var source = ConfigSourceBuilder.Build(_sourceBuilders); + var secret = ConfigSecretBuilder.Build(_secretBuilders); - var ui = ConfigUiBuilder.Build(_uiBuilders); - var media = ConfigMediaBuilder.Build(_mediaBuilders); - var speech = ConfigSpeechBuilder.Build(_speechBuilders); + var resolver = ConfigResolverBuilder.Build(_resolverBuilders); + var message = ConfigMessageBuilder.Build(_messageBuilders); - _builder.ConfigureLogging(logging => logging.ClearProviders()); - _builder.ConfigureServices((context, services) => - { - logging.ConfigureServices(context, services); + var ui = ConfigUiBuilder.Build(_uiBuilders); + var media = ConfigMediaBuilder.Build(_mediaBuilders); + var speech = ConfigSpeechBuilder.Build(_speechBuilders); - source.ConfigureServices(context, services); - secret.ConfigureServices(context, services); - resolver.ConfigureServices(context, services); - message.ConfigureServices(context, services); + _builder.ConfigureLogging(logging => logging.ClearProviders()); + _builder.ConfigureServices((context, services) => + { + logging.ConfigureServices(context, services); - ui.ConfigureServices(context, services); - media.ConfigureServices(context, services); - speech.ConfigureServices(context, services); - }); + source.ConfigureServices(context, services); + secret.ConfigureServices(context, services); + resolver.ConfigureServices(context, services); + message.ConfigureServices(context, services); - var host = _builder.Build(); + ui.ConfigureServices(context, services); + media.ConfigureServices(context, services); + speech.ConfigureServices(context, services); + }); - logging.ConfigureServices(host.Services); + var host = _builder.Build(); - source.ConfigureServices(host.Services); - secret.ConfigureServices(host.Services); - resolver.ConfigureServices(host.Services); - message.ConfigureServices(host.Services); + logging.ConfigureServices(host.Services); - ui.ConfigureServices(host.Services); - media.ConfigureServices(host.Services); - speech.ConfigureServices(host.Services); + source.ConfigureServices(host.Services); + secret.ConfigureServices(host.Services); + resolver.ConfigureServices(host.Services); + message.ConfigureServices(host.Services); - var commandSystem = new CommandSystem(host); - components.SetCommandSystem(commandSystem); + ui.ConfigureServices(host.Services); + media.ConfigureServices(host.Services); + speech.ConfigureServices(host.Services); - return commandSystem; - } + var commandSystem = new CommandSystem(host); + components.SetCommandSystem(commandSystem); - public ICommandSystemBuilder ConfigureAppConfiguration(Action configureDelegate) - { - _builder.ConfigureAppConfiguration(configureDelegate); - return this; - } + return commandSystem; + } - public ICommandSystemBuilder ConfigureContainer(Action configureDelegate) - { - _builder.ConfigureContainer(configureDelegate); - return this; - } + public ICommandSystemBuilder ConfigureAppConfiguration(Action configureDelegate) + { + _builder.ConfigureAppConfiguration(configureDelegate); + return this; + } - public ICommandSystemBuilder ConfigureHostConfiguration(Action configureDelegate) - { - _builder.ConfigureHostConfiguration(configureDelegate); - return this; - } + public ICommandSystemBuilder ConfigureContainer(Action configureDelegate) + { + _builder.ConfigureContainer(configureDelegate); + return this; + } - public ICommandSystemBuilder ConfigureServices(Action configureDelegate) - { - _builder.ConfigureServices(configureDelegate); - return this; - } + public ICommandSystemBuilder ConfigureHostConfiguration(Action configureDelegate) + { + _builder.ConfigureHostConfiguration(configureDelegate); + return this; + } - public ICommandSystemBuilder UseServiceProviderFactory(IServiceProviderFactory factory) where TContainerBuilder : notnull - { - _builder.UseServiceProviderFactory(factory); - return this; - } + public ICommandSystemBuilder ConfigureServices(Action configureDelegate) + { + _builder.ConfigureServices(configureDelegate); + return this; + } - public ICommandSystemBuilder UseServiceProviderFactory(Func> factory) where TContainerBuilder : notnull - { - _builder.UseServiceProviderFactory(factory); - return this; - } + public ICommandSystemBuilder UseServiceProviderFactory(IServiceProviderFactory factory) where TContainerBuilder : notnull + { + _builder.UseServiceProviderFactory(factory); + return this; + } - public ICommandSystemBuilder ConfigureLogging(Action configureDelegate) - { - _loggingBuilders.Add(configureDelegate); - return this; - } + public ICommandSystemBuilder UseServiceProviderFactory(Func> factory) where TContainerBuilder : notnull + { + _builder.UseServiceProviderFactory(factory); + return this; + } - public ICommandSystemBuilder ConfigureSources(Action configureDelegate) - { - _sourceBuilders.Add(configureDelegate); - return this; - } + public ICommandSystemBuilder ConfigureLogging(Action configureDelegate) + { + _loggingBuilders.Add(configureDelegate); + return this; + } - public ICommandSystemBuilder ConfigureSecrets(Action configureDelegate) - { - _secretBuilders.Add(configureDelegate); - return this; - } + public ICommandSystemBuilder ConfigureSources(Action configureDelegate) + { + _sourceBuilders.Add(configureDelegate); + return this; + } - public ICommandSystemBuilder ConfigureSpeech(Action configureDelegate) - { - _speechBuilders.Add(configureDelegate); - return this; - } + public ICommandSystemBuilder ConfigureSecrets(Action configureDelegate) + { + _secretBuilders.Add(configureDelegate); + return this; + } - public ICommandSystemBuilder ConfigureComponents(Action configureDelegate) - { - _componentBuilders.Add(configureDelegate); - return this; - } + public ICommandSystemBuilder ConfigureSpeech(Action configureDelegate) + { + _speechBuilders.Add(configureDelegate); + return this; + } - public ICommandSystemBuilder ConfigureResolvers(Action configureDelegate) - { - _resolverBuilders.Add(configureDelegate); - return this; - } + public ICommandSystemBuilder ConfigureComponents(Action configureDelegate) + { + _componentBuilders.Add(configureDelegate); + return this; + } - public ICommandSystemBuilder ConfigureMessages(Action configureDelegate) - { - _messageBuilders.Add(configureDelegate); - return this; - } + public ICommandSystemBuilder ConfigureResolvers(Action configureDelegate) + { + _resolverBuilders.Add(configureDelegate); + return this; + } - public ICommandSystemBuilder ConfigureUi(Action configureDelegate) - { - _uiBuilders.Add(configureDelegate); - return this; - } + public ICommandSystemBuilder ConfigureMessages(Action configureDelegate) + { + _messageBuilders.Add(configureDelegate); + return this; + } - public ICommandSystemBuilder ConfigureMedia(Action configureDelegate) - { - _mediaBuilders.Add(configureDelegate); - return this; - } + public ICommandSystemBuilder ConfigureUi(Action configureDelegate) + { + _uiBuilders.Add(configureDelegate); + return this; + } - public ICommandSystemBuilder ConfigureClipboard(Action configureDelegate) - { - _clipboardBuilders.Add(configureDelegate); - return this; - } + public ICommandSystemBuilder ConfigureMedia(Action configureDelegate) + { + _mediaBuilders.Add(configureDelegate); + return this; + } - private List> _loggingBuilders = new(); - private List> _sourceBuilders = new(); - private List> _secretBuilders = new(); - private List> _speechBuilders = new(); + public ICommandSystemBuilder ConfigureClipboard(Action configureDelegate) + { + _clipboardBuilders.Add(configureDelegate); + return this; + } + + private List> _loggingBuilders = new List>(); + private List> _sourceBuilders = new List>(); + private List> _secretBuilders = new List>(); + private List> _speechBuilders = new List>(); - private List> _componentBuilders = new(); - private List> _resolverBuilders = new(); - private List> _messageBuilders = new(); + private List> _componentBuilders = new List>(); + private List> _resolverBuilders = new List>(); + private List> _messageBuilders = new List>(); - private List> _uiBuilders = new(); - private List> _mediaBuilders = new(); - private List> _clipboardBuilders = new(); -} + private List> _uiBuilders = new List>(); + private List> _mediaBuilders = new List>(); + private List> _clipboardBuilders = new List>(); + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemBuilder/CommandSystemBuilderExample.cs b/src/cs/CommandSystemBuilder/CommandSystemBuilderExample.cs index 62db610a..94caaccc 100644 --- a/src/cs/CommandSystemBuilder/CommandSystemBuilderExample.cs +++ b/src/cs/CommandSystemBuilder/CommandSystemBuilderExample.cs @@ -1,90 +1,96 @@ -namespace macaroni; +using System; +using System.IO; +using System.Threading.Tasks; +using Microsoft.Extensions.Hosting; -internal static class CommandSystemBuilderExample +namespace macaroni { - public static (ICommandSystem host, Task running) Example() + internal static class CommandSystemBuilderExample { - var builder = CommandSystem.CreateBuilder() - .ConfigureLogging(logging => logging - .UseFileLogging(Directory.GetCurrentDirectory()) - ) - .ConfigureSources(sources => sources - .AddFile("fileName") - .AddDocument("name", reader: File.OpenText("...")) - .MonitorFolder(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "macros"), "*.mac") - .UseDefaultFolderMonitor(false) - ) - .ConfigureSecrets(secrets => secrets - .AddSecret("SPEECH_KEY", () => "...") - .AddSecret("SPEECH_REGION", "...") - .AddSecret("SPEECH_RECOGNITION_ENDPOINT", "...") - .AddSecret("SPEECH_SYNTHESIS_ENDPOINT", "...") - .AddSecret(SecretKind.SpeechKey, () => "...") - .AddSecret(SecretKind.SpeechRegion, "...") - .AddSecret(SecretKind.SpeechRecognitionEndpoint, "...") - .AddSecret(SecretKind.SpeechSynthesisEndpoint, "...") - .UseKeyVault("...", "...", "...") - // .UseCredential(CredentialKind.SpeechAuthToken, () => (Azure.Core.TokenCredential?)null) - ) - .ConfigureSpeech(speech => speech - .UseDefaultListeningState(ListeningState.Off) - .UseKeywordRecognition(GetKeyword(), GetKeywordModelFile()) - .UseHighRecall(false, false) + public static (ICommandSystem host, Task running) Example() + { + var builder = CommandSystem.CreateBuilder() + .ConfigureLogging(logging => logging + .UseFileLogging(Directory.GetCurrentDirectory()) + ) + .ConfigureSources(sources => sources + .AddFile("fileName") + .AddDocument("name", reader: File.OpenText("...")) + .MonitorFolder(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "macros"), "*.mac") + .UseDefaultFolderMonitor(false) + ) + .ConfigureSecrets(secrets => secrets + .AddSecret("SPEECH_KEY", () => "...") + .AddSecret("SPEECH_REGION", "...") + .AddSecret("SPEECH_RECOGNITION_ENDPOINT", "...") + .AddSecret("SPEECH_SYNTHESIS_ENDPOINT", "...") + .AddSecret(SecretKind.SpeechKey, () => "...") + .AddSecret(SecretKind.SpeechRegion, "...") + .AddSecret(SecretKind.SpeechRecognitionEndpoint, "...") + .AddSecret(SecretKind.SpeechSynthesisEndpoint, "...") + .UseKeyVault("...", "...", "...") + // .UseCredential(CredentialKind.SpeechAuthToken, () => (Azure.Core.TokenCredential?)null) + ) + .ConfigureSpeech(speech => speech + .UseDefaultListeningState(ListeningState.Off) + .UseKeywordRecognition(GetKeyword(), GetKeywordModelFile()) + .UseHighRecall(false, false) + ) + .ConfigureResolvers(resolvers => resolvers + .AddResolver("minimumTemperature", () => "58") + .AddResolver(name => name switch + { + "aaaaa" => "a", + "bbbbb" => "b", + _ => null + }) + ) + .ConfigureMessages(messages => messages + .AddHandler("CarControl.SetTemperature", value => { }) + .AddHandler((name, value) => { }) + ) + .ConfigureUi(ui => ui + .UseDisplay((message, from, pending, timeout) => { }) + .UseAlert((message, title, timeout) => { }) + .UseConfirm((message, title, timeout) => { }) + .UsePrompt((prompt, title, text, timeout) => "") + .UsePick((message, title, timeout, choices, choice) => "") + ) + .ConfigureMedia(media => media + .UseBeep((freq, duration) => { }) + .UsePlay((file, pos) => { }) + .UsePause(() => { }) + .UseResume(() => { }) + .UseStop(() => { }) + .UseNullAudio(false) ) - .ConfigureResolvers(resolvers => resolvers - .AddResolver("minimumTemperature", () => "58") - .AddResolver(name => name switch - { - "aaaaa" => "a", - "bbbbb" => "b", - _ => null - }) - ) - .ConfigureMessages(messages => messages - .AddHandler("CarControl.SetTemperature", value => { }) - .AddHandler((name, value) => { }) - ) - .ConfigureUi(ui => ui - .UseDisplay((message, from, pending, timeout) => { }) - .UseAlert((message, title, timeout) => { }) - .UseConfirm((message, title, timeout) => { }) - .UsePrompt((prompt, title, text, timeout) => "") - .UsePick((message, title, timeout, choices, choice) => "") - ) - .ConfigureMedia(media => media - .UseBeep((freq, duration) => { }) - .UsePlay((file, pos) => { }) - .UsePause(() => { }) - .UseResume(() => { }) - .UseStop(() => { }) - .UseNullAudio(false) - ) - .ConfigureClipboard(clipboard => clipboard - .UseGet(() => null ?? "") - .UseSet(text => { }) - .UseClear(() => { }) - ); + .ConfigureClipboard(clipboard => clipboard + .UseGet(() => null ?? "") + .UseSet(text => { }) + .UseClear(() => { }) + ); - var commandSystem = builder.Build(); - var running = commandSystem.RunAsync(); + var commandSystem = builder.Build(); + var running = commandSystem.RunAsync(); - return (commandSystem, running); - } + return (commandSystem, running); + } - private static string GetKeyword() - { - return "Copilot"; - } + private static string GetKeyword() + { + return "Copilot"; + } - private static string GetKeywordModelFile() - { - var use = 1; - var file = use switch + private static string GetKeywordModelFile() { - 1 => "copilot_higher_ca.table", - 2 => "copilot_lower_fa.table", - _ => "copilot_default.table" - }; - return file; + var use = 1; + var file = use switch + { + 1 => "copilot_higher_ca.table", + 2 => "copilot_lower_fa.table", + _ => "copilot_default.table" + }; + return file; + } } } \ No newline at end of file diff --git a/src/cs/CommandSystemBuilder/ConfigComponentBuilder.cs b/src/cs/CommandSystemBuilder/ConfigComponentBuilder.cs index 9637cb17..465456d6 100644 --- a/src/cs/CommandSystemBuilder/ConfigComponentBuilder.cs +++ b/src/cs/CommandSystemBuilder/ConfigComponentBuilder.cs @@ -1,71 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; using System.Reflection; -namespace macaroni; - -internal class ConfigComponentBuilder : IConfigureComponentBuilder +namespace macaroni { - internal static ConfigComponentBuilder Build(List> actions) - { - var builder = new ConfigComponentBuilder(); - actions.ToList().ForEach(action => action(builder)); - return builder; - } - public IConfigureComponentBuilder AddComponent(ICommandSystemComponent component) + internal class ConfigComponentBuilder : IConfigureComponentBuilder { - _components.Add(component); - return this; - } + internal static ConfigComponentBuilder Build(List> actions) + { + var builder = new ConfigComponentBuilder(); + actions.ToList().ForEach(action => action(builder)); + return builder; + } - public IConfigureComponentBuilder AddComponentsFromAssembly(Assembly assembly) - { - _assemblies.Enqueue(assembly); - return this; - } + public IConfigureComponentBuilder AddComponent(ICommandSystemComponent component) + { + _components.Add(component); + return this; + } - public void Configure(ICommandSystemBuilder builder) - { - AddComponentsFromAssemblies(); - _components.ForEach(component => component.Configure(builder)); - } + public IConfigureComponentBuilder AddComponentsFromAssembly(Assembly assembly) + { + _assemblies.Enqueue(assembly); + return this; + } - public void SetCommandSystem(ICommandSystem commandSystem) - { - _components.ForEach(component => component.SetCommandSystem(commandSystem)); - } + public void Configure(ICommandSystemBuilder builder) + { + AddComponentsFromAssemblies(); + _components.ForEach(component => component.Configure(builder)); + } - private void AddComponentsFromAssemblies() - { - while (_assemblies.TryDequeue(out Assembly? assembly)) + public void SetCommandSystem(ICommandSystem commandSystem) { - if (!_assembliesAdded.Contains(assembly)) + _components.ForEach(component => component.SetCommandSystem(commandSystem)); + } + + private void AddComponentsFromAssemblies() + { + while (_assemblies.TryDequeue(out Assembly? assembly)) { - _assembliesAdded.Add(assembly); - foreach (Type type in assembly.GetTypes()) + if (!_assembliesAdded.Contains(assembly)) { - AddComponentsViaMethodAttribute(this, type); + _assembliesAdded.Add(assembly); + foreach (Type type in assembly.GetTypes()) + { + AddComponentsViaMethodAttribute(this, type); + } } } } - } - private static void AddComponentsViaMethodAttribute(IConfigureComponentBuilder builder, Type type) - { - foreach (MethodInfo method in type.GetMethods(BindingFlags.Static | BindingFlags.Public)) + private static void AddComponentsViaMethodAttribute(IConfigureComponentBuilder builder, Type type) { - var attribute = method.GetCustomAttribute(); - if (attribute != null && method.ReturnType == typeof(void)) + foreach (MethodInfo method in type.GetMethods(BindingFlags.Static | BindingFlags.Public)) { - var parameters = method.GetParameters(); - if (parameters.Length == 1 && parameters[0].ParameterType == typeof(IConfigureComponentBuilder)) + var attribute = method.GetCustomAttribute(); + if (attribute != null && method.ReturnType == typeof(void)) { - method.Invoke(null, new object[] { builder }); + var parameters = method.GetParameters(); + if (parameters.Length == 1 && parameters[0].ParameterType == typeof(IConfigureComponentBuilder)) + { + method.Invoke(null, new object[] { builder }); + } } } } - } - Queue _assemblies = new(); - HashSet _assembliesAdded = new(); - List _components = new(); + Queue _assemblies = new Queue(); + HashSet _assembliesAdded = new HashSet(); + List _components = new List(); + } } diff --git a/src/cs/CommandSystemBuilder/ConfigLoggingBuilder.cs b/src/cs/CommandSystemBuilder/ConfigLoggingBuilder.cs index 9c6c43fe..e1546e4b 100644 --- a/src/cs/CommandSystemBuilder/ConfigLoggingBuilder.cs +++ b/src/cs/CommandSystemBuilder/ConfigLoggingBuilder.cs @@ -1,87 +1,95 @@ -namespace macaroni; -internal class ConfigLoggingBuilder : IConfigureLoggingBuilder -{ - public static ConfigLoggingBuilder Build(IEnumerable> actions) - { - var builder = new ConfigLoggingBuilder(); - actions.ToList().ForEach(action => action(builder)); - return builder; - } - - public void ConfigureServices(HostBuilderContext context, IServiceCollection services) - { - // no pre-build configuration required - } +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; - public void ConfigureServices(IServiceProvider services) +namespace macaroni +{ + internal class ConfigLoggingBuilder : IConfigureLoggingBuilder { - RegisterLoggingService(services); - RegisterBroadcastNotifications(services); - } + public static ConfigLoggingBuilder Build(IEnumerable> actions) + { + var builder = new ConfigLoggingBuilder(); + actions.ToList().ForEach(action => action(builder)); + return builder; + } - public IConfigureLoggingBuilder UseFileLogging(string path) - { - _logFilePath = path; - return this; - } + public void ConfigureServices(HostBuilderContext context, IServiceCollection services) + { + // no pre-build configuration required + } - public IConfigureLoggingBuilder AddExceptionHandler(ExceptionKind kind, Action handler) - { - if (!_exceptionHandlers.ContainsKey(kind)) + public void ConfigureServices(IServiceProvider services) { - _exceptionHandlers.Add(kind, new List>()); + RegisterLoggingService(services); + RegisterBroadcastNotifications(services); } - _exceptionHandlers[kind].Add(handler); - return this; - } + public IConfigureLoggingBuilder UseFileLogging(string path) + { + _logFilePath = path; + return this; + } - private void RegisterLoggingService(IServiceProvider services) - { - var states = services.GetRequiredService(); + public IConfigureLoggingBuilder AddExceptionHandler(ExceptionKind kind, Action handler) + { + if (!_exceptionHandlers.ContainsKey(kind)) + { + _exceptionHandlers.Add(kind, new List>()); + } - var logPathOk = !string.IsNullOrWhiteSpace(_logFilePath); - if (logPathOk) states.SetNamedState("__macaroni.logFilePath", _logFilePath); - } + _exceptionHandlers[kind].Add(handler); + return this; + } - private void RegisterBroadcastNotifications(IServiceProvider services) - { - var broadcast = services.GetRequiredService(); - if (_exceptionHandlers.ContainsKey(ExceptionKind.Parsing)) + private void RegisterLoggingService(IServiceProvider services) { - broadcast.StartNotify(nameof(ConfigLoggingBuilder), nameof(ConfigLoggingBuilder) + ".Parsing", ExceptionKind.Parsing, BroadcastParsingCallback); + var states = services.GetRequiredService(); + + var logPathOk = !string.IsNullOrWhiteSpace(_logFilePath); + if (logPathOk) states.SetNamedState("__macaroni.logFilePath", _logFilePath); } - if (_exceptionHandlers.ContainsKey(ExceptionKind.Runtime)) + private void RegisterBroadcastNotifications(IServiceProvider services) { - broadcast.StartNotify(nameof(ConfigLoggingBuilder), nameof(ConfigLoggingBuilder) + ".Runtime", ExceptionKind.Runtime, BroadcastRuntimeCallback); + var broadcast = services.GetRequiredService(); + if (_exceptionHandlers.ContainsKey(ExceptionKind.Parsing)) + { + broadcast.StartNotify(nameof(ConfigLoggingBuilder), nameof(ConfigLoggingBuilder) + ".Parsing", ExceptionKind.Parsing, BroadcastParsingCallback); + } + + if (_exceptionHandlers.ContainsKey(ExceptionKind.Runtime)) + { + broadcast.StartNotify(nameof(ConfigLoggingBuilder), nameof(ConfigLoggingBuilder) + ".Runtime", ExceptionKind.Runtime, BroadcastRuntimeCallback); + } + + if (_exceptionHandlers.ContainsKey(ExceptionKind.System)) + { + broadcast.StartNotify(nameof(ConfigLoggingBuilder), nameof(ConfigLoggingBuilder) + ".System", ExceptionKind.System, BroadcastSystemCallback); + } } - if (_exceptionHandlers.ContainsKey(ExceptionKind.System)) + private void BroadcastParsingCallback(Exception exception) { - broadcast.StartNotify(nameof(ConfigLoggingBuilder), nameof(ConfigLoggingBuilder) + ".System", ExceptionKind.System, BroadcastSystemCallback); + var callbacks = _exceptionHandlers.ContainsKey(ExceptionKind.Parsing) ? _exceptionHandlers[ExceptionKind.Parsing] : new List>(); + callbacks.ForEach(handler => handler(exception)); } - } - private void BroadcastParsingCallback(Exception exception) - { - var callbacks = _exceptionHandlers.ContainsKey(ExceptionKind.Parsing) ? _exceptionHandlers[ExceptionKind.Parsing] : new List>(); - callbacks.ForEach(handler => handler(exception)); - } + private void BroadcastRuntimeCallback(Exception exception) + { + var callbacks = _exceptionHandlers.ContainsKey(ExceptionKind.Runtime) ? _exceptionHandlers[ExceptionKind.Runtime] : new List>(); + callbacks.ForEach(handler => handler(exception)); + } - private void BroadcastRuntimeCallback(Exception exception) - { - var callbacks = _exceptionHandlers.ContainsKey(ExceptionKind.Runtime) ? _exceptionHandlers[ExceptionKind.Runtime] : new List>(); - callbacks.ForEach(handler => handler(exception)); - } + private void BroadcastSystemCallback(Exception exception) + { + var callbacks = _exceptionHandlers.ContainsKey(ExceptionKind.System) ? _exceptionHandlers[ExceptionKind.System] : new List>(); + callbacks.ForEach(handler => handler(exception)); + } - private void BroadcastSystemCallback(Exception exception) - { - var callbacks = _exceptionHandlers.ContainsKey(ExceptionKind.System) ? _exceptionHandlers[ExceptionKind.System] : new List>(); - callbacks.ForEach(handler => handler(exception)); + private string? _logFilePath; + private Dictionary>> _exceptionHandlers = new Dictionary>>(); } - - private string? _logFilePath; - private Dictionary>> _exceptionHandlers = new(); } diff --git a/src/cs/CommandSystemBuilder/ConfigMediaBuilder.cs b/src/cs/CommandSystemBuilder/ConfigMediaBuilder.cs index 1fe3fdde..ed47f2f0 100644 --- a/src/cs/CommandSystemBuilder/ConfigMediaBuilder.cs +++ b/src/cs/CommandSystemBuilder/ConfigMediaBuilder.cs @@ -1,77 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Linq; using macaroni.Interfaces; using Microsoft.CognitiveServices.Speech.Audio; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; -namespace macaroni; - -internal class ConfigMediaBuilder : IConfigureMediaBuilder -{ - public static ConfigMediaBuilder Build(IEnumerable> actions) +namespace macaroni +{ + internal class ConfigMediaBuilder : IConfigureMediaBuilder { - var builder = new ConfigMediaBuilder(); - actions.ToList().ForEach(action => action(builder)); - return builder; - } - - public void ConfigureServices(HostBuilderContext context, IServiceCollection services) - { - SetAudioConfig(services); - } + public static ConfigMediaBuilder Build(IEnumerable> actions) + { + var builder = new ConfigMediaBuilder(); + actions.ToList().ForEach(action => action(builder)); + return builder; + } - public void ConfigureServices(IServiceProvider services) - { - // no post-build configuration required - } + public void ConfigureServices(HostBuilderContext context, IServiceCollection services) + { + SetAudioConfig(services); + } - public IConfigureMediaBuilder UseBeep(Action beep) - { - throw new NotImplementedException(); - } + public void ConfigureServices(IServiceProvider services) + { + // no post-build configuration required + } - public IConfigureMediaBuilder UseNullAudio(bool useNullAudio = true) - { - _useNullAudio = useNullAudio; - return this; - } + public IConfigureMediaBuilder UseBeep(Action beep) + { + throw new NotImplementedException(); + } - public IConfigureMediaBuilder UsePause(Action pause) - { - throw new NotImplementedException(); - } + public IConfigureMediaBuilder UseNullAudio(bool useNullAudio = true) + { + _useNullAudio = useNullAudio; + return this; + } - public IConfigureMediaBuilder UsePlay(Action play) - { - throw new NotImplementedException(); - } + public IConfigureMediaBuilder UsePause(Action pause) + { + throw new NotImplementedException(); + } - public IConfigureMediaBuilder UseResume(Action resume) - { - throw new NotImplementedException(); - } + public IConfigureMediaBuilder UsePlay(Action play) + { + throw new NotImplementedException(); + } - public IConfigureMediaBuilder UseStop(Action stop) - { - throw new NotImplementedException(); - } - - private void SetAudioConfig(IServiceCollection services) - { - var audioConfigService = new AudioConfigService(); - if (_useNullAudio) + public IConfigureMediaBuilder UseResume(Action resume) { - var pullStream = PullAudioInputStream.CreatePullStream(new NullPullAudioInputStreamCallback()); - audioConfigService?.SetAudioConfig(AudioConfig.FromStreamInput(pullStream)); - } - services.AddSingleton(audioConfigService!); - } + throw new NotImplementedException(); + } - private bool _useNullAudio = false; - - private class NullPullAudioInputStreamCallback : PullAudioInputStreamCallback - { - public override int Read(byte[] dataBuffer, uint size) + public IConfigureMediaBuilder UseStop(Action stop) + { + throw new NotImplementedException(); + } + + private void SetAudioConfig(IServiceCollection services) { - return 0; + var audioConfigService = new AudioConfigService(); + if (_useNullAudio) + { + var pullStream = PullAudioInputStream.CreatePullStream(new NullPullAudioInputStreamCallback()); + audioConfigService?.SetAudioConfig(AudioConfig.FromStreamInput(pullStream)); + } + services.AddSingleton(audioConfigService!); } - } -} + + private bool _useNullAudio = false; + + private class NullPullAudioInputStreamCallback : PullAudioInputStreamCallback + { + public override int Read(byte[] dataBuffer, uint size) + { + return 0; + } + } + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemBuilder/ConfigMessageBuilder.cs b/src/cs/CommandSystemBuilder/ConfigMessageBuilder.cs index 7e996b10..6e4e02b5 100644 --- a/src/cs/CommandSystemBuilder/ConfigMessageBuilder.cs +++ b/src/cs/CommandSystemBuilder/ConfigMessageBuilder.cs @@ -1,37 +1,42 @@ using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using System; +using System.Collections.Generic; +using System.Linq; -namespace macaroni; - -internal class ConfigMessageBuilder : IConfigureMessageBuilder +namespace macaroni { - public static ConfigMessageBuilder Build(IEnumerable> actions) + internal class ConfigMessageBuilder : IConfigureMessageBuilder { - var builder = new ConfigMessageBuilder(); - actions.ToList().ForEach(action => action(builder)); - return builder; - } + public static ConfigMessageBuilder Build(IEnumerable> actions) + { + var builder = new ConfigMessageBuilder(); + actions.ToList().ForEach(action => action(builder)); + return builder; + } - internal void ConfigureServices(HostBuilderContext context, IServiceCollection services) - { - _base.ConfigureServices(context, services); - } + internal void ConfigureServices(HostBuilderContext context, IServiceCollection services) + { + _base.ConfigureServices(context, services); + } - internal void ConfigureServices(IServiceProvider services) - { - _base.ConfigureServices(services); - } + internal void ConfigureServices(IServiceProvider services) + { + _base.ConfigureServices(services); + } - public IConfigureMessageBuilder AddHandler(string name, Action handler) - { - _base.AddHandler(name, handler); - return this; - } + public IConfigureMessageBuilder AddHandler(string name, Action handler) + { + _base.AddHandler(name, handler); + return this; + } - public IConfigureMessageBuilder AddHandler(Action handler) - { - _base.AddHandler(handler); - return this; - } + public IConfigureMessageBuilder AddHandler(Action handler) + { + _base.AddHandler(handler); + return this; + } - private ConfigMessageBuilderBase _base = new(); -} + private ConfigMessageBuilderBase _base = new ConfigMessageBuilderBase(); + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemBuilder/ConfigMessageBuilderBase.cs b/src/cs/CommandSystemBuilder/ConfigMessageBuilderBase.cs index 2423a9f3..f6c5e355 100644 --- a/src/cs/CommandSystemBuilder/ConfigMessageBuilderBase.cs +++ b/src/cs/CommandSystemBuilder/ConfigMessageBuilderBase.cs @@ -1,45 +1,52 @@ -namespace macaroni; +using System; +using System.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; -internal class ConfigMessageBuilderBase +namespace macaroni { - public void ConfigureServices(IServiceProvider services) - { - RegisterBroadcastNotify(services); - } - public void ConfigureServices(HostBuilderContext context, IServiceCollection services) + internal class ConfigMessageBuilderBase { - // no pre-build configuration required - } + public void ConfigureServices(IServiceProvider services) + { + RegisterBroadcastNotify(services); + } - public void AddHandler(string name, Action handler) - { - _nameHandlers.Add(new(name, handler)); - } + public void ConfigureServices(HostBuilderContext context, IServiceCollection services) + { + // no pre-build configuration required + } - public void AddHandler(Action handler) - { - _handlers.Add(handler); - } + public void AddHandler(string name, Action handler) + { + _nameHandlers.Add(new KeyValuePair>(name, handler)); + } - private void BroadcastCallback(string scopeId, string callbackId, string messageName, string? messageValue) - { - _nameHandlers.ForEach(kvp => + public void AddHandler(Action handler) { - if (kvp.Key == messageName) + _handlers.Add(handler); + } + + private void BroadcastCallback(string scopeId, string callbackId, string messageName, string? messageValue) + { + _nameHandlers.ForEach(kvp => { - kvp.Value(messageValue); - } - }); - _handlers.ForEach(action => action(messageName, messageValue)); - } + if (kvp.Key == messageName) + { + kvp.Value(messageValue); + } + }); + _handlers.ForEach(action => action(messageName, messageValue)); + } - private void RegisterBroadcastNotify(IServiceProvider services) - { - var broadcast = services.GetRequiredService(); - broadcast.StartNotify(typeof(T).Name, typeof(T).Name, "*", null, BroadcastCallback); - } + private void RegisterBroadcastNotify(IServiceProvider services) + { + var broadcast = services.GetRequiredService(); + broadcast.StartNotify(typeof(T).Name, typeof(T).Name, "*", null, BroadcastCallback); + } - private List> _handlers = new(); - private List>> _nameHandlers = new(); -} + private List> _handlers = new List>(); + private List>> _nameHandlers = new List>>(); + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemBuilder/ConfigResolverBuilder.cs b/src/cs/CommandSystemBuilder/ConfigResolverBuilder.cs index d280b730..03c3b8e6 100644 --- a/src/cs/CommandSystemBuilder/ConfigResolverBuilder.cs +++ b/src/cs/CommandSystemBuilder/ConfigResolverBuilder.cs @@ -1,43 +1,48 @@ using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using System; +using System.Collections.Generic; +using System.Linq; -namespace macaroni; - -internal class ConfigResolverBuilder : IConfigureResolverBuilder +namespace macaroni { - public static ConfigResolverBuilder Build(IEnumerable> actions) + internal class ConfigResolverBuilder : IConfigureResolverBuilder { - var builder = new ConfigResolverBuilder(); - actions.ToList().ForEach(action => action(builder)); - return builder; + public static ConfigResolverBuilder Build(IEnumerable> actions) + { + var builder = new ConfigResolverBuilder(); + actions.ToList().ForEach(action => action(builder)); + return builder; + } + + public void ConfigureServices(HostBuilderContext context, IServiceCollection services) + { + _base.ConfigureServices(context, services); + } + + public void ConfigureServices(IServiceProvider services) + { + _base.ConfigureServices(services); + } + + public IConfigureResolverBuilder AddResolver(string name, Func resolver) + { + _base.AddResolver(name, resolver); + return this; + } + + public IConfigureResolverBuilder AddResolver(Func resolver) + { + _base.AddResolver(resolver); + return this; + } + + public IConfigureResolverBuilder UseContext(string name, object value) + { + _base.UseContext(name, value); + return this; + } + + ConfigResolverBuilderBase _base = new ConfigResolverBuilderBase(); } - - public void ConfigureServices(HostBuilderContext context, IServiceCollection services) - { - _base.ConfigureServices(context, services); - } - - public void ConfigureServices(IServiceProvider services) - { - _base.ConfigureServices(services); - } - - public IConfigureResolverBuilder AddResolver(string name, Func resolver) - { - _base.AddResolver(name, resolver); - return this; - } - - public IConfigureResolverBuilder AddResolver(Func resolver) - { - _base.AddResolver(resolver); - return this; - } - - public IConfigureResolverBuilder UseContext(string name, object value) - { - _base.UseContext(name, value); - return this; - } - - ConfigResolverBuilderBase _base = new(); -} +} \ No newline at end of file diff --git a/src/cs/CommandSystemBuilder/ConfigResolverBuilderBase.cs b/src/cs/CommandSystemBuilder/ConfigResolverBuilderBase.cs index 73c5742b..e1861528 100644 --- a/src/cs/CommandSystemBuilder/ConfigResolverBuilderBase.cs +++ b/src/cs/CommandSystemBuilder/ConfigResolverBuilderBase.cs @@ -1,55 +1,61 @@ -namespace macaroni; +using System; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; -internal class ConfigResolverBuilderBase +namespace macaroni { - public void ConfigureServices(HostBuilderContext context, IServiceCollection services) - { - AddContextResolver(services); - } - public void ConfigureServices(IServiceProvider services) + internal class ConfigResolverBuilderBase { - // no post-build configuration required - } + public void ConfigureServices(HostBuilderContext context, IServiceCollection services) + { + AddContextResolver(services); + } - public void UseContext(string name, object value) - { - EnsureContextResolver(); - _callbackResolver!.Set(name, value, SetValueKind.OverrideAllResolvers); - } + public void ConfigureServices(IServiceProvider services) + { + // no post-build configuration required + } - public void AddResolver(string name, Func resolver) - { - EnsureContextResolver(); - _callbackResolver!.RegisterResolver(nameof(ConfigResolverBuilder), check => + public void UseContext(string name, object value) { - return check == "context.keys" ? name - : check == name ? resolver() - : null; - }); - } + EnsureContextResolver(); + _callbackResolver!.Set(name, value, SetValueKind.OverrideAllResolvers); + } - public void AddResolver(Func resolver) - { - EnsureContextResolver(); - _callbackResolver!.RegisterResolver(nameof(ConfigResolverBuilderBase), resolver); - } + public void AddResolver(string name, Func resolver) + { + EnsureContextResolver(); + _callbackResolver!.RegisterResolver(nameof(ConfigResolverBuilder), check => + { + return check == "context.keys" ? name + : check == name ? resolver() + : null; + }); + } - private void AddContextResolver(IServiceCollection services) - { - if (_callbackResolver != null) + public void AddResolver(Func resolver) { - services.AddSingleton(_callbackResolver!); + EnsureContextResolver(); + _callbackResolver!.RegisterResolver(nameof(ConfigResolverBuilderBase), resolver); } - } - private void EnsureContextResolver() - { - if (_callbackResolver == null) + private void AddContextResolver(IServiceCollection services) { - _callbackResolver = new(); + if (_callbackResolver != null) + { + services.AddSingleton(_callbackResolver!); + } + } + + private void EnsureContextResolver() + { + if (_callbackResolver == null) + { + _callbackResolver = new CallbackContextResolver(); + } } - } - private CallbackContextResolver? _callbackResolver; + private CallbackContextResolver? _callbackResolver; + } } diff --git a/src/cs/CommandSystemBuilder/ConfigSecretBuilder.cs b/src/cs/CommandSystemBuilder/ConfigSecretBuilder.cs index 1c81b783..84948a62 100644 --- a/src/cs/CommandSystemBuilder/ConfigSecretBuilder.cs +++ b/src/cs/CommandSystemBuilder/ConfigSecretBuilder.cs @@ -1,91 +1,96 @@ using Azure.Core; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using System; +using System.Collections.Generic; +using System.Linq; -namespace macaroni; - -internal class ConfigSecretBuilder : IConfigureSecretBuilder +namespace macaroni { - public static ConfigSecretBuilder Build(IEnumerable> actions) + internal class ConfigSecretBuilder : IConfigureSecretBuilder { - var builder = new ConfigSecretBuilder(); - actions.ToList().ForEach(action => action(builder)); - return builder; - } + public static ConfigSecretBuilder Build(IEnumerable> actions) + { + var builder = new ConfigSecretBuilder(); + actions.ToList().ForEach(action => action(builder)); + return builder; + } - public void ConfigureServices(HostBuilderContext context, IServiceCollection services) - { - AddSecretSettings(services); - } + public void ConfigureServices(HostBuilderContext context, IServiceCollection services) + { + AddSecretSettings(services); + } - public void ConfigureServices(IServiceProvider services) - { - // no post-build configuration required - } + public void ConfigureServices(IServiceProvider services) + { + // no post-build configuration required + } - public IConfigureSecretBuilder AddSecret(SecretKind secret, string value) - { - return AddSecret(NameFromKind(secret), value); - } + public IConfigureSecretBuilder AddSecret(SecretKind secret, string value) + { + return AddSecret(NameFromKind(secret), value); + } - public IConfigureSecretBuilder AddSecret(SecretKind secret, Func func) - { - return AddSecret(NameFromKind(secret), func); - } + public IConfigureSecretBuilder AddSecret(SecretKind secret, Func func) + { + return AddSecret(NameFromKind(secret), func); + } - public IConfigureSecretBuilder AddSecret(string name, string value) - { - return AddSecret(name, () => value); - } + public IConfigureSecretBuilder AddSecret(string name, string value) + { + return AddSecret(name, () => value); + } - public IConfigureSecretBuilder AddSecret(string name, Func func) - { - _secrets.Add(new KeyValuePair>(name, func)); - return this; - } + public IConfigureSecretBuilder AddSecret(string name, Func func) + { + _secrets.Add(new KeyValuePair>(name, func)); + return this; + } - public IConfigureSecretBuilder UseKeyVault(string? uri, string? tenantId, string? clientId) - { - AddSecret("KEY_VAULT_URI", uri ?? ""); - AddSecret("KEY_VAULT_TENANT_ID", tenantId ?? ""); - AddSecret("KEY_VAULT_CLIENT_ID", clientId ?? ""); - - return this; - } + public IConfigureSecretBuilder UseKeyVault(string? uri, string? tenantId, string? clientId) + { + AddSecret("KEY_VAULT_URI", uri ?? ""); + AddSecret("KEY_VAULT_TENANT_ID", tenantId ?? ""); + AddSecret("KEY_VAULT_CLIENT_ID", clientId ?? ""); - // public IConfigureSecretBuilder UseCredential(CredentialKind kind, Func func) - // { - // _credentials.Add(new KeyValuePair>(NameFromKind(kind), func)); - // return this; - // } + return this; + } - private void AddSecretSettings(IServiceCollection services) - { - services.AddSingleton(new SecretSettings(_secrets)); - } + // public IConfigureSecretBuilder UseCredential(CredentialKind kind, Func func) + // { + // _credentials.Add(new KeyValuePair>(NameFromKind(kind), func)); + // return this; + // } - private static string NameFromKind(SecretKind kind) - { - return kind switch + private void AddSecretSettings(IServiceCollection services) { - SecretKind.SpeechKey => "SPEECH_KEY", - SecretKind.SpeechRegion => "SPEECH_REGION", - SecretKind.SpeechRecognitionEndpoint => "SPEECH_RECOGNITION_ENDPOINT", - SecretKind.SpeechRecognitionEndpointId => "SPEECH_CUSTOM_RECOGNITION_ENDPOINT_ID", - SecretKind.SpeechSynthesisEndpoint => "SPEECH_SYNTHESIS_ENDPOINT", - SecretKind.SpeechSynthesisEndpointId => "SPEECH_CUSTOM_SYNTHESIS_ENDPOINT_ID", - _ => throw new NotImplementedException($"{kind} SecretKind not implemented") - }; - } + services.AddSingleton(new SecretSettings(_secrets)); + } - private static string NameFromKind(CredentialKind kind) - { - return kind switch + private static string NameFromKind(SecretKind kind) { - CredentialKind.SpeechAuthToken => "SPEECH_AUTH_TOKEN", - _ => throw new NotImplementedException($"{kind} CredentialKind not implemented") - }; - } + return kind switch + { + SecretKind.SpeechKey => "SPEECH_KEY", + SecretKind.SpeechRegion => "SPEECH_REGION", + SecretKind.SpeechRecognitionEndpoint => "SPEECH_RECOGNITION_ENDPOINT", + SecretKind.SpeechRecognitionEndpointId => "SPEECH_CUSTOM_RECOGNITION_ENDPOINT_ID", + SecretKind.SpeechSynthesisEndpoint => "SPEECH_SYNTHESIS_ENDPOINT", + SecretKind.SpeechSynthesisEndpointId => "SPEECH_CUSTOM_SYNTHESIS_ENDPOINT_ID", + _ => throw new NotImplementedException($"{kind} SecretKind not implemented") + }; + } + + private static string NameFromKind(CredentialKind kind) + { + return kind switch + { + CredentialKind.SpeechAuthToken => "SPEECH_AUTH_TOKEN", + _ => throw new NotImplementedException($"{kind} CredentialKind not implemented") + }; + } - private List>> _secrets = new(); - private List>> _credentials = new(); -} + private List>> _secrets = new List>>(); + private List>> _credentials = new List>>(); + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemBuilder/ConfigSourceBuilder.cs b/src/cs/CommandSystemBuilder/ConfigSourceBuilder.cs index 65590630..088d8c76 100644 --- a/src/cs/CommandSystemBuilder/ConfigSourceBuilder.cs +++ b/src/cs/CommandSystemBuilder/ConfigSourceBuilder.cs @@ -1,93 +1,98 @@ -using Esprima.Ast; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; -namespace macaroni; - -internal class ConfigSourceBuilder : IConfigureSourceBuilder +namespace macaroni { - internal static ConfigSourceBuilder Build(IEnumerable> actions) - { - var builder = new ConfigSourceBuilder(); - actions.ToList().ForEach(action => action(builder)); - return builder; - } - - internal void ConfigureServices(HostBuilderContext context, IServiceCollection services) - { - AddCommandSetFactoryMonitors(services); - AddCommandSetDocuments(services); - AddCommandSetTemplateReaders(services); - } - - internal void ConfigureServices(IServiceProvider services) + internal class ConfigSourceBuilder : IConfigureSourceBuilder { - // no post-build configuration required - } + internal static ConfigSourceBuilder Build(IEnumerable> actions) + { + var builder = new ConfigSourceBuilder(); + actions.ToList().ForEach(action => action(builder)); + return builder; + } - public IConfigureSourceBuilder AddDocument(string documentName, TextReader reader) - { - _documents.Add(new KeyValuePair(documentName, reader)); - return this; - } + internal void ConfigureServices(HostBuilderContext context, IServiceCollection services) + { + AddCommandSetFactoryMonitors(services); + AddCommandSetDocuments(services); + AddCommandSetTemplateReaders(services); + } - public IConfigureSourceBuilder AddTemplateReader(Func reader) - { - _templateReaders.Add(reader); - return this; - } + internal void ConfigureServices(IServiceProvider services) + { + // no post-build configuration required + } - public IConfigureSourceBuilder AddFile(string fileName) - { - var fi = new FileInfo(fileName); - if (!fi.Exists) throw FileHelpers.ErrorFileNotFoundException(fileName); + public IConfigureSourceBuilder AddDocument(string documentName, TextReader reader) + { + _documents.Add(new KeyValuePair(documentName, reader)); + return this; + } - return MonitorFolder(fi.DirectoryName!, fi.Name); - } + public IConfigureSourceBuilder AddTemplateReader(Func reader) + { + _templateReaders.Add(reader); + return this; + } - public IConfigureSourceBuilder MonitorFolder(string folder, string pattern = "*.mac") - { - _monitors.Add(new KeyValuePair(folder, pattern)); - return this; - } + public IConfigureSourceBuilder AddFile(string fileName) + { + var fi = new FileInfo(fileName); + if (!fi.Exists) throw FileHelpers.ErrorFileNotFoundException(fileName); - public IConfigureSourceBuilder UseDefaultFolderMonitor(bool useDefaultFolderMonitor = true) - { - _useDefaultMonitor = useDefaultFolderMonitor; - return this; - } + return MonitorFolder(fi.DirectoryName!, fi.Name); + } - private void AddCommandSetFactoryMonitors(IServiceCollection services) - { - if (_useDefaultMonitor) + public IConfigureSourceBuilder MonitorFolder(string folder, string pattern = "*.mac") { - services.AddSingleton(services => new DefaultFileFolderCommandSetFactory(services)); + _monitors.Add(new KeyValuePair(folder, pattern)); + return this; } - foreach (var monitor in _monitors) + public IConfigureSourceBuilder UseDefaultFolderMonitor(bool useDefaultFolderMonitor = true) { - services.AddSingleton(services => new FileFolderCommandSetFactory(services, monitor.Key, monitor.Value)); + _useDefaultMonitor = useDefaultFolderMonitor; + return this; } - } - private void AddCommandSetTemplateReaders(IServiceCollection services) - { - if (_templateReaders.Count > 0) + private void AddCommandSetFactoryMonitors(IServiceCollection services) { - services.AddSingleton(services => new TemplateReaderContextResolver(_templateReaders)); + if (_useDefaultMonitor) + { + services.AddSingleton(services => new DefaultFileFolderCommandSetFactory(services)); + } + + foreach (var monitor in _monitors) + { + services.AddSingleton(services => new FileFolderCommandSetFactory(services, monitor.Key, monitor.Value)); + } } - } + private void AddCommandSetTemplateReaders(IServiceCollection services) + { + if (_templateReaders.Count > 0) + { + services.AddSingleton(services => new TemplateReaderContextResolver(_templateReaders)); + } - private void AddCommandSetDocuments(IServiceCollection services) - { - foreach (var item in _documents) + } + + private void AddCommandSetDocuments(IServiceCollection services) { - services.AddSingleton(services => new TextReaderCommandSetFactory(services, item.Key, item.Value)); + foreach (var item in _documents) + { + services.AddSingleton(services => new TextReaderCommandSetFactory(services, item.Key, item.Value)); + } } - } - private bool _useDefaultMonitor = false; - private List> _monitors = new(); - private List> _documents = new(); - private List> _templateReaders = new(); -} + private bool _useDefaultMonitor = false; + private List> _monitors = new List>(); + private List> _documents = new List>(); + private List> _templateReaders = new List>(); + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemBuilder/ConfigSpeechBuilder.cs b/src/cs/CommandSystemBuilder/ConfigSpeechBuilder.cs index cbba8492..1db465e1 100644 --- a/src/cs/CommandSystemBuilder/ConfigSpeechBuilder.cs +++ b/src/cs/CommandSystemBuilder/ConfigSpeechBuilder.cs @@ -1,22 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; using macaroni.Interfaces; using Microsoft.CognitiveServices.Speech.Audio; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; -namespace macaroni; - -internal class ConfigSpeechBuilder : IConfigureSpeechBuilder +namespace macaroni { - internal static ConfigSpeechBuilder Build(IEnumerable> actions) + internal class ConfigSpeechBuilder : IConfigureSpeechBuilder { - var builder = new ConfigSpeechBuilder(); - actions.ToList().ForEach(action => action(builder)); - return builder; - } + internal static ConfigSpeechBuilder Build(IEnumerable> actions) + { + var builder = new ConfigSpeechBuilder(); + actions.ToList().ForEach(action => action(builder)); + return builder; + } - internal void ConfigureServices(HostBuilderContext context, IServiceCollection services) - { - SetAudioConfig(services); - } + internal void ConfigureServices(HostBuilderContext context, IServiceCollection services) + { + SetAudioConfig(services); + } internal void ConfigureServices(IServiceProvider services) { @@ -36,63 +40,63 @@ public IConfigureSpeechBuilder AddSpeakingStateChangedHandler(Action reader, Action? closer) - { - _reader = reader; - _closer = closer; - return this; - } + public IConfigureSpeechBuilder UsePullStream(Func reader, Action? closer) + { + _reader = reader; + _closer = closer; + return this; + } - private void SetGlobalNamedStates(IServiceProvider services) - { - var states = services.GetRequiredService(); - states.SetNamedState("__macaroni.defaultListeningState", _defaultListeningState.ToString()); - states.SetNamedState("__macaroni.useNuggets", _useNuggets.ToString()); - states.SetNamedState("__macaroni.useCLU", _useCLU.ToString()); - - var keywordOk = !string.IsNullOrWhiteSpace(_keyword) && !string.IsNullOrWhiteSpace(_keywordModelFile); - MR.DBG_TRACE_INFO("Keyword specified = " + keywordOk.ToString()); - if (keywordOk) + private void SetGlobalNamedStates(IServiceProvider services) { - states.SetNamedState("__macaroni.keyword", _keyword!); - states.SetNamedState("__macaroni.keywordModelFile", _keywordModelFile!); + var states = services.GetRequiredService(); + states.SetNamedState("__macaroni.defaultListeningState", _defaultListeningState.ToString()); + states.SetNamedState("__macaroni.useNuggets", _useNuggets.ToString()); + states.SetNamedState("__macaroni.useCLU", _useCLU.ToString()); + + var keywordOk = !string.IsNullOrWhiteSpace(_keyword) && !string.IsNullOrWhiteSpace(_keywordModelFile); + MR.DBG_TRACE_INFO("Keyword specified = " + keywordOk.ToString()); + if (keywordOk) + { + states.SetNamedState("__macaroni.keyword", _keyword!); + states.SetNamedState("__macaroni.keywordModelFile", _keywordModelFile!); + } } - } - private void SetAudioConfig(IServiceCollection services) - { - var audioConfigService = new AudioConfigService(); - if (_reader != null) + private void SetAudioConfig(IServiceCollection services) { - var callback = new CustomPullAudioInputStreamCallback(_reader, _closer); - var pullStream = PullAudioInputStream.CreatePullStream(callback); - audioConfigService?.SetAudioConfig(AudioConfig.FromStreamInput(pullStream)); + var audioConfigService = new AudioConfigService(); + if (_reader != null) + { + var callback = new CustomPullAudioInputStreamCallback(_reader, _closer); + var pullStream = PullAudioInputStream.CreatePullStream(callback); + audioConfigService?.SetAudioConfig(AudioConfig.FromStreamInput(pullStream)); + } + services.AddSingleton(audioConfigService!); } - services.AddSingleton(audioConfigService!); - } private void RegisterBroadcastNotifications(IServiceProvider services) { @@ -133,32 +137,33 @@ private void BroadcastSynthesizerStateChangedCallback(string scopeId, string cal private Func? _reader; private Action? _closer; - private List> _listeningStateChangedHandlers = new(); - private List> _speakingStateChangedHandlers = new(); + private List> _listeningStateChangedHandlers = new List>(); + private List> _speakingStateChangedHandlers = new List>(); - private class CustomPullAudioInputStreamCallback : PullAudioInputStreamCallback - { - public CustomPullAudioInputStreamCallback(Func reader, Action? closer) + private class CustomPullAudioInputStreamCallback : PullAudioInputStreamCallback { - this._reader = reader; - this._closer = closer; - } + public CustomPullAudioInputStreamCallback(Func reader, Action? closer) + { + this._reader = reader; + this._closer = closer; + } - public override int Read(byte[] dataBuffer, uint size) - { - return _reader(dataBuffer, size); - } + public override int Read(byte[] dataBuffer, uint size) + { + return _reader(dataBuffer, size); + } - public override void Close() - { - if (_closer != null) + public override void Close() { - _closer(); + if (_closer != null) + { + _closer(); + } + base.Close(); } - base.Close(); - } - private Func _reader; - private Action? _closer; + private Func _reader; + private Action? _closer; + } } -} +} \ No newline at end of file diff --git a/src/cs/CommandSystemBuilder/ConfigUiBuilder.cs b/src/cs/CommandSystemBuilder/ConfigUiBuilder.cs index 53f761b0..8ef6f3a1 100644 --- a/src/cs/CommandSystemBuilder/ConfigUiBuilder.cs +++ b/src/cs/CommandSystemBuilder/ConfigUiBuilder.cs @@ -1,106 +1,111 @@ +using System; +using System.Collections.Generic; +using System.Linq; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; -namespace macaroni; - -internal class ConfigUiBuilder : IConfigureUiBuilder +namespace macaroni { - public static ConfigUiBuilder Build(IEnumerable> actions) - { - var builder = new ConfigUiBuilder(); - actions.ToList().ForEach(action => action(builder)); - return builder; - } - - public void ConfigureServices(HostBuilderContext context, IServiceCollection services) - { - BuildOnScreenDisplayService(services); - BuildMessageBoxService(services); - } - - public void ConfigureServices(IServiceProvider services) + internal class ConfigUiBuilder : IConfigureUiBuilder { - // no post-build configuration required - } + public static ConfigUiBuilder Build(IEnumerable> actions) + { + var builder = new ConfigUiBuilder(); + actions.ToList().ForEach(action => action(builder)); + return builder; + } - public IConfigureUiBuilder UseAlert(Action alert) - { - _useAlertAction = alert; - return this; - } + public void ConfigureServices(HostBuilderContext context, IServiceCollection services) + { + BuildOnScreenDisplayService(services); + BuildMessageBoxService(services); + } - public IConfigureUiBuilder UseAlert(Func alert) - { - _useAlertFunc = alert; - return this; - } + public void ConfigureServices(IServiceProvider services) + { + // no post-build configuration required + } - public IConfigureUiBuilder UseConfirm(Action confirm) - { - _useConfirmAction = confirm; - return this; - } + public IConfigureUiBuilder UseAlert(Action alert) + { + _useAlertAction = alert; + return this; + } - public IConfigureUiBuilder UseConfirm(Func confirm) - { - _useConfirmFunc = confirm; - return this; - } + public IConfigureUiBuilder UseAlert(Func alert) + { + _useAlertFunc = alert; + return this; + } - public IConfigureUiBuilder UseDisplay(Action display) - { - _useDisplayAction = display; - return this; - } + public IConfigureUiBuilder UseConfirm(Action confirm) + { + _useConfirmAction = confirm; + return this; + } - public IConfigureUiBuilder UsePrompt(Func prompt) - { - _usePromptFunc = prompt; - return this; - } + public IConfigureUiBuilder UseConfirm(Func confirm) + { + _useConfirmFunc = confirm; + return this; + } - public IConfigureUiBuilder UsePick(Func, string?, string?> pick) - { - _usePickFunc = pick; - return this; - } + public IConfigureUiBuilder UseDisplay(Action display) + { + _useDisplayAction = display; + return this; + } - private void BuildOnScreenDisplayService(IServiceCollection services) - { - if (_useDisplayAction != null) + public IConfigureUiBuilder UsePrompt(Func prompt) { - var callbackService = new CallbackOnScreenDisplayService(_useDisplayAction, (tips, moreTips) => { }); - services.AddSingleton(callbackService); + _usePromptFunc = prompt; + return this; } - } - private void BuildMessageBoxService(IServiceCollection services) - { - var alertOk = _useAlertAction != null || _useAlertFunc != null; - var confirmOk = _useConfirmAction != null || _useConfirmFunc != null; - var promptOk = _usePromptFunc != null; - var pickOk = _usePickFunc != null; + public IConfigureUiBuilder UsePick(Func, string?, string?> pick) + { + _usePickFunc = pick; + return this; + } - if (alertOk || confirmOk || promptOk || pickOk) + private void BuildOnScreenDisplayService(IServiceCollection services) { - _useAlertFunc ??= _useAlertFunc = _useAlertAction != null - ? new Func((message, title, timeout) => { _useAlertAction(message, title, timeout); return true; }) - : new Func((message, title, timeout) => { return false; }); - _useConfirmFunc ??= _useConfirmAction != null - ? new Func((message, title, timeout) => { _useConfirmAction(message, title, timeout); return true; }) - : new Func((message, title, timeout) => { return false; }); - _usePromptFunc ??= new Func((message, title, text, timeout) => { return null; }); - _usePickFunc ??= new Func, string?, string?>((message, title, timeout, choices, choice) => { return null; }); + if (_useDisplayAction != null) + { + var callbackService = new CallbackOnScreenDisplayService(_useDisplayAction, (tips, moreTips) => { }); + services.AddSingleton(callbackService); + } + } - var messageBoxService = new CallbackMessageBoxService(_useAlertFunc, _useConfirmFunc, _usePromptFunc, _usePickFunc); - services.AddSingleton(messageBoxService); + private void BuildMessageBoxService(IServiceCollection services) + { + var alertOk = _useAlertAction != null || _useAlertFunc != null; + var confirmOk = _useConfirmAction != null || _useConfirmFunc != null; + var promptOk = _usePromptFunc != null; + var pickOk = _usePickFunc != null; + + if (alertOk || confirmOk || promptOk || pickOk) + { + _useAlertFunc ??= _useAlertFunc = _useAlertAction != null + ? new Func((message, title, timeout) => { _useAlertAction(message, title, timeout); return true; }) + : new Func((message, title, timeout) => { return false; }); + _useConfirmFunc ??= _useConfirmAction != null + ? new Func((message, title, timeout) => { _useConfirmAction(message, title, timeout); return true; }) + : new Func((message, title, timeout) => { return false; }); + _usePromptFunc ??= new Func((message, title, text, timeout) => { return null; }); + _usePickFunc ??= new Func, string?, string?>((message, title, timeout, choices, choice) => { return null; }); + + var messageBoxService = new CallbackMessageBoxService(_useAlertFunc, _useConfirmFunc, _usePromptFunc, _usePickFunc); + services.AddSingleton(messageBoxService); + } } - } - private Action? _useDisplayAction; - private Action? _useAlertAction; - private Func? _useAlertFunc; - private Action? _useConfirmAction; - private Func? _useConfirmFunc; - private Func? _usePromptFunc; - private Func, string?, string?>? _usePickFunc; -} + private Action? _useDisplayAction; + private Action? _useAlertAction; + private Func? _useAlertFunc; + private Action? _useConfirmAction; + private Func? _useConfirmFunc; + private Func? _usePromptFunc; + private Func, string?, string?>? _usePickFunc; + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/AudioConfigService.cs b/src/cs/CommandSystemServices/AudioConfigService.cs index 39053652..125f703a 100644 --- a/src/cs/CommandSystemServices/AudioConfigService.cs +++ b/src/cs/CommandSystemServices/AudioConfigService.cs @@ -1,24 +1,25 @@ using macaroni.Interfaces; using Microsoft.CognitiveServices.Speech.Audio; -namespace macaroni; - -internal class AudioConfigService : IAudioConfigService +namespace macaroni { - public AudioConfigService() + internal class AudioConfigService : IAudioConfigService { - _audioConfig = null; - } + public AudioConfigService() + { + _audioConfig = null; + } - public void SetAudioConfig(AudioConfig audioConfig) - { - _audioConfig = audioConfig; - } + public void SetAudioConfig(AudioConfig audioConfig) + { + _audioConfig = audioConfig; + } - public AudioConfig GetAudioConfig() - { - return _audioConfig ?? AudioConfig.FromDefaultMicrophoneInput(); - } + public AudioConfig GetAudioConfig() + { + return _audioConfig ?? AudioConfig.FromDefaultMicrophoneInput(); + } - private AudioConfig? _audioConfig; -} + private AudioConfig? _audioConfig; + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/BroadcastExceptionService.cs b/src/cs/CommandSystemServices/BroadcastExceptionService.cs index 49db5cc5..6a0bac0a 100644 --- a/src/cs/CommandSystemServices/BroadcastExceptionService.cs +++ b/src/cs/CommandSystemServices/BroadcastExceptionService.cs @@ -1,84 +1,90 @@ -namespace macaroni; +using System; +using System.Collections.Generic; +using System.Linq; -internal class BroadcastExceptionService : IBroadcastExceptionService +namespace macaroni { - void IBroadcastExceptionService.StartNotify(string scopeId, string callbackId, ExceptionKind kind, Action callback) + + internal class BroadcastExceptionService : IBroadcastExceptionService { - lock(_exceptionCallbacks) + void IBroadcastExceptionService.StartNotify(string scopeId, string callbackId, ExceptionKind kind, Action callback) { - var messageCallback = new ExceptionCallback() { ScopeId = scopeId, CallbackId = callbackId, Kind = kind, Callback = callback }; - AddExceptionCallback(messageCallback); + lock (_exceptionCallbacks) + { + var messageCallback = new ExceptionCallback() { ScopeId = scopeId, CallbackId = callbackId, Kind = kind, Callback = callback }; + AddExceptionCallback(messageCallback); + } } - } - void IBroadcastExceptionService.StopNotify(string scopeId, string? callbackId) - { - lock(_exceptionCallbacks) + void IBroadcastExceptionService.StopNotify(string scopeId, string? callbackId) { - RemoveExceptionCallback(scopeId, callbackId); + lock (_exceptionCallbacks) + { + RemoveExceptionCallback(scopeId, callbackId); + } } - } - void IBroadcastExceptionService.BroadcastException(ExceptionKind kind, Exception ex) - { - MR.DBG_TRACE_VERBOSE($"BroadcastException: {kind} {ex.GetType()}"); - lock(_exceptionCallbacks) + void IBroadcastExceptionService.BroadcastException(ExceptionKind kind, Exception ex) { - var ecs = GetExceptionCallbacks(kind); - foreach (var ec in ecs) + MR.DBG_TRACE_VERBOSE($"BroadcastException: {kind} {ex.GetType()}"); + lock (_exceptionCallbacks) { - ec.Callback(ex); + var ecs = GetExceptionCallbacks(kind); + foreach (var ec in ecs) + { + ec.Callback(ex); + } } } - } - private IEnumerable GetExceptionCallbacks(ExceptionKind kind) - { - return _exceptionCallbacks.SelectMany(x => x.Value - .Where(kvp => kvp.Value.Kind == kind) - .Select(kvp => kvp.Value)); - } + private IEnumerable GetExceptionCallbacks(ExceptionKind kind) + { + return _exceptionCallbacks.SelectMany(x => x.Value + .Where(kvp => kvp.Value.Kind == kind) + .Select(kvp => kvp.Value)); + } - private void AddExceptionCallback(ExceptionCallback mc) - { - RemoveExceptionCallback(mc.ScopeId, mc.CallbackId); - RequireScope(mc.ScopeId).Add(mc.CallbackId, mc); - } + private void AddExceptionCallback(ExceptionCallback mc) + { + RemoveExceptionCallback(mc.ScopeId, mc.CallbackId); + RequireScope(mc.ScopeId).Add(mc.CallbackId, mc); + } - private void RemoveExceptionCallback(string scopeId, string? callbackId) - { - var scope = GetScope(scopeId); - if (callbackId == null) + private void RemoveExceptionCallback(string scopeId, string? callbackId) { - scope?.Clear(); + var scope = GetScope(scopeId); + if (callbackId == null) + { + scope?.Clear(); + } + else + { + scope?.Remove(callbackId); + } } - else + + private IDictionary? GetScope(string scopeId) { - scope?.Remove(callbackId); + return _exceptionCallbacks.ContainsKey(scopeId) ? _exceptionCallbacks[scopeId] : null; } - } - private IDictionary? GetScope(string scopeId) - { - return _exceptionCallbacks.ContainsKey(scopeId) ? _exceptionCallbacks[scopeId] : null; - } + private IDictionary RequireScope(string scopeId) + { + if (!_exceptionCallbacks.ContainsKey(scopeId)) + { + _exceptionCallbacks[scopeId] = new Dictionary(); + } + return _exceptionCallbacks[scopeId]; + } - private IDictionary RequireScope(string scopeId) - { - if (!_exceptionCallbacks.ContainsKey(scopeId)) + internal struct ExceptionCallback { - _exceptionCallbacks[scopeId] = new Dictionary(); + internal string ScopeId; + internal string CallbackId; + internal ExceptionKind Kind; + internal Action Callback; } - return _exceptionCallbacks[scopeId]; - } - internal struct ExceptionCallback - { - internal string ScopeId; - internal string CallbackId; - internal ExceptionKind Kind; - internal Action Callback; + private Dictionary> _exceptionCallbacks = new Dictionary>(); } - - private Dictionary> _exceptionCallbacks = new(); -} +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/BroadcastMessageService.cs b/src/cs/CommandSystemServices/BroadcastMessageService.cs index cd1c4697..8435e27a 100644 --- a/src/cs/CommandSystemServices/BroadcastMessageService.cs +++ b/src/cs/CommandSystemServices/BroadcastMessageService.cs @@ -1,103 +1,108 @@ -namespace macaroni; +using System; +using System.Collections.Generic; +using System.Linq; -internal class BroadcastMessageService : IBroadcastMessageService +namespace macaroni { - void IBroadcastMessageService.StartNotify(string scopeId, string callbackId, string messageName, string? messageValue, Action callback) + internal class BroadcastMessageService : IBroadcastMessageService { - lock(_messageCallbacks) + void IBroadcastMessageService.StartNotify(string scopeId, string callbackId, string messageName, string? messageValue, Action callback) { - var messageCallback = new MessageCallback() { ScopeId = scopeId, CallbackId = callbackId, MessageName = messageName, MessageValue = messageValue, Callback = callback }; - AddMessageCallback(messageCallback); + lock (_messageCallbacks) + { + var messageCallback = new MessageCallback() { ScopeId = scopeId, CallbackId = callbackId, MessageName = messageName, MessageValue = messageValue, Callback = callback }; + AddMessageCallback(messageCallback); + } } - } - void IBroadcastMessageService.StopNotify(string scopeId, string? callbackId) - { - lock(_messageCallbacks) + void IBroadcastMessageService.StopNotify(string scopeId, string? callbackId) { - RemoveMessageCallback(scopeId, callbackId); + lock (_messageCallbacks) + { + RemoveMessageCallback(scopeId, callbackId); + } } - } - void IBroadcastMessageService.BroadcastMessage(string name, string? value, string? scope) - { - MR.DBG_TRACE_VERBOSE($"BroadcastMessage: {name} {value} ... (started)"); - lock(_messageCallbacks) + void IBroadcastMessageService.BroadcastMessage(string name, string? value, string? scope) { - var mcs = GetMessageCallbacks(name, value, scope); - foreach (var mc in mcs) + MR.DBG_TRACE_VERBOSE($"BroadcastMessage: {name} {value} ... (started)"); + lock (_messageCallbacks) { - mc.Callback(mc.ScopeId, mc.CallbackId, name, value); + var mcs = GetMessageCallbacks(name, value, scope); + foreach (var mc in mcs) + { + mc.Callback(mc.ScopeId, mc.CallbackId, name, value); + } } + MR.DBG_TRACE_VERBOSE($"BroadcastMessage: {name} {value} ... (done!!)"); } - MR.DBG_TRACE_VERBOSE($"BroadcastMessage: {name} {value} ... (done!!)"); - } - private IEnumerable GetMessageCallbacks(string name, string? value, string? scope) - { - MR.DBG_TRACE_INFO($"GetMessageCallbacks: name={name}, value={value} ... (started)"); - var callbacks = _messageCallbacks.SelectMany(x => x.Value - .Where(kvp => kvp.Value.MessageName == name || kvp.Value.MessageName == "*") - .Where(kvp => kvp.Value.MessageValue == null || kvp.Value.MessageValue == value) - .Select(kvp => kvp.Value)) - .ToList(); + private IEnumerable GetMessageCallbacks(string name, string? value, string? scope) + { + MR.DBG_TRACE_INFO($"GetMessageCallbacks: name={name}, value={value} ... (started)"); + var callbacks = _messageCallbacks.SelectMany(x => x.Value + .Where(kvp => kvp.Value.MessageName == name || kvp.Value.MessageName == "*") + .Where(kvp => kvp.Value.MessageValue == null || kvp.Value.MessageValue == value) + .Select(kvp => kvp.Value)) + .ToList(); - if (callbacks.Count == 0) + if (callbacks.Count == 0) + { + MR.DBG_TRACE_INFO($"GetMessageCallbacks: name={name}, value={value} ... (not found)"); + } + else + { + foreach (var callback in callbacks) + { + MR.DBG_TRACE_INFO($"GetMessageCallbacks: name={name}, value={value} ... (found: callbackId={callback.CallbackId})"); + } + } + + return callbacks; + } + + private void AddMessageCallback(MessageCallback mc) { - MR.DBG_TRACE_INFO($"GetMessageCallbacks: name={name}, value={value} ... (not found)"); + RemoveMessageCallback(mc.ScopeId, mc.CallbackId); + RequireScope(mc.ScopeId).Add(mc.CallbackId, mc); } - else + + private void RemoveMessageCallback(string scopeId, string? callbackId) { - foreach (var callback in callbacks) + var scope = GetScope(scopeId); + if (callbackId == null) { - MR.DBG_TRACE_INFO($"GetMessageCallbacks: name={name}, value={value} ... (found: callbackId={callback.CallbackId})"); + scope?.Clear(); + } + else + { + scope?.Remove(callbackId); } } - return callbacks; - } - - private void AddMessageCallback(MessageCallback mc) - { - RemoveMessageCallback(mc.ScopeId, mc.CallbackId); - RequireScope(mc.ScopeId).Add(mc.CallbackId, mc); - } - - private void RemoveMessageCallback(string scopeId, string? callbackId) - { - var scope = GetScope(scopeId); - if (callbackId == null) + private IDictionary? GetScope(string scopeId) { - scope?.Clear(); + return _messageCallbacks.ContainsKey(scopeId) ? _messageCallbacks[scopeId] : null; } - else + + private IDictionary RequireScope(string scopeId) { - scope?.Remove(callbackId); + if (!_messageCallbacks.ContainsKey(scopeId)) + { + _messageCallbacks[scopeId] = new Dictionary(); + } + return _messageCallbacks[scopeId]; } - } - - private IDictionary? GetScope(string scopeId) - { - return _messageCallbacks.ContainsKey(scopeId) ? _messageCallbacks[scopeId] : null; - } - private IDictionary RequireScope(string scopeId) - { - if (!_messageCallbacks.ContainsKey(scopeId)) + internal struct MessageCallback { - _messageCallbacks[scopeId] = new Dictionary(); + internal string ScopeId; + internal string CallbackId; + internal string MessageName; + internal string? MessageValue; + internal Action Callback; } - return _messageCallbacks[scopeId]; - } - internal struct MessageCallback - { - internal string ScopeId; - internal string CallbackId; - internal string MessageName; - internal string? MessageValue; - internal Action Callback; + private Dictionary> _messageCallbacks = new Dictionary>(); } - - private Dictionary> _messageCallbacks = new(); -} +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/CallbackMessageBoxService.cs b/src/cs/CommandSystemServices/CallbackMessageBoxService.cs index d41c4785..f15c444f 100644 --- a/src/cs/CommandSystemServices/CallbackMessageBoxService.cs +++ b/src/cs/CommandSystemServices/CallbackMessageBoxService.cs @@ -1,45 +1,49 @@ -namespace macaroni; +using System; +using System.Collections.Generic; -internal class CallbackMessageBoxService : IMessageBoxService +namespace macaroni { - public CallbackMessageBoxService(Func alert, Func confirm, Func prompt, Func, string?, string?> pick) + internal class CallbackMessageBoxService : IMessageBoxService { - _alert = alert; - _confirm = confirm; - _prompt = prompt; - _pick = pick; - } + public CallbackMessageBoxService(Func alert, Func confirm, Func prompt, Func, string?, string?> pick) + { + _alert = alert; + _confirm = confirm; + _prompt = prompt; + _pick = pick; + } - public bool Show(string message, string? title, string? timeout) - { - var timeoutValue = timeout != null ? int.Parse(timeout) : 0; - return _alert(message, title, timeoutValue); - } + public bool Show(string message, string? title, string? timeout) + { + var timeoutValue = timeout != null ? int.Parse(timeout) : 0; + return _alert(message, title, timeoutValue); + } - public bool Confirm(string message, string? title, string? timeout) - { - var timeoutValue = timeout != null ? int.Parse(timeout) : 0; - return _confirm(message, title, timeoutValue); - } + public bool Confirm(string message, string? title, string? timeout) + { + var timeoutValue = timeout != null ? int.Parse(timeout) : 0; + return _confirm(message, title, timeoutValue); + } - public bool Prompt(string message, string? title, string? timeout, ref string text) - { - var timeoutValue = timeout != null ? int.Parse(timeout) : 0; - var response = _prompt(message, title, text, timeoutValue); - text = response ?? ""; - return response != null; - } + public bool Prompt(string message, string? title, string? timeout, ref string text) + { + var timeoutValue = timeout != null ? int.Parse(timeout) : 0; + var response = _prompt(message, title, text, timeoutValue); + text = response ?? ""; + return response != null; + } - public bool Pick(IEnumerable choices, string? message, string? title, string? timeout, ref string? choice) - { - var timeoutValue = timeout != null ? int.Parse(timeout) : 0; - var response = _pick(message, title, timeoutValue, choices, choice); - choice = response ?? ""; - return response != null; - } + public bool Pick(IEnumerable choices, string? message, string? title, string? timeout, ref string? choice) + { + var timeoutValue = timeout != null ? int.Parse(timeout) : 0; + var response = _pick(message, title, timeoutValue, choices, choice); + choice = response ?? ""; + return response != null; + } - private Func _alert; - private Func _confirm; - private Func _prompt; - private Func, string?, string?> _pick; -} + private Func _alert; + private Func _confirm; + private Func _prompt; + private Func, string?, string?> _pick; + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/CallbackOnScreenDisplayService.cs b/src/cs/CommandSystemServices/CallbackOnScreenDisplayService.cs index 14165c69..d5ef6569 100644 --- a/src/cs/CommandSystemServices/CallbackOnScreenDisplayService.cs +++ b/src/cs/CommandSystemServices/CallbackOnScreenDisplayService.cs @@ -1,23 +1,28 @@ -namespace macaroni; -internal class CallbackOnScreenDisplayService : IOnScreenDisplayService +using System; +using System.Collections.Generic; + +namespace macaroni { - public CallbackOnScreenDisplayService(Action displayText, Action?, Func?>?> displayTips) + internal class CallbackOnScreenDisplayService : IOnScreenDisplayService { - _displayText = displayText; - _displayTips = displayTips; - } + public CallbackOnScreenDisplayService(Action displayText, Action?, Func?>?> displayTips) + { + _displayText = displayText; + _displayTips = displayTips; + } - public void DisplayText(string text, string from, bool? pending, int timeout) - { - _displayText(text, from, pending, timeout); - } + public void DisplayText(string text, string from, bool? pending, int timeout) + { + _displayText(text, from, pending, timeout); + } - public void DisplayTips(IEnumerable? tips, Func?>? moreTips) - { - _displayTips(tips, moreTips); - } + public void DisplayTips(IEnumerable? tips, Func?>? moreTips) + { + _displayTips(tips, moreTips); + } - private Action _displayText; - private Action?, Func?>?> _displayTips; -} + private Action _displayText; + private Action?, Func?>?> _displayTips; + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/CommandExecutionService.cs b/src/cs/CommandSystemServices/CommandExecutionService.cs index 0ca322dc..26c2f935 100644 --- a/src/cs/CommandSystemServices/CommandExecutionService.cs +++ b/src/cs/CommandSystemServices/CommandExecutionService.cs @@ -1,456 +1,454 @@ -using Microsoft.CognitiveServices.Speech; -using Microsoft.CognitiveServices.Speech.Audio; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; -using System.Diagnostics; -using System.Text; -using Newtonsoft.Json; -using Microsoft.ClearScript.V8; -using System; -namespace macaroni; - -internal partial class CommandExecutionService : ICommandExecutionService +namespace macaroni { - public CommandExecutionService(IServiceProvider services, IBroadcastMessageService broadcastMessageService, ITimeIntervalService timerService) + internal partial class CommandExecutionService : ICommandExecutionService { - _serviceProvider = services; - _timerService = timerService; - broadcastMessageService.StartNotify(nameof(CommandExecutionService), nameof(CommandExecutionService), "unexpected.phrase", null, PhraseNotRecognized); - } + public CommandExecutionService(IServiceProvider services, IBroadcastMessageService broadcastMessageService, ITimeIntervalService timerService) + { + _serviceProvider = services; + _timerService = timerService; + broadcastMessageService.StartNotify(nameof(CommandExecutionService), nameof(CommandExecutionService), "unexpected.phrase", null, PhraseNotRecognized); + } - public void Execute(ICommand? command, Action? configureContext = null) - { - // All "ICommand" executions flow thru this function. - // - // When a "dialog command" is executed, it can have two possible outcomes: - // (1) the dialog is "completed" at the end of the executor list execution, meaning - // there are no additional expectations at this time (the trigger collection is empty) - // (2) the dialog is "open" at the end of the executor list execution, and - // additional expectations (trigger collection) is populated (see `ICommand.Expecting`) - // - // NOTE: All "single turn" commands that don't use the "dialog" executor, are considered "completed" - // at the end of the execution of their list of executors. The second case never applies in those instances. - - // In the second case above ("open" dialog commands), there are different "next turn" things that could - // happen. The most hopeful "next thing" is that the user does what is asked of them (supplying the - // requested information). When that happens, and there is no further "expectations", the command - // executor list is fully run, and the command is, at that point, finally considered "completed". - - // However, in some cases for "open" dialog commands, the user might say something that is unexpected from the - // "open" dialog command's point of view, or say nothing at all. That could be one of two cases: - // (a) the user spoke something that matched another valid command defined elsewhere in the command system - // (b) the user spoke something that was either not understandable (babble) or something that wasn't matched - // by a command authored elsewhere in the supplied command sets (neither pattern match nor CLU intent match). - // (c) the user spoke nothing - - // For each of these cases (a, b, and c), some dialog scenarios will want to handle the situation differently. - // * some will "do nothing" and "ignore" the user interaction from this dialog command's perspective - // * some will "cancel" the "open" dialog - // * some will "retry" (or re-trigger) the dialog command, likely to "re-prompt" for missing information, or - // guidance on what the user should do next. - // * some will want to run "custom logic" to be authored that doesn't fit any of the above - - // This function has multiple purposes in this "system" described above. - // - // (1) when a command starts executing, "cancel" all the commands wanting to be canceled - // (2) when a command "finishes" executing, determine if the command was "completed" or "not completed" - // (3) based on it's completed status, - // (a) if it's completed, - // - ensure it's no longer being kept track of as an "open" command - // - find the most recent command that should be "re-triggered" - // (b) if it's not completed - // - keep track of this "open" dialog command - // - this is done so it can be considered for (1) and (3a) in the future - - if (command == null) - { - MR.DBG_TRACE_INFO($"CommandExecutionService.Execute: command is null"); - } - - if (command != null) - { - Task.Run(() => + public void Execute(ICommand? command, Action? configureContext = null) + { + // All "ICommand" executions flow thru this function. + // + // When a "dialog command" is executed, it can have two possible outcomes: + // (1) the dialog is "completed" at the end of the executor list execution, meaning + // there are no additional expectations at this time (the trigger collection is empty) + // (2) the dialog is "open" at the end of the executor list execution, and + // additional expectations (trigger collection) is populated (see `ICommand.Expecting`) + // + // NOTE: All "single turn" commands that don't use the "dialog" executor, are considered "completed" + // at the end of the execution of their list of executors. The second case never applies in those instances. + + // In the second case above ("open" dialog commands), there are different "next turn" things that could + // happen. The most hopeful "next thing" is that the user does what is asked of them (supplying the + // requested information). When that happens, and there is no further "expectations", the command + // executor list is fully run, and the command is, at that point, finally considered "completed". + + // However, in some cases for "open" dialog commands, the user might say something that is unexpected from the + // "open" dialog command's point of view, or say nothing at all. That could be one of two cases: + // (a) the user spoke something that matched another valid command defined elsewhere in the command system + // (b) the user spoke something that was either not understandable (babble) or something that wasn't matched + // by a command authored elsewhere in the supplied command sets (neither pattern match nor CLU intent match). + // (c) the user spoke nothing + + // For each of these cases (a, b, and c), some dialog scenarios will want to handle the situation differently. + // * some will "do nothing" and "ignore" the user interaction from this dialog command's perspective + // * some will "cancel" the "open" dialog + // * some will "retry" (or re-trigger) the dialog command, likely to "re-prompt" for missing information, or + // guidance on what the user should do next. + // * some will want to run "custom logic" to be authored that doesn't fit any of the above + + // This function has multiple purposes in this "system" described above. + // + // (1) when a command starts executing, "cancel" all the commands wanting to be canceled + // (2) when a command "finishes" executing, determine if the command was "completed" or "not completed" + // (3) based on it's completed status, + // (a) if it's completed, + // - ensure it's no longer being kept track of as an "open" command + // - find the most recent command that should be "re-triggered" + // (b) if it's not completed + // - keep track of this "open" dialog command + // - this is done so it can be considered for (1) and (3a) in the future + + if (command == null) { - MR.DBG_TRACE_INFO($"CommandExecutionService.Execute: command={command.Name} ... starting"); - var context = command.GetExecutionContext(); - configureContext?.Invoke(context); - context.Start(); - - CommandStarting(command); + MR.DBG_TRACE_INFO($"CommandExecutionService.Execute: command is null"); + } - var result = command.Execute(context); - if (result != ExecutionResult.Canceled && context.Result == ExecutionResult.Canceled) + if (command != null) + { + Task.Run(() => { - result = ExecutionResult.Canceled; - } + MR.DBG_TRACE_INFO($"CommandExecutionService.Execute: command={command.Name} ... starting"); + var context = command.GetExecutionContext(); + configureContext?.Invoke(context); + context.Start(); - var completed = result != ExecutionResult.Yielded; - if (completed) CommandCompleted(command, result); - if (!completed) CommandNotCompleted(command); + CommandStarting(command); - MR.DBG_TRACE_INFO($"CommandExecutionService.Execute: command={command.Name} ... result={result}"); - }); - } - } - - public void Cancel(ICommand? command) - { - CancelCommand(command); - } - - public IEnumerable GetNotCompleted() - { - return _notCompletedCommands.ToList(); - } - - private void PhraseNotRecognized(string scopeId, string callbackId, string messageName, string? messageValue) - { - // when a phrase is "not recognized", meaning, no matching intent or pattern is found, this function will - // be called (via "unexpected.phrase" broadcast message... see ctor) - // - // when this happens, two things will result: - // (1) all other "open" dialog commands that are not yet completed, and marked for - // "cancellation upon unexpected phrases", will be "canceled" - // (2) of the remaining "open" dialog commands, if any of them are marked to be "retry"'d (e.g. re-triggered) - // or have a specific list of executors to be run "when unexpected phrases" are spoken, the most recent - // of these commands will be selected, and either "re-triggered" or it's list of "unexpected executors" - // will be executed - - var task = Task.Run(() => - { - var wantCanceled = GetCommandsShouldCancelOnUnexpectedPhrase(); - CancelCommands(wantCanceled); - - var mostRecent = GetMostRecentShouldRetryOrExecuteOnUnexpectedPhrase(); - if (mostRecent != null) RetryOrExecute(mostRecent, mostRecent?.Unexpected?.PhrasePolicy, "unexpected.phrase"); - }); - task.Wait(1000); - } + var result = command.Execute(context); + if (result != ExecutionResult.Canceled && context.Result == ExecutionResult.Canceled) + { + result = ExecutionResult.Canceled; + } - private void CommandStarting(ICommand command) - { - ClearTimerTimeout(command); - if (IsPhraseOrIntentTriggered(command)) - { - MR.DBG_TRACE_VERBOSE($"-- EXECUTE COMMAND (starting): {command.Id}"); - ClearAllTimerTimeouts(); + var completed = result != ExecutionResult.Yielded; + if (completed) CommandCompleted(command, result); + if (!completed) CommandNotCompleted(command); - var wantCanceled = GetCommandsShouldCancelOnUnexpectedCommand(command); - CancelCommands(wantCanceled); + MR.DBG_TRACE_INFO($"CommandExecutionService.Execute: command={command.Name} ... result={result}"); + }); + } } - } - - private void CommandNotCompleted(ICommand notCompleted) - { - MR.DBG_TRACE_VERBOSE($"-- EXECUTE COMMAND (not completed): {notCompleted.Id}"); - YieldCommand(notCompleted); - CheckSetTimer(notCompleted); - } - - private void CommandCompleted(ICommand completed, ExecutionResult result) - { - MR.DBG_TRACE_VERBOSE($"-- EXECUTE COMMAND (completed): {completed.Id}"); - if (IsPhraseOrIntentTriggered(completed)) + public void Cancel(ICommand? command) { - StopCommand(completed, result); - CheckRetryOrExecuteOnUnexpectedCommand(completed, result); + CancelCommand(command); } - else + + public IEnumerable GetNotCompleted() { - StopCommand(completed, result); + return _notCompletedCommands.ToList(); } + private void PhraseNotRecognized(string scopeId, string callbackId, string messageName, string? messageValue) + { + // when a phrase is "not recognized", meaning, no matching intent or pattern is found, this function will + // be called (via "unexpected.phrase" broadcast message... see ctor) + // + // when this happens, two things will result: + // (1) all other "open" dialog commands that are not yet completed, and marked for + // "cancellation upon unexpected phrases", will be "canceled" + // (2) of the remaining "open" dialog commands, if any of them are marked to be "retry"'d (e.g. re-triggered) + // or have a specific list of executors to be run "when unexpected phrases" are spoken, the most recent + // of these commands will be selected, and either "re-triggered" or it's list of "unexpected executors" + // will be executed + + var task = Task.Run(() => + { + var wantCanceled = GetCommandsShouldCancelOnUnexpectedPhrase(); + CancelCommands(wantCanceled); - } + var mostRecent = GetMostRecentShouldRetryOrExecuteOnUnexpectedPhrase(); + if (mostRecent != null) RetryOrExecute(mostRecent, mostRecent?.Unexpected?.PhrasePolicy, "unexpected.phrase"); + }); + task.Wait(1000); + } - private void CheckRetryOrExecuteOnUnexpectedCommand(ICommand completed, ExecutionResult result) - { - var mostRecent = GetMostRecentShouldRetryOrExecuteOnUnexpectedCommand(); - if (mostRecent != null) + private void CommandStarting(ICommand command) { - RetryOrExecute(mostRecent, mostRecent?.Unexpected?.CommandPolicy, "unexpected.command"); + ClearTimerTimeout(command); + if (IsPhraseOrIntentTriggered(command)) + { + MR.DBG_TRACE_VERBOSE($"-- EXECUTE COMMAND (starting): {command.Id}"); + ClearAllTimerTimeouts(); + + var wantCanceled = GetCommandsShouldCancelOnUnexpectedCommand(command); + CancelCommands(wantCanceled); + } } - } - private void CancelCommands(IEnumerable wantCanceled) - { - foreach (var command in wantCanceled.ToList()) + private void CommandNotCompleted(ICommand notCompleted) { - CancelCommand(command); + MR.DBG_TRACE_VERBOSE($"-- EXECUTE COMMAND (not completed): {notCompleted.Id}"); + YieldCommand(notCompleted); + CheckSetTimer(notCompleted); } - } - private void CancelCommand(ICommand? command) - { - if (command != null) + private void CommandCompleted(ICommand completed, ExecutionResult result) { - MR.DBG_TRACE_VERBOSE($"-- CANCEL COMMAND: {command.Id}"); + MR.DBG_TRACE_VERBOSE($"-- EXECUTE COMMAND (completed): {completed.Id}"); - var context = command.GetExecutionContext(); - if (ShouldAutoPushPopListen(context)) + if (IsPhraseOrIntentTriggered(completed)) + { + StopCommand(completed, result); + CheckRetryOrExecuteOnUnexpectedCommand(completed, result); + } + else { - PopListeningState(context); + StopCommand(completed, result); } - command.ClearContext(); - _notCompletedCommands.Remove(command); - context.Cancel(); } - } - private void RetryOrExecute(ICommand command, object? policy, string triggerType) - { - if (ShouldRetryOn(policy)) + private void CheckRetryOrExecuteOnUnexpectedCommand(ICommand completed, ExecutionResult result) { - MR.DBG_TRACE_VERBOSE($"-- EXECUTE COMMAND (retry via execute): {command.Id}"); - Execute(command, context => RegisterTriggerTypeResolver(context, triggerType)); + var mostRecent = GetMostRecentShouldRetryOrExecuteOnUnexpectedCommand(); + if (mostRecent != null) + { + RetryOrExecute(mostRecent, mostRecent?.Unexpected?.CommandPolicy, "unexpected.command"); + } } - else if (ShouldExecuteOn(policy, out var executors)) + + private void CancelCommands(IEnumerable wantCanceled) { - MR.DBG_TRACE_VERBOSE($"-- EXECUTE COMMAND (retry via executors): {command.Id}"); + foreach (var command in wantCanceled.ToList()) + { + CancelCommand(command); + } + } - ClearTimerTimeout(command); + private void CancelCommand(ICommand? command) + { + if (command != null) + { + MR.DBG_TRACE_VERBOSE($"-- CANCEL COMMAND: {command.Id}"); - var context = command.GetExecutionContext(); - RegisterTriggerTypeResolver(context, triggerType); - context.Start(); + var context = command.GetExecutionContext(); + if (ShouldAutoPushPopListen(context)) + { + PopListeningState(context); + } - var result = executors?.Execute(context!) ?? ExecutionResult.Completed; + command.ClearContext(); + _notCompletedCommands.Remove(command); - var remappedResult = RemapUnexpectedExecutorListResult(command, result); - var shouldStopCancelOrCompleteResult = remappedResult != ExecutionResult.Yielded; + context.Cancel(); + } + } - var doAutoPushPopListen = ShouldAutoPushPopListen(context); - if (shouldStopCancelOrCompleteResult) + private void RetryOrExecute(ICommand command, object? policy, string triggerType) + { + if (ShouldRetryOn(policy)) { - PopListeningState(context); - CommandCompleted(command, remappedResult); + MR.DBG_TRACE_VERBOSE($"-- EXECUTE COMMAND (retry via execute): {command.Id}"); + Execute(command, context => RegisterTriggerTypeResolver(context, triggerType)); } - else + else if (ShouldExecuteOn(policy, out var executors)) { - CommandNotCompleted(command); - if (doAutoPushPopListen) + MR.DBG_TRACE_VERBOSE($"-- EXECUTE COMMAND (retry via executors): {command.Id}"); + + ClearTimerTimeout(command); + + var context = command.GetExecutionContext(); + RegisterTriggerTypeResolver(context, triggerType); + context.Start(); + + var result = executors?.Execute(context!) ?? ExecutionResult.Completed; + + var remappedResult = RemapUnexpectedExecutorListResult(command, result); + var shouldStopCancelOrCompleteResult = remappedResult != ExecutionResult.Yielded; + + var doAutoPushPopListen = ShouldAutoPushPopListen(context); + if (shouldStopCancelOrCompleteResult) { - StartListening(); + PopListeningState(context); + CommandCompleted(command, remappedResult); + } + else + { + CommandNotCompleted(command); + if (doAutoPushPopListen) + { + StartListening(); + } } } } - } - private bool ShouldCancelOn(object? policy) - { - return policy is IUnexpectedDialogPolicy.Action && (policy as IUnexpectedDialogPolicy.Action?) == IUnexpectedDialogPolicy.Action.Cancel; - } + private bool ShouldCancelOn(object? policy) + { + return policy is IUnexpectedDialogPolicy.Action && (policy as IUnexpectedDialogPolicy.Action?) == IUnexpectedDialogPolicy.Action.Cancel; + } - private bool ShouldRetryOn(object? policy) - { - return policy is IUnexpectedDialogPolicy.Action && (policy as IUnexpectedDialogPolicy.Action?) == IUnexpectedDialogPolicy.Action.Retry; - } + private bool ShouldRetryOn(object? policy) + { + return policy is IUnexpectedDialogPolicy.Action && (policy as IUnexpectedDialogPolicy.Action?) == IUnexpectedDialogPolicy.Action.Retry; + } - private bool ShouldExecuteOn(object? policy, out IExecutorCollection? executors) - { - executors = policy as IExecutorCollection; - return executors != null; - } + private bool ShouldExecuteOn(object? policy, out IExecutorCollection? executors) + { + executors = policy as IExecutorCollection; + return executors != null; + } - private bool ShouldRetryOrExecute(object? policy) - { - return ShouldRetryOn(policy) || ShouldExecuteOn(policy, out var executors); - } - - private static bool ShouldAutoPushPopListen(IExecutionContext context) - { - return context.Get("AutoPushPopListen", "false") as string == "true"; - } + private bool ShouldRetryOrExecute(object? policy) + { + return ShouldRetryOn(policy) || ShouldExecuteOn(policy, out var executors); + } - private ExecutionResult RemapUnexpectedExecutorListResult(ICommand command, ExecutionResult result) - { - return result switch + private static bool ShouldAutoPushPopListen(IExecutionContext context) { - ExecutionResult.Canceled => ExecutionResult.Canceled, // cancel means cancel - ExecutionResult.Stopped => ExecutionResult.Stopped, // stop means stop + return context.Get("AutoPushPopListen", "false") as string == "true"; + } - // yield and completed are remapped to "yielded" only if the command has expectations - ExecutionResult.Completed or - ExecutionResult.Yielded or - _ => command.Expecting != null ? ExecutionResult.Yielded : ExecutionResult.Stopped - }; - } + private ExecutionResult RemapUnexpectedExecutorListResult(ICommand command, ExecutionResult result) + { + return result switch + { + ExecutionResult.Canceled => ExecutionResult.Canceled, // cancel means cancel + ExecutionResult.Stopped => ExecutionResult.Stopped, // stop means stop + + // yield and completed are remapped to "yielded" only if the command has expectations + ExecutionResult.Completed => command.Expecting != null ? ExecutionResult.Yielded : ExecutionResult.Stopped, + ExecutionResult.Yielded => command.Expecting != null ? ExecutionResult.Yielded : ExecutionResult.Stopped, + _ => command.Expecting != null ? ExecutionResult.Yielded : ExecutionResult.Stopped + }; + } - private void YieldCommand(ICommand notCompleted) - { - var context = notCompleted.GetExecutionContext(); + private void YieldCommand(ICommand notCompleted) + { + var context = notCompleted.GetExecutionContext(); - // ensure the command not completed is at the top of the "stack" to be retried first if/when necessary - _notCompletedCommands.Remove(notCompleted); - _notCompletedCommands.Add(notCompleted); + // ensure the command not completed is at the top of the "stack" to be retried first if/when necessary + _notCompletedCommands.Remove(notCompleted); + _notCompletedCommands.Add(notCompleted); - context.Yield(); - } + context.Yield(); + } - private void StopCommand(ICommand completed, ExecutionResult result) - { - var context = completed.GetExecutionContext(); + private void StopCommand(ICommand completed, ExecutionResult result) + { + var context = completed.GetExecutionContext(); - completed.ClearContext(); - _notCompletedCommands.Remove(completed); + completed.ClearContext(); + _notCompletedCommands.Remove(completed); - switch (result) - { - case ExecutionResult.Completed: - context.Complete(); - break; - case ExecutionResult.Canceled: - context.Cancel(); - break; - default: - context.Stop(); - break; + switch (result) + { + case ExecutionResult.Completed: + context.Complete(); + break; + case ExecutionResult.Canceled: + context.Cancel(); + break; + default: + context.Stop(); + break; + } } - } - private IEnumerable GetCommandsShouldCancelOnUnexpectedCommand(ICommand unexpectedCommand) - { - return _notCompletedCommands.Where(x => x != unexpectedCommand && ShouldCancelOn(x.Unexpected?.CommandPolicy)); - } + private IEnumerable GetCommandsShouldCancelOnUnexpectedCommand(ICommand unexpectedCommand) + { + return _notCompletedCommands.Where(x => x != unexpectedCommand && ShouldCancelOn(x.Unexpected?.CommandPolicy)); + } - private IEnumerable GetCommandsShouldCancelOnUnexpectedPhrase() - { - return _notCompletedCommands.Where(x => ShouldCancelOn(x.Unexpected?.PhrasePolicy)); - } + private IEnumerable GetCommandsShouldCancelOnUnexpectedPhrase() + { + return _notCompletedCommands.Where(x => ShouldCancelOn(x.Unexpected?.PhrasePolicy)); + } - private ICommand? GetMostRecentShouldRetryOrExecuteOnUnexpectedCommand() - { - return _notCompletedCommands.LastOrDefault(x => ShouldRetryOrExecute(x.Unexpected?.CommandPolicy)); - } + private ICommand? GetMostRecentShouldRetryOrExecuteOnUnexpectedCommand() + { + return _notCompletedCommands.LastOrDefault(x => ShouldRetryOrExecute(x.Unexpected?.CommandPolicy)); + } - private ICommand? GetMostRecentShouldRetryOrExecuteOnUnexpectedPhrase() - { - return _notCompletedCommands.LastOrDefault(x => ShouldRetryOrExecute(x.Unexpected?.PhrasePolicy)); - } + private ICommand? GetMostRecentShouldRetryOrExecuteOnUnexpectedPhrase() + { + return _notCompletedCommands.LastOrDefault(x => ShouldRetryOrExecute(x.Unexpected?.PhrasePolicy)); + } - private static string RegisterTriggerTypeResolver(IExecutionContext context, string triggerType) - { - return context.RegisterResolver(nameof(CommandExecutionService), key => key == "trigger.type" ? triggerType : null); - } + private static string RegisterTriggerTypeResolver(IExecutionContext context, string triggerType) + { + return context.RegisterResolver(nameof(CommandExecutionService), key => key == "trigger.type" ? triggerType : null); + } - private bool IsPhraseOrIntentTriggered(ICommand command) - { - var context = command.GetExecutionContext(); + private bool IsPhraseOrIntentTriggered(ICommand command) + { + var context = command.GetExecutionContext(); - var trigger = context.Get("trigger.type", "") as string; - if (trigger == "phrase" || trigger == "intent") return true; + var trigger = context.Get("trigger.type", "") as string; + if (trigger == "phrase" || trigger == "intent") return true; - trigger = context.Get("intent.trigger", "") as string; - if (!string.IsNullOrEmpty(trigger)) return true; + trigger = context.Get("intent.trigger", "") as string; + if (!string.IsNullOrEmpty(trigger)) return true; - trigger = context.Get("phrase.trigger", "") as string; - if (!string.IsNullOrEmpty(trigger)) return true; + trigger = context.Get("phrase.trigger", "") as string; + if (!string.IsNullOrEmpty(trigger)) return true; - return false; - } + return false; + } - private void StartListening() - { - var intent = _serviceProvider.GetRequiredService(); + private void StartListening() + { + var intent = _serviceProvider.GetRequiredService(); - intent.SetState(intent.GetState() == ListeningState.Once - ? ListeningState.Once - : ListeningState.On); + intent.SetState(intent.GetState() == ListeningState.Once + ? ListeningState.Once + : ListeningState.On); - MR.DBG_TRACE_INFO($"CommandExecutionService: ListeningState.{intent.GetState()} ***"); - } + MR.DBG_TRACE_INFO($"CommandExecutionService: ListeningState.{intent.GetState()} ***"); + } - private void PopListeningState(IExecutionContext context) - { - var intent = _serviceProvider.GetRequiredService(); - var stashed = context.Get("listen.state.stash", null); - if (stashed != null) + private void PopListeningState(IExecutionContext context) { - MR.DBG_TRACE_INFO($"PopState = {stashed}"); - var restore = (ListeningState)stashed; - intent.SetState(restore); + var intent = _serviceProvider.GetRequiredService(); + var stashed = context.Get("listen.state.stash", null); + if (stashed != null) + { + MR.DBG_TRACE_INFO($"PopState = {stashed}"); + var restore = (ListeningState)stashed; + intent.SetState(restore); + } } - } - - private bool ShouldSetTimerOn(object? policy, out int timeoutInMs) - { - timeoutInMs = 0; - var action = policy as IUnexpectedDialogPolicy.Action?; - if (action == IUnexpectedDialogPolicy.Action.Ignore) + private bool ShouldSetTimerOn(object? policy, out int timeoutInMs) { - MR.DBG_TRACE_INFO($"ShouldSetTimerOn: false"); - return false; - } + timeoutInMs = 0; - MR.DBG_TRACE_INFO($"ShouldSetTimerOn: true"); - timeoutInMs = 10000; // TODO: Consider non-hardcoded value, configurable, somewhere... - return true; - } + var action = policy as IUnexpectedDialogPolicy.Action?; + if (action == IUnexpectedDialogPolicy.Action.Ignore) + { + MR.DBG_TRACE_INFO($"ShouldSetTimerOn: false"); + return false; + } - private void CheckSetTimer(ICommand command) - { - MR.DBG_TRACE_INFO($"CheckSetTimer: {command.Id}"); - var timeoutPolicy = command.Unexpected?.TimeoutPolicy; - if (ShouldSetTimerOn(timeoutPolicy, out var timeoutInMs)) - { - ClearTimerTimeout(command); - SetTimerTimeout(command, timeoutInMs); + MR.DBG_TRACE_INFO($"ShouldSetTimerOn: true"); + timeoutInMs = 10000; // TODO: Consider non-hardcoded value, configurable, somewhere... + return true; } - } - private void ClearAllTimerTimeouts() - { - var commands = _timerIds.Keys.ToList(); - foreach (var command in commands) + private void CheckSetTimer(ICommand command) { - ClearTimerTimeout(command); + MR.DBG_TRACE_INFO($"CheckSetTimer: {command.Id}"); + var timeoutPolicy = command.Unexpected?.TimeoutPolicy; + if (ShouldSetTimerOn(timeoutPolicy, out var timeoutInMs)) + { + ClearTimerTimeout(command); + SetTimerTimeout(command, timeoutInMs); + } } - } - private bool ClearTimerTimeout(ICommand command) - { - if (_timerIds.TryGetValue(command, out var id)) + private void ClearAllTimerTimeouts() { - MR.DBG_TRACE_INFO($"ClearTimerTimeout: {command.Id}"); - _timerService.ClearInterval(id); - _timerIds.Remove(command); - return true; + var commands = _timerIds.Keys.ToList(); + foreach (var command in commands) + { + ClearTimerTimeout(command); + } } - return false; - } - private void SetTimerTimeout(ICommand command, int timeoutInMs) - { - MR.DBG_TRACE_INFO($"SetTimerTimeout: {command.Id}"); - var id = _timerService.SetInterval(() => HandleTimerTimeout(command), timeoutInMs); - _timerIds[command] = id; - } + private bool ClearTimerTimeout(ICommand command) + { + if (_timerIds.TryGetValue(command, out var id)) + { + MR.DBG_TRACE_INFO($"ClearTimerTimeout: {command.Id}"); + _timerService.ClearInterval(id); + _timerIds.Remove(command); + return true; + } + return false; + } - private void HandleTimerTimeout(ICommand command) - { - MR.DBG_TRACE_INFO($"HandleTimer: {command.Id}"); - ClearTimerTimeout(command); - if (ShouldCancelOn(command.Unexpected?.TimeoutPolicy)) + private void SetTimerTimeout(ICommand command, int timeoutInMs) { - MR.DBG_TRACE_INFO($"HandleTimer: ShouldCancel"); - CancelCommand(command); - MR.DBG_TRACE_INFO($"HandleTimer: ShouldCancel... Done."); + MR.DBG_TRACE_INFO($"SetTimerTimeout: {command.Id}"); + var id = _timerService.SetInterval(() => HandleTimerTimeout(command), timeoutInMs); + _timerIds[command] = id; } - else + + private void HandleTimerTimeout(ICommand command) { - MR.DBG_TRACE_INFO($"HandleTimer: RetryOrExecute"); - RetryOrExecute(command, command.Unexpected?.TimeoutPolicy, "unexpected.timeout"); - MR.DBG_TRACE_INFO($"HandleTimer: RetryOrExecute... Done."); + MR.DBG_TRACE_INFO($"HandleTimer: {command.Id}"); + ClearTimerTimeout(command); + if (ShouldCancelOn(command.Unexpected?.TimeoutPolicy)) + { + MR.DBG_TRACE_INFO($"HandleTimer: ShouldCancel"); + CancelCommand(command); + MR.DBG_TRACE_INFO($"HandleTimer: ShouldCancel... Done."); + } + else + { + MR.DBG_TRACE_INFO($"HandleTimer: RetryOrExecute"); + RetryOrExecute(command, command.Unexpected?.TimeoutPolicy, "unexpected.timeout"); + MR.DBG_TRACE_INFO($"HandleTimer: RetryOrExecute... Done."); + } } - } - private readonly IServiceProvider _serviceProvider; - private readonly ITimeIntervalService _timerService; + private readonly IServiceProvider _serviceProvider; + private readonly ITimeIntervalService _timerService; - private List _notCompletedCommands = new(); - private Dictionary _timerIds = new(); -} + private List _notCompletedCommands = new List(); + private Dictionary _timerIds = new Dictionary(); + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/ConversationAnalysisClientService.cs b/src/cs/CommandSystemServices/ConversationAnalysisClientService.cs index 08ee4130..4d53bf40 100644 --- a/src/cs/CommandSystemServices/ConversationAnalysisClientService.cs +++ b/src/cs/CommandSystemServices/ConversationAnalysisClientService.cs @@ -1,29 +1,52 @@ -using Azure.AI.Language.Conversations; + +/* Unmerged change from project 'macaroni_core (net6.0-windows)' +Before: +using Azure.AI.Language.Conversations; using Azure; using Microsoft.CognitiveServices.Speech; -using Microsoft.CognitiveServices.Speech.Intent; -using Microsoft.Extensions.DependencyInjection; +After: +using Azure; +using Azure.AI.Language.Conversations; +using Microsoft.CognitiveServices.Speech; +*/ + +/* Unmerged change from project 'macaroni_core (netstandard2.1)' +Before: +using Azure.AI.Language.Conversations; +using Azure; +using Microsoft.CognitiveServices.Speech; +After: +using Azure; +using Azure.AI.Language.Conversations; +using Microsoft.CognitiveServices.Speech; +*/ -namespace macaroni; +using System; +using Azure; +using Azure.AI.Language.Conversations; +using Microsoft.Extensions.DependencyInjection; -internal class ConversationAnalysisClientService : IConversationAnalysisClientService +namespace macaroni { - public ConversationAnalysisClientService(IServiceProvider services) + internal class ConversationAnalysisClientService : IConversationAnalysisClientService { - _serviceProvider = services; - } + public ConversationAnalysisClientService(IServiceProvider services) + { + _serviceProvider = services; + } - public ConversationAnalysisClient GetConversationAnalysisClient() - { - var settings = _serviceProvider.GetRequiredService(); - var endpointString = settings.Get("CLU_ENDPOINT")?.Trim(); - var key = settings.Get("CLU_KEY")?.Trim(); + public ConversationAnalysisClient GetConversationAnalysisClient() + { + var settings = _serviceProvider.GetRequiredService(); + var endpointString = settings.Get("CLU_ENDPOINT")?.Trim(); + var key = settings.Get("CLU_KEY")?.Trim(); - Uri endpoint = new Uri(endpointString!); - AzureKeyCredential credential = new AzureKeyCredential(key!); - ConversationAnalysisClient client = new ConversationAnalysisClient(endpoint, credential); - return client; - } + Uri endpoint = new Uri(endpointString!); + AzureKeyCredential credential = new AzureKeyCredential(key!); + ConversationAnalysisClient client = new ConversationAnalysisClient(endpoint, credential); + return client; + } - private readonly IServiceProvider _serviceProvider; -} + private readonly IServiceProvider _serviceProvider; + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/FileMonitoringService.cs b/src/cs/CommandSystemServices/FileMonitoringService.cs index 1ef453f3..55576f2e 100644 --- a/src/cs/CommandSystemServices/FileMonitoringService.cs +++ b/src/cs/CommandSystemServices/FileMonitoringService.cs @@ -1,17 +1,22 @@ -namespace macaroni; +using System; +using System.Collections.Generic; +using System.IO; -internal class FileMonitoringService : IFileMonitoringService +namespace macaroni { - public void StartNotify(string path, string filter, Action newFiles, Action changedFiles, Action deletedFiles, Action>? updatedFileList) + internal class FileMonitoringService : IFileMonitoringService { - _monitor = new FileMonitor(path, filter); - _monitor.StartNotify(newFiles, changedFiles, deletedFiles, updatedFileList); - } + public void StartNotify(string path, string filter, Action newFiles, Action changedFiles, Action deletedFiles, Action>? updatedFileList) + { + _monitor = new FileMonitor(path, filter); + _monitor.StartNotify(newFiles, changedFiles, deletedFiles, updatedFileList); + } - public void StopNotify() - { - _monitor?.StopNotify(); - } + public void StopNotify() + { + _monitor?.StopNotify(); + } - private FileMonitor? _monitor = null; -} + private FileMonitor? _monitor = null; + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/GenericClipboardService.cs b/src/cs/CommandSystemServices/GenericClipboardService.cs index 784edca2..e0c7d71f 100644 --- a/src/cs/CommandSystemServices/GenericClipboardService.cs +++ b/src/cs/CommandSystemServices/GenericClipboardService.cs @@ -1,26 +1,27 @@ -namespace macaroni; - -internal class GenericClipboardService : IClipboardService +namespace macaroni { - public void Clear() + internal class GenericClipboardService : IClipboardService { - } + public void Clear() + { + } - public void Set(string value, string? format) - { - } + public void Set(string value, string? format) + { + } - public string? GetText() - { - return null; - } + public string? GetText() + { + return null; + } - public void SetImage(IImage image) - { - } + public void SetImage(IImage image) + { + } - public IImage? GetImage() - { - return null; + public IImage? GetImage() + { + return null; + } } -} +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/GenericCommandSystemHost.cs b/src/cs/CommandSystemServices/GenericCommandSystemHost.cs index 207fc25f..01684c82 100644 --- a/src/cs/CommandSystemServices/GenericCommandSystemHost.cs +++ b/src/cs/CommandSystemServices/GenericCommandSystemHost.cs @@ -1,8 +1,9 @@ -namespace macaroni; - -internal class GenericCommandSystemHost : ICommandSystemHost +namespace macaroni { - public void Quit() + internal class GenericCommandSystemHost : ICommandSystemHost { + public void Quit() + { + } } -} +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/GenericHotkeyService.cs b/src/cs/CommandSystemServices/GenericHotkeyService.cs index ff2764e3..2f6be30a 100644 --- a/src/cs/CommandSystemServices/GenericHotkeyService.cs +++ b/src/cs/CommandSystemServices/GenericHotkeyService.cs @@ -1,12 +1,15 @@ -namespace macaroni; +using System; -internal class GenericHotkeyService : IHotkeyService +namespace macaroni { - public void StartNotify(string groupId, string id, string hotkey, Action callback) + internal class GenericHotkeyService : IHotkeyService { - } + public void StartNotify(string groupId, string id, string hotkey, Action callback) + { + } - public void StopNotify(string groupId, string? hotkeyId) - { + public void StopNotify(string groupId, string? hotkeyId) + { + } } -} +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/GenericMessageBoxService.cs b/src/cs/CommandSystemServices/GenericMessageBoxService.cs index 074a4ac6..0dd49529 100644 --- a/src/cs/CommandSystemServices/GenericMessageBoxService.cs +++ b/src/cs/CommandSystemServices/GenericMessageBoxService.cs @@ -1,24 +1,27 @@ -namespace macaroni; +using System.Collections.Generic; -internal class GenericMessageBoxService : IMessageBoxService +namespace macaroni { - public bool Show(string message, string? title, string? timeout) + internal class GenericMessageBoxService : IMessageBoxService { - return false; - } + public bool Show(string message, string? title, string? timeout) + { + return false; + } - public bool Confirm(string message, string? title, string? timeout) - { - return false; - } + public bool Confirm(string message, string? title, string? timeout) + { + return false; + } - public bool Prompt(string message, string? title, string? timeout, ref string text) - { - return false; - } + public bool Prompt(string message, string? title, string? timeout, ref string text) + { + return false; + } - public bool Pick(IEnumerable choices, string? message, string? title, string? timeout, ref string? choice) - { - return false; + public bool Pick(IEnumerable choices, string? message, string? title, string? timeout, ref string? choice) + { + return false; + } } -} +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/GenericOnScreenDisplayService.cs b/src/cs/CommandSystemServices/GenericOnScreenDisplayService.cs index 4325d602..00f937d2 100644 --- a/src/cs/CommandSystemServices/GenericOnScreenDisplayService.cs +++ b/src/cs/CommandSystemServices/GenericOnScreenDisplayService.cs @@ -1,12 +1,16 @@ -namespace macaroni; +using System; +using System.Collections.Generic; -internal class GenericOnScreenDisplayService : IOnScreenDisplayService +namespace macaroni { - public void DisplayText(string text, string from, bool? pending = null, int timeout = 0) + internal class GenericOnScreenDisplayService : IOnScreenDisplayService { - } + public void DisplayText(string text, string from, bool? pending = null, int timeout = 0) + { + } - public void DisplayTips(IEnumerable? tips, Func?>? moreTips) - { + public void DisplayTips(IEnumerable? tips, Func?>? moreTips) + { + } } -} +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/GenericPlayMediaService.cs b/src/cs/CommandSystemServices/GenericPlayMediaService.cs index 66fee98b..9c2630bd 100644 --- a/src/cs/CommandSystemServices/GenericPlayMediaService.cs +++ b/src/cs/CommandSystemServices/GenericPlayMediaService.cs @@ -1,32 +1,46 @@ -namespace macaroni; - -using System; -using System.Text; -using System.Runtime.InteropServices; - -internal class GenericPlayMediaService : IPlayMediaService +namespace macaroni { - public void Beep() - { - } + /* Unmerged change from project 'macaroni_core (net6.0-windows)' + Before: + using System.Text; + using System.Runtime.InteropServices; + After: + using System.Runtime.InteropServices; + using System.Text; + */ - public void Beep(int frequency, int duration) + /* Unmerged change from project 'macaroni_core (netstandard2.1)' + Before: + using System.Text; + using System.Runtime.InteropServices; + After: + using System.Runtime.InteropServices; + using System.Text; + */ + internal class GenericPlayMediaService : IPlayMediaService { - } + public void Beep() + { + } - public void Play(string file, int pos = 0) - { - } + public void Beep(int frequency, int duration) + { + } - public void Pause() - { - } + public void Play(string file, int pos = 0) + { + } - public void Resume() - { - } + public void Pause() + { + } - public void Stop() - { + public void Resume() + { + } + + public void Stop() + { + } } -} +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/GenericProtectedSecretSettingsCache.cs b/src/cs/CommandSystemServices/GenericProtectedSecretSettingsCache.cs index 13f70796..04bd9dfa 100644 --- a/src/cs/CommandSystemServices/GenericProtectedSecretSettingsCache.cs +++ b/src/cs/CommandSystemServices/GenericProtectedSecretSettingsCache.cs @@ -1,5 +1,6 @@ -namespace macaroni; - -internal class GenericProtectedSecretSettingsCache : ProtectedSettingsMemoryCache +namespace macaroni { -} + internal class GenericProtectedSecretSettingsCache : ProtectedSettingsMemoryCache + { + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/GenericScreenCaptureService.cs b/src/cs/CommandSystemServices/GenericScreenCaptureService.cs index de132e00..f42fa026 100644 --- a/src/cs/CommandSystemServices/GenericScreenCaptureService.cs +++ b/src/cs/CommandSystemServices/GenericScreenCaptureService.cs @@ -1,34 +1,35 @@ -namespace macaroni; - -internal class GenericScreenCaptureService : IScreenCaptureService +namespace macaroni { - public string? GetScreenText() + internal class GenericScreenCaptureService : IScreenCaptureService { - return null; - } + public string? GetScreenText() + { + return null; + } - public string? GetWindowText() - { - return null; - } + public string? GetWindowText() + { + return null; + } - public string? GetFocusText() - { - return null; - } + public string? GetFocusText() + { + return null; + } - public IImage? GetScreenImage() - { - return null; - } + public IImage? GetScreenImage() + { + return null; + } - public IImage? GetWindowImage() - { - return null; - } + public IImage? GetWindowImage() + { + return null; + } - public IImage? GetFocusImage() - { - return null; + public IImage? GetFocusImage() + { + return null; + } } -} +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/GlobalNamedStateMonitoringService.cs b/src/cs/CommandSystemServices/GlobalNamedStateMonitoringService.cs index 9511dbff..c942450e 100644 --- a/src/cs/CommandSystemServices/GlobalNamedStateMonitoringService.cs +++ b/src/cs/CommandSystemServices/GlobalNamedStateMonitoringService.cs @@ -1,40 +1,43 @@ -namespace macaroni; +using System; -internal class GlobalNamedStateMonitoringService : IGlobalNamedStateMonitorService, INotifyGlobalNamedState +namespace macaroni { - public GlobalNamedStateMonitoringService(IGlobalNamedStateService namedStateService) + internal class GlobalNamedStateMonitoringService : IGlobalNamedStateMonitorService, INotifyGlobalNamedState { - _namedStateService = namedStateService; - } + public GlobalNamedStateMonitoringService(IGlobalNamedStateService namedStateService) + { + _namedStateService = namedStateService; + } - public void StartNotify(string name, Action? notify) - { - var firstTime = _name == null; + public void StartNotify(string name, Action? notify) + { + var firstTime = _name == null; - _name = name; - _notify = notify; + _name = name; + _notify = notify; - if (firstTime) - { - _namedStateService.StartNotify(this); + if (firstTime) + { + _namedStateService.StartNotify(this); + } } - } - public void StopNotify() - { - _namedStateService.StopNotify(this); - } + public void StopNotify() + { + _namedStateService.StopNotify(this); + } - public void NamedStateChanged(IGlobalNamedState state) - { - if (state.Name == _name) + public void NamedStateChanged(IGlobalNamedState state) { - _notify?.Invoke(state); + if (state.Name == _name) + { + _notify?.Invoke(state); + } } - } - private IGlobalNamedStateService _namedStateService; + private IGlobalNamedStateService _namedStateService; - private string? _name; - private Action? _notify; -} + private string? _name; + private Action? _notify; + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/GlobalNamedStateService.cs b/src/cs/CommandSystemServices/GlobalNamedStateService.cs index 3061dd02..3099e375 100644 --- a/src/cs/CommandSystemServices/GlobalNamedStateService.cs +++ b/src/cs/CommandSystemServices/GlobalNamedStateService.cs @@ -1,92 +1,95 @@ using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; -namespace macaroni; - -internal class GlobalNamedStateService : IGlobalNamedStateService +namespace macaroni { - public void SetNamedState(string name, string? value) + internal class GlobalNamedStateService : IGlobalNamedStateService { - if (!string.IsNullOrEmpty(value)) - { - StateAddOrUpdate(name, value); - } - else + public void SetNamedState(string name, string? value) { - StateClear(name); + if (!string.IsNullOrEmpty(value)) + { + StateAddOrUpdate(name, value); + } + else + { + StateClear(name); + } } - } - - public string? GetNamedState(string name) - { - return _states.TryGetValue(name, out var state) ? state.Value : null; - } - public void StartNotify(INotifyGlobalNamedState notify) - { - lock (_notify) + public string? GetNamedState(string name) { - _notify.Add(notify); + return _states.TryGetValue(name, out var state) ? state.Value : null; } - } - public void StopNotify(INotifyGlobalNamedState notify) - { - lock (_notify) + public void StartNotify(INotifyGlobalNamedState notify) { - _notify.Remove(notify); + lock (_notify) + { + _notify.Add(notify); + } } - } - private void StateAddOrUpdate(string name, string value) - { - var state = _states.AddOrUpdate(name, - key => new NamedState(key, value), - (key, state) => + public void StopNotify(INotifyGlobalNamedState notify) + { + lock (_notify) { - (state as NamedState)!.Value = value; - return state; - }); - Notify(state); - } + _notify.Remove(notify); + } + } - private void StateClear(string name) - { - _states.TryRemove(name, out var state); - if (state != null) + private void StateAddOrUpdate(string name, string value) { - (state as NamedState)!.Value = null; + var state = _states.AddOrUpdate(name, + key => new NamedState(key, value), + (key, state) => + { + (state as NamedState)!.Value = value; + return state; + }); Notify(state); } - } - private void Notify(IGlobalNamedState? state) - { - if (state != null) + private void StateClear(string name) { - lock (_notify) + _states.TryRemove(name, out var state); + if (state != null) { - MR.DBG_TRACE_INFO($"Notifying state; name={state.Name}, value={state.Value}"); - foreach (var notify in _notify.ToList()) // make a copy in case notified tries to remove during callback + (state as NamedState)!.Value = null; + Notify(state); + } + } + + private void Notify(IGlobalNamedState? state) + { + if (state != null) + { + lock (_notify) { - notify.NamedStateChanged(state); + MR.DBG_TRACE_INFO($"Notifying state; name={state.Name}, value={state.Value}"); + foreach (var notify in _notify.ToList()) // make a copy in case notified tries to remove during callback + { + notify.NamedStateChanged(state); + } } } } - } - class NamedState : IGlobalNamedState - { - public NamedState(string name, string value) + class NamedState : IGlobalNamedState { - Name = name; - Value = value; - } + public NamedState(string name, string value) + { + Name = name; + Value = value; + } - public string Name { get; internal set;} + public string Name { get; internal set; } - public string? Value { get; internal set; } - } + public string? Value { get; internal set; } + } - private ConcurrentDictionary _states = new(); - private List _notify = new(); -} + private ConcurrentDictionary _states = new ConcurrentDictionary(); + private List _notify = new List(); + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/HttpClientService.cs b/src/cs/CommandSystemServices/HttpClientService.cs index 5e204324..8801e8c1 100644 --- a/src/cs/CommandSystemServices/HttpClientService.cs +++ b/src/cs/CommandSystemServices/HttpClientService.cs @@ -1,83 +1,87 @@ -using Microsoft.Extensions.DependencyInjection; -using System.Diagnostics; +using System; +using System.Collections.Generic; +using System.Net.Http; using System.Net.Http.Headers; +using System.Threading.Tasks; -namespace macaroni; - -internal class HttpClientService : IHttpClientService +namespace macaroni { - public HttpClientService(IServiceProvider serviceProvider) - { - _serviceProvider = serviceProvider; - } - - public Task SendRequestAsync(string uri, string? method, string? content, IEnumerable? headers) + internal class HttpClientService : IHttpClientService { - if (string.IsNullOrEmpty(method) && content != null) + public HttpClientService(IServiceProvider serviceProvider) { - method = "POST"; + _serviceProvider = serviceProvider; } - return method?.ToUpper() switch { - "POST" => HttpPostSendAsync(uri, content, headers), - _ => HttpGetSendAsync(uri, headers) - }; - } + public Task SendRequestAsync(string uri, string? method, string? content, IEnumerable? headers) + { + if (string.IsNullOrEmpty(method) && content != null) + { + method = "POST"; + } - private Task HttpGetSendAsync(string uri, IEnumerable? headers) - { - EnsureHttpClient(); + return method?.ToUpper() switch + { + "POST" => HttpPostSendAsync(uri, content, headers), + _ => HttpGetSendAsync(uri, headers) + }; + } - var request = new HttpRequestMessage(HttpMethod.Get, uri); - return _client!.SendAsync(UpdateHeaders(request, headers)); - } + private Task HttpGetSendAsync(string uri, IEnumerable? headers) + { + EnsureHttpClient(); - private Task HttpPostSendAsync(string uri, string? content, IEnumerable? headers) - { - EnsureHttpClient(); + var request = new HttpRequestMessage(HttpMethod.Get, uri); + return _client!.SendAsync(UpdateHeaders(request, headers)); + } - var request = new HttpRequestMessage(HttpMethod.Post, uri); - return _client!.SendAsync(UpdateHeaders(UpdateContent(request, content), headers)); - } + private Task HttpPostSendAsync(string uri, string? content, IEnumerable? headers) + { + EnsureHttpClient(); - private void EnsureHttpClient() - { - if (_client == null) + var request = new HttpRequestMessage(HttpMethod.Post, uri); + return _client!.SendAsync(UpdateHeaders(UpdateContent(request, content), headers)); + } + + private void EnsureHttpClient() { - _client = new HttpClient(); + if (_client == null) + { + _client = new HttpClient(); + } } - } - private HttpRequestMessage UpdateHeaders(HttpRequestMessage request, IEnumerable? headers) - { - if (headers != null) + private HttpRequestMessage UpdateHeaders(HttpRequestMessage request, IEnumerable? headers) { - foreach (var x in headers) + if (headers != null) { - var headerName = x.Before(':'); - var headerValue = x.After(':'); - if (headerName == "Content-Type") + foreach (var x in headers) { - request.Content!.Headers.ContentType = new MediaTypeHeaderValue(headerValue); - } - else - { - request.Headers.Add(headerName, headerValue); + var headerName = x.Before(':'); + var headerValue = x.After(':'); + if (headerName == "Content-Type") + { + request.Content!.Headers.ContentType = new MediaTypeHeaderValue(headerValue); + } + else + { + request.Headers.Add(headerName, headerValue); + } } } + return request; } - return request; - } - private HttpRequestMessage UpdateContent(HttpRequestMessage request, string? content) - { - if (content != null) + private HttpRequestMessage UpdateContent(HttpRequestMessage request, string? content) { - request.Content = new StringContent(content); + if (content != null) + { + request.Content = new StringContent(content); + } + return request; } - return request; - } - private readonly IServiceProvider _serviceProvider; - private HttpClient? _client; -} + private readonly IServiceProvider _serviceProvider; + private HttpClient? _client; + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/ImageAnalysisService.cs b/src/cs/CommandSystemServices/ImageAnalysisService.cs index 6f4a448b..b764297a 100644 --- a/src/cs/CommandSystemServices/ImageAnalysisService.cs +++ b/src/cs/CommandSystemServices/ImageAnalysisService.cs @@ -1,98 +1,98 @@ -using Microsoft.CognitiveServices.Speech; -using Microsoft.CognitiveServices.Speech.Audio; -using Microsoft.Extensions.DependencyInjection; -using System.Diagnostics; -using System.Text; -using Newtonsoft.Json; + +using System; +using System.Threading.Tasks; +using Azure.AI.Vision.Core.Input; using Azure.AI.Vision.Core.Options; using Azure.AI.Vision.ImageAnalysis; -using Azure.AI.Vision.Core.Input; -namespace macaroni; +using Microsoft.Extensions.DependencyInjection; -internal class ImageAnalysisService : IImageAnalysisService +namespace macaroni { - public ImageAnalysisService(IServiceProvider services) + internal class ImageAnalysisService : IImageAnalysisService { - _serviceProvider = services; - } + public ImageAnalysisService(IServiceProvider services) + { + _serviceProvider = services; + } - public async Task Analyze(string fileName, string? featuresRequested, string? language) - { - var analyzer = CreateAnalyzer(fileName, featuresRequested, language); - return await analyzer.AnalyzeAsync(); - } + public async Task Analyze(string fileName, string? featuresRequested, string? language) + { + var analyzer = CreateAnalyzer(fileName, featuresRequested, language); + return await analyzer.AnalyzeAsync(); + } - private ImageAnalyzer CreateAnalyzer(string fileName, string? featuresRequested, string? language) - { - var serviceOptions = GetServiceOptions(); - var source = GetVisionSource(fileName); - var options = GetImageAnalysisOptions(featuresRequested, language); + private ImageAnalyzer CreateAnalyzer(string fileName, string? featuresRequested, string? language) + { + var serviceOptions = GetServiceOptions(); + var source = GetVisionSource(fileName); + var options = GetImageAnalysisOptions(featuresRequested, language); - var analyzer = new ImageAnalyzer(serviceOptions, source, options); - return analyzer; - } + var analyzer = new ImageAnalyzer(serviceOptions, source, options); + return analyzer; + } - private VisionServiceOptions GetServiceOptions() - { - var service = _serviceProvider.GetRequiredService(); - service.GetImageAnalyzerConnectionInfo(out var key, out var endpoint); + private VisionServiceOptions GetServiceOptions() + { + var service = _serviceProvider.GetRequiredService(); + service.GetImageAnalyzerConnectionInfo(out var key, out var endpoint); - var serviceOptions = new VisionServiceOptions(endpoint, key); - return serviceOptions; - } + var serviceOptions = new VisionServiceOptions(endpoint, key); + return serviceOptions; + } - private static VisionSource GetVisionSource(string fileName) - { - return VisionSource.FromFile(fileName); - } + private static VisionSource GetVisionSource(string fileName) + { + return VisionSource.FromFile(fileName); + } - private ImageAnalysisOptions GetImageAnalysisOptions(string? featuresRequested, string? language) - { - return new ImageAnalysisOptions() + private ImageAnalysisOptions GetImageAnalysisOptions(string? featuresRequested, string? language) { - Language = language ?? GetDefaultLanguage(), - Features = GetImageAnalysisFeatures(featuresRequested) ?? GetDefaultImageAnalysisFeatures() - }; - } + return new ImageAnalysisOptions() + { + Language = language ?? GetDefaultLanguage(), + Features = GetImageAnalysisFeatures(featuresRequested) ?? GetDefaultImageAnalysisFeatures() + }; + } - private string GetDefaultLanguage() - { - var service = _serviceProvider.GetRequiredService(); - return service.GetDefaultLanguage(); - } + private string GetDefaultLanguage() + { + var service = _serviceProvider.GetRequiredService(); + return service.GetDefaultLanguage(); + } - private ImageAnalysisFeature? GetImageAnalysisFeatures(string? requested) - { - if (string.IsNullOrEmpty(requested)) return null; + private ImageAnalysisFeature? GetImageAnalysisFeatures(string? requested) + { + if (string.IsNullOrEmpty(requested)) return null; - ImageAnalysisFeature features = 0; + ImageAnalysisFeature features = 0; - var items = requested.Split(new char[] { ',', ';', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); - foreach (var item in items) - { - var check = item.Trim(); - if (Enum.TryParse(check, true, out ImageAnalysisFeature feature)) + var items = requested.Split(new char[] { ',', ';', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + foreach (var item in items) { - features |= feature; - } - else if (Enum.TryParse($"{check}s", true, out feature)) - { - features |= feature; + var check = item.Trim(); + if (Enum.TryParse(check, true, out ImageAnalysisFeature feature)) + { + features |= feature; + } + else if (Enum.TryParse($"{check}s", true, out feature)) + { + features |= feature; + } } + return features; } - return features; - } - private static ImageAnalysisFeature GetDefaultImageAnalysisFeatures() - { - return ImageAnalysisFeature.Tags - | ImageAnalysisFeature.Objects - | ImageAnalysisFeature.People - | ImageAnalysisFeature.CropSuggestions - | ImageAnalysisFeature.Descriptions - | ImageAnalysisFeature.Text; - } + private static ImageAnalysisFeature GetDefaultImageAnalysisFeatures() + { + return ImageAnalysisFeature.Tags + | ImageAnalysisFeature.Objects + | ImageAnalysisFeature.People + | ImageAnalysisFeature.CropSuggestions + | ImageAnalysisFeature.Descriptions + | ImageAnalysisFeature.Text; + } - private readonly IServiceProvider _serviceProvider; -} + private readonly IServiceProvider _serviceProvider; + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/ImageAnalyzerConfigService.cs b/src/cs/CommandSystemServices/ImageAnalyzerConfigService.cs index 98f19f8e..60a79d8c 100644 --- a/src/cs/CommandSystemServices/ImageAnalyzerConfigService.cs +++ b/src/cs/CommandSystemServices/ImageAnalyzerConfigService.cs @@ -1,47 +1,49 @@ -using Microsoft.CognitiveServices.Speech; -using Microsoft.CognitiveServices.Speech.Intent; +using System; +using System.IO; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; -namespace macaroni; - -internal class ImageAnalyzerConfigService : IImageAnalyzerConfigService +namespace macaroni { - public ImageAnalyzerConfigService(IServiceProvider services, IHostEnvironment environment) + internal class ImageAnalyzerConfigService : IImageAnalyzerConfigService { - _serviceProvider = services; - _settings = services.GetRequiredService(); - - var logFilePath = services.GetRequiredService()?.GetNamedState("__macaroni.logFilePath"); - if (logFilePath != null) + public ImageAnalyzerConfigService(IServiceProvider services, IHostEnvironment environment) { - _logFileName = Path.Combine(logFilePath, $"macaroni.carbon-vision-{DateTime.Now.ToFileTime()}.log"); + _serviceProvider = services; + _settings = services.GetRequiredService(); + + var logFilePath = services.GetRequiredService()?.GetNamedState("__macaroni.logFilePath"); + if (logFilePath != null) + { + _logFileName = Path.Combine(logFilePath, $"macaroni.carbon-vision-{DateTime.Now.ToFileTime()}.log"); + } } - } - public string GetDefaultLanguage() - { - var defaultDefault = _settings.Get("DEFAULT_LANGUAGE", null) ?? "en-US"; - var defaultLanguage = _settings.Get("VISION_DEFAULT_LANGUAGE", defaultDefault); + public string GetDefaultLanguage() + { + var defaultDefault = _settings.Get("DEFAULT_LANGUAGE", null) ?? "en-US"; + var defaultLanguage = _settings.Get("VISION_DEFAULT_LANGUAGE", defaultDefault); - if (string.IsNullOrEmpty(defaultLanguage)) defaultLanguage = defaultDefault; + if (string.IsNullOrEmpty(defaultLanguage)) defaultLanguage = defaultDefault; - return defaultLanguage!.Trim('\r', '\n', ' ').Before('-'); - } - - public void GetImageAnalyzerConnectionInfo(out string? key, out string? endpoint) - { - var settings = _serviceProvider.GetRequiredService(); - key = settings.Get("VISION_KEY")?.Trim(); - endpoint = settings.Get("VISION_ENDPOINT")?.Trim(); + return defaultLanguage!.Trim('\r', '\n', ' ').Before('-'); + } - if (!string.IsNullOrEmpty(_logFileName)) + public void GetImageAnalyzerConnectionInfo(out string? key, out string? endpoint) { - MR.DBG_TRACE_INFO($"Logging to {_logFileName}..."); - Azure.AI.Vision.Core.Diagnostics.Logging.FileLogger.Start(_logFileName); + var settings = _serviceProvider.GetRequiredService(); + key = settings.Get("VISION_KEY")?.Trim(); + endpoint = settings.Get("VISION_ENDPOINT")?.Trim(); + + if (!string.IsNullOrEmpty(_logFileName)) + { + MR.DBG_TRACE_INFO($"Logging to {_logFileName}..."); + Azure.AI.Vision.Core.Diagnostics.Logging.FileLogger.Start(_logFileName); + } } - } - private readonly IServiceProvider _serviceProvider; - private readonly ICommandSystemSettings _settings; - private readonly string? _logFileName; -} + private readonly IServiceProvider _serviceProvider; + private readonly ICommandSystemSettings _settings; + private readonly string? _logFileName; + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/KeyVaultSettingsService.cs b/src/cs/CommandSystemServices/KeyVaultSettingsService.cs index 96234c9e..ea2e85d9 100644 --- a/src/cs/CommandSystemServices/KeyVaultSettingsService.cs +++ b/src/cs/CommandSystemServices/KeyVaultSettingsService.cs @@ -1,272 +1,278 @@ -using Azure.Identity; +using System; +using System.IO; +using System.Collections.Generic; +using Azure.Identity; using Azure.Security.KeyVault.Secrets; using Microsoft.Extensions.DependencyInjection; using System.Diagnostics; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; -namespace macaroni; - -internal class KeyVaultSettingsService : IKeyVaultSettingsService +namespace macaroni { - public KeyVaultSettingsService(IServiceProvider services, ISecretSettings secretSettings, IProtectedSecretSettingsCache secretSettingsCache) + internal class KeyVaultSettingsService : IKeyVaultSettingsService { - _services = services; - _secretSettings = secretSettings; - _secretSettingsCache = secretSettingsCache; + public KeyVaultSettingsService(IServiceProvider services, ISecretSettings secretSettings, IProtectedSecretSettingsCache secretSettingsCache) + { + _services = services; + _secretSettings = secretSettings; + _secretSettingsCache = secretSettingsCache; - var uri = GetInitKeyVaultSetting("KEY_VAULT_URI"); - _uri = !string.IsNullOrEmpty(uri) ? new Uri(uri) : null; + var uri = GetInitKeyVaultSetting("KEY_VAULT_URI"); + _uri = !string.IsNullOrEmpty(uri) ? new Uri(uri) : null; - _clientId = GetInitKeyVaultSetting("KEY_VAULT_CLIENT_ID"); - _tenantId = GetInitKeyVaultSetting("KEY_VAULT_TENANT_ID"); + _clientId = GetInitKeyVaultSetting("KEY_VAULT_CLIENT_ID"); + _tenantId = GetInitKeyVaultSetting("KEY_VAULT_TENANT_ID"); - _useKeyVault = _uri != null && _tenantId != null && _clientId != null; - if (_useKeyVault) - { - StartPassiveInitialize(); + _useKeyVault = _uri != null && _tenantId != null && _clientId != null; + if (_useKeyVault) + { + StartPassiveInitialize(); + } } - } - public string? GetSettingValue(string settingKey, bool allowFastFailBeforeInit = true) - { - // If (and only if) we're already initialized, we'll check the full, service-queried dictionary that may - // differ from the hard-coded local values. This just isn't available until initialization finishes. - if (this._isInitialized && _secretSettingsCache.TryGet(settingKey, out var value)) + public string? GetSettingValue(string settingKey, bool allowFastFailBeforeInit = true) { - return value; - } + // If (and only if) we're already initialized, we'll check the full, service-queried dictionary that may + // differ from the hard-coded local values. This just isn't available until initialization finishes. + if (this._isInitialized && _secretSettingsCache.TryGet(settingKey, out var value)) + { + return value; + } + + // ...But if we're not yet initialized and we don't know about the value ahead of time, then don't wait around + // for initialization to finish. NOTE: this means this could return null one second and a valid value the next. + // The optional parameter can force initialization wait if lazy behavior isn't desired with the hard-coded list. + if (allowFastFailBeforeInit && !_keyVaultBackedVariableNames.Contains(settingKey)) + { + return null; + } + + if (_useKeyVault) + { + // If we got this far, we need to wait for initialization to finish. It'll often take ~20s. + this.InitializeAsync(showStatus: true).Wait(); + } + + if (this._secretSettingsCache.TryGet(settingKey, out var settingValue)) + { + return settingValue; + } - // ...But if we're not yet initialized and we don't know about the value ahead of time, then don't wait around - // for initialization to finish. NOTE: this means this could return null one second and a valid value the next. - // The optional parameter can force initialization wait if lazy behavior isn't desired with the hard-coded list. - if (allowFastFailBeforeInit && !_keyVaultBackedVariableNames.Contains(settingKey)) - { return null; } - if (_useKeyVault) + public bool TryGetSettingValue(string settingKey, out string settingValue, bool allowFastFailBeforeInit = true) { - // If we got this far, we need to wait for initialization to finish. It'll often take ~20s. - this.InitializeAsync(showStatus: true).Wait(); + var nullableValue = this.GetSettingValue(settingKey, allowFastFailBeforeInit); + settingValue = nullableValue ?? string.Empty; + return nullableValue != null; } - if (this._secretSettingsCache.TryGet(settingKey, out var settingValue)) + private void StartPassiveInitialize() { - return settingValue; + _ = Task.Run(async () => await this.InitializeAsync(showStatus: false)); } - return null; - } - - public bool TryGetSettingValue(string settingKey, out string settingValue, bool allowFastFailBeforeInit = true) - { - var nullableValue = this.GetSettingValue(settingKey, allowFastFailBeforeInit); - settingValue = nullableValue ?? string.Empty; - return nullableValue != null; - } - - private void StartPassiveInitialize() - { - _ = Task.Run(async () => await this.InitializeAsync(showStatus: false)); - } - - private async Task InitializeAsync(bool showStatus) - { - CheckShowStatusUpdates(showStatus); - - try + private async Task InitializeAsync(bool showStatus) { - if (await InitializeBeginAsync()) + CheckShowStatusUpdates(showStatus); + + try { - var keyVaultTimer = Stopwatch.StartNew(); + if (await InitializeBeginAsync()) + { + var keyVaultTimer = Stopwatch.StartNew(); - var azureCredential = GetAzureCredential(); - var secretClient = new SecretClient(_uri, azureCredential); + var azureCredential = GetAzureCredential(); + var secretClient = new SecretClient(_uri, azureCredential); - List secretNames = await GetSecretSettingNamesAsync(secretClient); - MR.DBG_TRACE_INFO($"Initial KeyVault query took (ugh) {keyVaultTimer.ElapsedMilliseconds} ms"); + List secretNames = await GetSecretSettingNamesAsync(secretClient); + MR.DBG_TRACE_INFO($"Initial KeyVault query took (ugh) {keyVaultTimer.ElapsedMilliseconds} ms"); - await UpdateSecretSettingsInParallelAsync(secretClient, secretNames); + await UpdateSecretSettingsInParallelAsync(secretClient, secretNames); + } + } + catch (Exception ex) + { + MR.DBG_TRACE_ERROR($"EXCEPTION in InitializeAsync:\n{ex.Message}"); + ResetClientSecret(); + } + finally + { + InitializeEnd(); } } - catch (Exception ex) + + private async Task InitializeBeginAsync() { - MR.DBG_TRACE_ERROR($"EXCEPTION in InitializeAsync:\n{ex.Message}"); - ResetClientSecret(); + await this._initializationSemaphore.WaitAsync(); + return !this._isInitialized; } - finally + + private void InitializeEnd() { - InitializeEnd(); + this._isInitialized = true; + this._initializationSemaphore.Release(); } - } - private async Task InitializeBeginAsync() - { - await this._initializationSemaphore.WaitAsync(); - return !this._isInitialized; - } - - private void InitializeEnd() - { - this._isInitialized = true; - this._initializationSemaphore.Release(); - } - - private string? GetInitKeyVaultSetting(string settingKey) - { - if (_secretSettings.TryGet(settingKey, out var value)) + private string? GetInitKeyVaultSetting(string settingKey) { - MR.DBG_TRACE_INFO($"GetInitKeyVaultSetting: {settingKey} = {value}"); - return value; - } + if (_secretSettings.TryGet(settingKey, out var value)) + { + MR.DBG_TRACE_INFO($"GetInitKeyVaultSetting: {settingKey} = {value}"); + return value; + } - return null; - } + return null; + } - private Azure.Core.TokenCredential? GetAzureCredential() - { - var credential = GetClientSecret(out var clientSecret) - ? GetClientSecretCredential(clientSecret) - : null; + private Azure.Core.TokenCredential? GetAzureCredential() + { + var credential = GetClientSecret(out var clientSecret) + ? GetClientSecretCredential(clientSecret) + : null; - return credential ?? GetDefaultAzureCredential(); - } + return credential ?? GetDefaultAzureCredential(); + } - private bool GetClientSecret(out string? clientSecret) - { - _secretSettingsCache.TryGet(_clientSecretName, out var value); + private bool GetClientSecret(out string? clientSecret) + { + _secretSettingsCache.TryGet(_clientSecretName, out var value); - var tryFile = value == null && FileHelpers.FileExists(_clientSecretName); - if (tryFile) value = FileHelpers.FileReadAllText(_clientSecretName); + var tryFile = value == null && FileHelpers.FileExists(_clientSecretName); + if (tryFile) value = FileHelpers.FileReadAllText(_clientSecretName); - clientSecret = value; - return !string.IsNullOrEmpty(value); - } + clientSecret = value; + return !string.IsNullOrEmpty(value); + } - private void ResetClientSecret() - { - _secretSettingsCache.Set(_clientSecretName, null); + private void ResetClientSecret() + { + _secretSettingsCache.Set(_clientSecretName, null); - var file = FileHelpers.FindFile(_clientSecretName); - if (file != null) File.Delete(file); - } + var file = FileHelpers.FindFile(_clientSecretName); + if (file != null) File.Delete(file); + } - private Azure.Core.TokenCredential? GetClientSecretCredential(string? clientSecret) - { - if (!string.IsNullOrEmpty(_clientId) && !string.IsNullOrEmpty(_tenantId)) + private Azure.Core.TokenCredential? GetClientSecretCredential(string? clientSecret) { - MR.DBG_TRACE_INFO("CREDENTIALS: Using ClientSecretCredential..."); - var options = new ClientSecretCredentialOptions(); - options.AdditionallyAllowedTenants.Add("*"); - return new ClientSecretCredential(_tenantId, _clientId, clientSecret, options); + if (!string.IsNullOrEmpty(_clientId) && !string.IsNullOrEmpty(_tenantId)) + { + MR.DBG_TRACE_INFO("CREDENTIALS: Using ClientSecretCredential..."); + var options = new ClientSecretCredentialOptions(); + options.AdditionallyAllowedTenants.Add("*"); + return new ClientSecretCredential(_tenantId, _clientId, clientSecret, options); + } + return null; } - return null; - } - private Azure.Core.TokenCredential GetDefaultAzureCredential() - { - MR.DBG_TRACE_INFO("CREDENTIALS: Using DefaultAzureCredential..."); - return new DefaultAzureCredential(includeInteractiveCredentials: true); - } + private Azure.Core.TokenCredential GetDefaultAzureCredential() + { + MR.DBG_TRACE_INFO("CREDENTIALS: Using DefaultAzureCredential..."); + return new DefaultAzureCredential(includeInteractiveCredentials: true); + } - private static async Task> GetSecretSettingNamesAsync(SecretClient secretClient) - { - List names = new(); - try + private static async Task> GetSecretSettingNamesAsync(SecretClient secretClient) { - await foreach (var property in secretClient.GetPropertiesOfSecretsAsync()) + List names = new List(); + try { - if (property?.Enabled == true) + await foreach (var property in secretClient.GetPropertiesOfSecretsAsync()) { - names.Add(property.Name); + if (property?.Enabled == true) + { + names.Add(property.Name); + } } } - } - catch (Exception ex) - { - MR.DBG_TRACE_ERROR($"Exception querying KeyVault for properties: {ex.Message}"); - throw; - } + catch (Exception ex) + { + MR.DBG_TRACE_ERROR($"Exception querying KeyVault for properties: {ex.Message}"); + throw; + } - return names; - } + return names; + } - private async Task UpdateSecretSettingsInParallelAsync(SecretClient secretClient, List names) - { - // We do all the actual value queries in parallel. This only speeds things up marginally; by far the - // slowest part of all this is the authentication for whatever first query is done. - await Task.WhenAll((IEnumerable)names.Select(async name => + private async Task UpdateSecretSettingsInParallelAsync(SecretClient secretClient, List names) { - await UpdateSecretSettingAsync(name, secretClient); - })); - } + // We do all the actual value queries in parallel. This only speeds things up marginally; by far the + // slowest part of all this is the authentication for whatever first query is done. + await Task.WhenAll((IEnumerable)names.Select(async name => + { + await UpdateSecretSettingAsync(name, secretClient); + })); + } - private async Task UpdateSecretSettingAsync(string name, SecretClient secretClient) - { - try + private async Task UpdateSecretSettingAsync(string name, SecretClient secretClient) { - var responseFromKeyVault = await secretClient.GetSecretAsync(name); - var valueFromKeyVault = responseFromKeyVault?.Value?.Value; - if (valueFromKeyVault != null) + try { - lock (this._settingsLock) + var responseFromKeyVault = await secretClient.GetSecretAsync(name); + var valueFromKeyVault = responseFromKeyVault?.Value?.Value; + if (valueFromKeyVault != null) { - // KeyVault and related APIs don't accept underscores, while environment variables expect - // them. Make that translation here. - var formattedStorageKey = name.Replace('-', '_'); - this._secretSettingsCache.Set(formattedStorageKey, valueFromKeyVault); + lock (this._settingsLock) + { + // KeyVault and related APIs don't accept underscores, while environment variables expect + // them. Make that translation here. + var formattedStorageKey = name.Replace('-', '_'); + this._secretSettingsCache.Set(formattedStorageKey, valueFromKeyVault); + } } } + catch (Exception ex) + { + MR.DBG_TRACE_ERROR($"Exception fetching value for '{name}': {ex.Message}"); + } } - catch (Exception ex) - { - MR.DBG_TRACE_ERROR($"Exception fetching value for '{name}': {ex.Message}"); - } - } - private void CheckShowStatusUpdates(bool showStatusMessages) - { - if (showStatusMessages && !this._isInitialized && !this._initializationStatusDisplayActive) + private void CheckShowStatusUpdates(bool showStatusMessages) { - _ = this.ShowStatusUpdates(); + if (showStatusMessages && !this._isInitialized && !this._initializationStatusDisplayActive) + { + _ = this.ShowStatusUpdates(); + } } - } - private async Task ShowStatusUpdates() - { - this._initializationStatusDisplayActive = true; - var displayService = this._services.GetRequiredService(); - - // Wait a brief time for the first startup message to appear - await Task.Delay(TimeSpan.FromSeconds(2.5)); - for (int i = 0; !this._isInitialized; i++) + private async Task ShowStatusUpdates() { - displayService.DisplayText($"Fetching Azure authentication information ({i}s): " - + "this may take 10-20 seconds and may open a browser window ...", "AUTH", true, 2000); - await Task.Delay(TimeSpan.FromSeconds(1)); + this._initializationStatusDisplayActive = true; + var displayService = this._services.GetRequiredService(); + + // Wait a brief time for the first startup message to appear + await Task.Delay(TimeSpan.FromSeconds(2.5)); + for (int i = 0; !this._isInitialized; i++) + { + displayService.DisplayText($"Fetching Azure authentication information ({i}s): " + + "this may take 10-20 seconds and may open a browser window ...", "AUTH", true, 2000); + await Task.Delay(TimeSpan.FromSeconds(1)); + } + displayService.DisplayText($"Fetching Azure authentication information ... Done!", "AUTH", false); + this._initializationStatusDisplayActive = false; } - displayService.DisplayText($"Fetching Azure authentication information ... Done!", "AUTH", false); - this._initializationStatusDisplayActive = false; - } - private readonly IServiceProvider _services; - private readonly ISecretSettings _secretSettings; - private readonly IProtectedSecretSettingsCache _secretSettingsCache; + private readonly IServiceProvider _services; + private readonly ISecretSettings _secretSettings; + private readonly IProtectedSecretSettingsCache _secretSettingsCache; - private readonly Uri? _uri; - private readonly string? _clientId; - private readonly string? _tenantId; - private readonly bool _useKeyVault; + private readonly Uri? _uri; + private readonly string? _clientId; + private readonly string? _tenantId; + private readonly bool _useKeyVault; - private bool _isInitialized; - private bool _initializationStatusDisplayActive; - private readonly SemaphoreSlim _initializationSemaphore = new(initialCount: 1, maxCount: 1); + private bool _isInitialized; + private bool _initializationStatusDisplayActive; + private readonly SemaphoreSlim _initializationSemaphore = new SemaphoreSlim(initialCount: 1, maxCount: 1); - private readonly object _settingsLock = new(); + private readonly object _settingsLock = new object(); - private const string _clientSecretName = "KEY_VAULT_CLIENT_SECRET"; + private const string _clientSecretName = "KEY_VAULT_CLIENT_SECRET"; - private static readonly string[] _keyVaultBackedVariableNames = new[] - { + private static readonly string[] _keyVaultBackedVariableNames = new[] + { // This is the list of hard-coded, predefined variable names for which we'll always wait for a full initialization // and connection before claiming non-presence. Actual value population is based on what's in the vault (which may // not match these), but anything *not* in this list requested before initialization finishes will report 'null' @@ -291,4 +297,5 @@ private async Task ShowStatusUpdates() "TRANSLATOR_ENDPOINT", "TRANSLATOR_REGION", }; -} + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/NuggetExecutionService.cs b/src/cs/CommandSystemServices/NuggetExecutionService.cs index 4f7d7d33..bcdb3e0f 100644 --- a/src/cs/CommandSystemServices/NuggetExecutionService.cs +++ b/src/cs/CommandSystemServices/NuggetExecutionService.cs @@ -1,421 +1,427 @@ +using System; +using System.Collections.Generic; +using System.Linq; using Azure.AI.OpenAI; using System.Text; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; -namespace macaroni; - -internal partial class NuggetExecutionService : INuggetExecutionService +namespace macaroni { - public NuggetExecutionService(IServiceProvider services, IOpenAiCompletionService completionService, IBroadcastMessageService broadcastMessageService) + internal partial class NuggetExecutionService : INuggetExecutionService { - _serviceProvider = services; - _completionService = completionService; - _broadcastMessageService = broadcastMessageService; - } + public NuggetExecutionService(IServiceProvider services, IOpenAiCompletionService completionService, IBroadcastMessageService broadcastMessageService) + { + _serviceProvider = services; + _completionService = completionService; + _broadcastMessageService = broadcastMessageService; + } - public void RegisterNuggets(string groupId, IEnumerable nuggets) - { - var group = RequireNuggetGroup(groupId); - nuggets.ToList().ForEach(nug => group.Add(nug)); - } + public void RegisterNuggets(string groupId, IEnumerable nuggets) + { + var group = RequireNuggetGroup(groupId); + nuggets.ToList().ForEach(nug => group.Add(nug)); + } - public void UnRegisterNuggets(string groupId) - { - var group = GetNuggetGroup(groupId); - group?.Clear(); - } + public void UnRegisterNuggets(string groupId) + { + var group = GetNuggetGroup(groupId); + group?.Clear(); + } - public void StartNotify(string groupId, string callbackId, string nuggetName, string? nuggetParameter, Action callback) - { - lock(_nuggetCallbacks) + public void StartNotify(string groupId, string callbackId, string nuggetName, string? nuggetParameter, Action callback) { - var nuggetCallback = new NuggetTriggerCallback() { GroupId = groupId, CallbackId = callbackId, NuggetName = nuggetName, NuggetParameter = nuggetParameter, Callback = callback }; - AddNuggetTriggerCallback(nuggetCallback); + lock (_nuggetCallbacks) + { + var nuggetCallback = new NuggetTriggerCallback() { GroupId = groupId, CallbackId = callbackId, NuggetName = nuggetName, NuggetParameter = nuggetParameter, Callback = callback }; + AddNuggetTriggerCallback(nuggetCallback); + } } - } - public void StopNotify(string groupId, string? callbackId) - { - lock(_nuggetCallbacks) + public void StopNotify(string groupId, string? callbackId) { - RemoveNuggetTriggerCallback(groupId, callbackId); + lock (_nuggetCallbacks) + { + RemoveNuggetTriggerCallback(groupId, callbackId); + } } - } - public bool AddUserChatMessage(string text) - { - if (!EnsureInitMessages()) return false; + public bool AddUserChatMessage(string text) + { + if (!EnsureInitMessages()) return false; - _messages.Add(new ChatMessage(ChatRole.User, text)); - TrimRuntimeMessages(); + _messages.Add(new ChatMessage(ChatRole.User, text)); + TrimRuntimeMessages(); - return true; - } + return true; + } - public async Task ExecuteAsync(string text) - { - if (!EnsureInitMessages()) return false; + public async Task ExecuteAsync(string text) + { + if (!EnsureInitMessages()) return false; - _broadcastMessageService.BroadcastMessage("nugget.chain.checking", text, null); + _broadcastMessageService.BroadcastMessage("nugget.chain.checking", text, null); - var gpt4 = true; - var deployment = gpt4 ? "robch-gpt-4-0314" : "robch-gpt35-turbo"; + var gpt4 = true; + var deployment = gpt4 ? "robch-gpt-4-0314" : "robch-gpt35-turbo"; - var result = await _completionService.CompleteChat(_messages, null, null, deployment, "800", "0.7", null, null, "0.95"); - MR.DBG_TRACE_VERBOSE($"OpenAI chat result:\n\n*******\n{result}\n*******"); + var result = await _completionService.CompleteChat(_messages, null, null, deployment, "800", "0.7", null, null, "0.95"); + MR.DBG_TRACE_VERBOSE($"OpenAI chat result:\n\n*******\n{result}\n*******"); - _messages.Add(new ChatMessage(ChatRole.Assistant, result)); + _messages.Add(new ChatMessage(ChatRole.Assistant, result)); - var split = result.Split('\n'); - return TryNuggetCallbacksAndChains(split); - } + var split = result.Split('\n'); + return TryNuggetCallbacksAndChains(split); + } - private bool TryNuggetCallbacksAndChains(string[] response) - { - var allNuggets = _nuggets.SelectMany(kvp => kvp.Value).ToList(); - INugget? checkNugget = null; + private bool TryNuggetCallbacksAndChains(string[] response) + { + var allNuggets = _nuggets.SelectMany(kvp => kvp.Value).ToList(); + INugget? checkNugget = null; - var localContext = EnsureLocalContext(); - var executionContext = CreateExecutionContext(); + var localContext = EnsureLocalContext(); + var executionContext = CreateExecutionContext(); - var apisFound = 0; - var apisCompleted = 0; - for (int i = 0; i < response.Count(); i++) - { - var line = response[i]; - if (!line.StartsWith("api: ")) continue; + var apisFound = 0; + var apisCompleted = 0; + for (int i = 0; i < response.Count(); i++) + { + var line = response[i]; + if (!line.StartsWith("api: ")) continue; - var api = line.Substring(5); - apisFound += 1; + var api = line.Substring(5); + apisFound += 1; - var nugget = allNuggets - .Where(x => x.Name == api) - .FirstOrDefault(); + var nugget = allNuggets + .Where(x => x.Name == api) + .FirstOrDefault(); - var found = nugget != null; - if (!found) - { - MR.DBG_TRACE_WARNING($"TryNuggetCallbacksAndChains: Unknown nugget: {api}"); - break; - } + var found = nugget != null; + if (!found) + { + MR.DBG_TRACE_WARNING($"TryNuggetCallbacksAndChains: Unknown nugget: {api}"); + break; + } - var parameters = GetResponseParameters(response, ref i); - var executed = TryExecuteNugget(executionContext, nugget!, parameters); - if (executed) checkNugget = nugget; + var parameters = GetResponseParameters(response, ref i); + var executed = TryExecuteNugget(executionContext, nugget!, parameters); + if (executed) checkNugget = nugget; - var calledCallback = TryNuggetTriggerCallback(api, parameters, localContext); - if (calledCallback) checkNugget = null; + var calledCallback = TryNuggetTriggerCallback(api, parameters, localContext); + if (calledCallback) checkNugget = null; - if (!calledCallback && !executed) - { - MR.DBG_TRACE_WARNING($"TryNuggetCallbacksAndChains: Stopped chain at nugget: {api}"); - break; - } + if (!calledCallback && !executed) + { + MR.DBG_TRACE_WARNING($"TryNuggetCallbacksAndChains: Stopped chain at nugget: {api}"); + break; + } - apisCompleted += 1; - } + apisCompleted += 1; + } - if (apisCompleted == apisFound && apisFound > 0) - { - if (checkNugget != null) + if (apisCompleted == apisFound && apisFound > 0) { - var lastOutput = checkNugget.Outputs?.LastOrDefault(); - if (lastOutput != null) + if (checkNugget != null) { - var value = executionContext.Get(lastOutput, null); - if (value != null) + var lastOutput = checkNugget.Outputs?.LastOrDefault(); + if (lastOutput != null) { - _broadcastMessageService.BroadcastMessage("unexpected.nugget.chain", value.ToString(), null); + var value = executionContext.Get(lastOutput, null); + if (value != null) + { + _broadcastMessageService.BroadcastMessage("unexpected.nugget.chain", value.ToString(), null); + } } } + + MR.DBG_TRACE_INFO($"TryNuggetCallbacksAndChains: Completed {apisCompleted} nugget triggers/executions"); + return true; } - MR.DBG_TRACE_INFO($"TryNuggetCallbacksAndChains: Completed {apisCompleted} nugget triggers/executions"); - return true; + return false; } - return false; - } + private object? ResolveContext(string name, IDictionary parameters) + { + if (name == "context") return string.Join('\n', parameters.Keys); + return parameters.ContainsKey(name) ? parameters[name] : null; + } - private object? ResolveContext(string name, IDictionary parameters) - { - if (name == "context") return string.Join('\n', parameters.Keys); - return parameters.ContainsKey(name) ? parameters[name] : null; - } + private IDictionary GetResponseParameters(string[] response, ref int i) + { + var parameters = new Dictionary(); - private IDictionary GetResponseParameters(string[] response, ref int i) - { - var parameters = new Dictionary(); + for (var p = i + 1; p < response.Count(); p++) + { + var line = response[p]; + if (string.IsNullOrEmpty(line)) break; - for (var p = i + 1; p < response.Count(); p++) - { - var line = response[p]; - if (string.IsNullOrEmpty(line)) break; + var name = line.Before(':'); + if (string.IsNullOrEmpty(name)) break; - var name = line.Before(':'); - if (string.IsNullOrEmpty(name)) break; + var value = line.After(':'); + if (string.IsNullOrEmpty(value)) break; - var value = line.After(':'); - if (string.IsNullOrEmpty(value)) break; + i += 1; - i += 1; + if (value.StartsWith('\"') && value.EndsWith('\"')) + { + value = value.Substring(1, value.Length - 2); + } + if (value.StartsWith('\'') && value.EndsWith('\'')) + { + value = value.Substring(1, value.Length - 2); + } - if (value.StartsWith('\"') && value.EndsWith('\"')) - { - value = value.Substring(1, value.Length - 2); - } - if (value.StartsWith('\'') && value.EndsWith('\'')) - { - value = value.Substring(1, value.Length - 2); + if (value != "null") + { + parameters.Add(name, value); + } } - if (value != "null") - { - parameters.Add(name, value); - } + var traceParams = string.Join(", ", parameters.Select(kvp => $"{kvp.Key}={kvp.Value}")); + MR.DBG_TRACE_INFO($"GetResponseParameters: {traceParams}"); + + return parameters; } - var traceParams = string.Join(", ", parameters.Select(kvp => $"{kvp.Key}={kvp.Value}")); - MR.DBG_TRACE_INFO($"GetResponseParameters: {traceParams}"); + private bool TryExecuteNugget(IExecutionContext context, INugget nugget, IDictionary parameters) + { + var executable = nugget != null && nugget.Executors?.Count() > 0; + if (!executable) return false; - return parameters; - } + context.RegisterResolver(nameof(NuggetExecutionService), name => ResolveContext(name, parameters)); + nugget!.Executors!.Execute(context); - private bool TryExecuteNugget(IExecutionContext context, INugget nugget, IDictionary parameters) - { - var executable = nugget != null && nugget.Executors?.Count() > 0; - if (!executable) return false; + var localContext = EnsureLocalContext(); + nugget!.Outputs?.ToList().ForEach(name => + { + var value = context.Get(name, null); + if (value != null) localContext.Set(name, value, SetValueKind.InterleavedWithResolvers); + }); - context.RegisterResolver(nameof(NuggetExecutionService), name => ResolveContext(name, parameters)); - nugget!.Executors!.Execute(context); + return true; + } - var localContext = EnsureLocalContext(); - nugget!.Outputs?.ToList().ForEach(name => + private bool TryNuggetTriggerCallback(string name, IDictionary parameters, ILocalContext localContext) { - var value = context.Get(name, null); - if (value != null) localContext.Set(name, value, SetValueKind.InterleavedWithResolvers); - }); + lock (_nuggetCallbacks) + { + var ncs = GetNuggetTriggerCallbacks(name, parameters).ToList(); + ncs.Reverse(); - return true; - } + foreach (var nc in ncs) + { + var triggerContext = CreateTriggerContext(parameters, localContext); + nc.Callback(nc.GroupId, nc.CallbackId, name, nc.NuggetParameter, triggerContext); + return true; + } - private bool TryNuggetTriggerCallback(string name, IDictionary parameters, ILocalContext localContext) - { - lock (_nuggetCallbacks) - { - var ncs = GetNuggetTriggerCallbacks(name, parameters).ToList(); - ncs.Reverse(); + return false; + } + } - foreach (var nc in ncs) + private IExecutionContext CreateTriggerContext(IDictionary parameters, ILocalContext localContext) + { + var triggerContext = CreateExecutionContext(); + foreach (var key in parameters.Keys) { - var triggerContext = CreateTriggerContext(parameters, localContext); - nc.Callback(nc.GroupId, nc.CallbackId, name, nc.NuggetParameter, triggerContext); - return true; + var value = parameters[key]; + value = localContext.Resolve(value); + if (value != null) + { + triggerContext.Set(key, value); + } } - return false; + return triggerContext; } - } - private IExecutionContext CreateTriggerContext(IDictionary parameters, ILocalContext localContext) - { - var triggerContext = CreateExecutionContext(); - foreach (var key in parameters.Keys) + private ILocalContext EnsureLocalContext() { - var value = parameters[key]; - value = localContext.Resolve(value); - if (value != null) + if (_nuggetContext == null) { - triggerContext.Set(key, value); + _nuggetContext = _serviceProvider.GetRequiredService(); } - } - return triggerContext; - } + return _nuggetContext!; + } - private ILocalContext EnsureLocalContext() - { - if (_nuggetContext == null) + private IExecutionContext CreateExecutionContext() { - _nuggetContext = _serviceProvider.GetRequiredService(); + var context = _serviceProvider.GetRequiredService(); + context.RegisterResolver(nameof(ICommandSet), key => EnsureLocalContext()?.Get(key, null)); + return context; } - return _nuggetContext!; - } - - private IExecutionContext CreateExecutionContext() - { - var context = _serviceProvider.GetRequiredService(); - context.RegisterResolver(nameof(ICommandSet), key => EnsureLocalContext()?.Get(key, null)); - return context; - } - - private IEnumerable GetNuggetTriggerCallbacks(string name, IDictionary parameters) - { - return _nuggetCallbacks.SelectMany(x => x.Value - .Where(kvp => kvp.Value.NuggetName == name) - .Where(kvp => kvp.Value.NuggetParameter == null || parameters.ContainsKey(kvp.Value.NuggetParameter)) - .Select(kvp => kvp.Value)); - } - - private IList? GetNuggetGroup(string groupId) - { - return _nuggets.ContainsKey(groupId) ? _nuggets[groupId] : null; - } + private IEnumerable GetNuggetTriggerCallbacks(string name, IDictionary parameters) + { + return _nuggetCallbacks.SelectMany(x => x.Value + .Where(kvp => kvp.Value.NuggetName == name) + .Where(kvp => kvp.Value.NuggetParameter == null || parameters.ContainsKey(kvp.Value.NuggetParameter)) + .Select(kvp => kvp.Value)); + } - private IList RequireNuggetGroup(string groupId) - { - if (!_nuggets.ContainsKey(groupId)) + private IList? GetNuggetGroup(string groupId) { - _nuggets[groupId] = new List(); + return _nuggets.ContainsKey(groupId) ? _nuggets[groupId] : null; } - return _nuggets[groupId]; - } - private IDictionary? GetTriggerCallbackGroup(string groupId) - { - return _nuggetCallbacks.ContainsKey(groupId) ? _nuggetCallbacks[groupId] : null; - } + private IList RequireNuggetGroup(string groupId) + { + if (!_nuggets.ContainsKey(groupId)) + { + _nuggets[groupId] = new List(); + } + return _nuggets[groupId]; + } - private IDictionary RequireTriggerCallbackGroup(string groupId) - { - if (!_nuggetCallbacks.ContainsKey(groupId)) + private IDictionary? GetTriggerCallbackGroup(string groupId) { - _nuggetCallbacks[groupId] = new Dictionary(); + return _nuggetCallbacks.ContainsKey(groupId) ? _nuggetCallbacks[groupId] : null; } - return _nuggetCallbacks[groupId]; - } - private void AddNuggetTriggerCallback(NuggetTriggerCallback nc) - { - RemoveNuggetTriggerCallback(nc.GroupId, nc.CallbackId); - RequireTriggerCallbackGroup(nc.GroupId).Add(nc.CallbackId, nc); - } + private IDictionary RequireTriggerCallbackGroup(string groupId) + { + if (!_nuggetCallbacks.ContainsKey(groupId)) + { + _nuggetCallbacks[groupId] = new Dictionary(); + } + return _nuggetCallbacks[groupId]; + } - private void RemoveNuggetTriggerCallback(string groupId, string? callbackId) - { - var group = GetTriggerCallbackGroup(groupId); - if (callbackId == null) + private void AddNuggetTriggerCallback(NuggetTriggerCallback nc) { - group?.Clear(); + RemoveNuggetTriggerCallback(nc.GroupId, nc.CallbackId); + RequireTriggerCallbackGroup(nc.GroupId).Add(nc.CallbackId, nc); } - else + + private void RemoveNuggetTriggerCallback(string groupId, string? callbackId) { - group?.Remove(callbackId); + var group = GetTriggerCallbackGroup(groupId); + if (callbackId == null) + { + group?.Clear(); + } + else + { + group?.Remove(callbackId); + } } - } - private bool EnsureInitMessages() - { - lock (_messages) + private bool EnsureInitMessages() { - if (_messages.Count == 0) + lock (_messages) { - InitChatMessages(); + if (_messages.Count == 0) + { + InitChatMessages(); + } } + + return _messages.Count > 0; } - return _messages.Count > 0; - } + private void InitChatMessages() + { + var allNuggets = _nuggets.SelectMany(kvp => kvp.Value); + var systemNugget = allNuggets.Where(x => x.Name == "nugget_system_message").FirstOrDefault(); + var otherNuggets = allNuggets.Where(x => x.Name != "nugget_system_message"); - private void InitChatMessages() - { - var allNuggets = _nuggets.SelectMany(kvp => kvp.Value); - var systemNugget = allNuggets.Where(x => x.Name == "nugget_system_message").FirstOrDefault(); - var otherNuggets = allNuggets.Where(x => x.Name != "nugget_system_message"); + string nuggets = GetNuggetAPIsAndInstructions(otherNuggets); + var systemMessage = InitSystemChatMessage(systemNugget, nuggets); + if (systemMessage != null) _messages.Add(systemMessage); - string nuggets = GetNuggetAPIsAndInstructions(otherNuggets); - var systemMessage = InitSystemChatMessage(systemNugget, nuggets); - if (systemMessage != null) _messages.Add(systemMessage); + var examples = systemNugget?.Examples ?? Enumerable.Empty(); + foreach (var example in examples) + { + var ok = !string.IsNullOrEmpty(example.User); + if (ok) _messages.Add(new ChatMessage(ChatRole.User, example.User)); - var examples = systemNugget?.Examples ?? Enumerable.Empty(); - foreach (var example in examples) - { - var ok = !string.IsNullOrEmpty(example.User); - if (ok) _messages.Add(new ChatMessage(ChatRole.User, example.User)); + ok = !string.IsNullOrEmpty(example.Assistant); + if (ok) _messages.Add(new ChatMessage(ChatRole.Assistant, example.Assistant)); + } - ok = !string.IsNullOrEmpty(example.Assistant); - if (ok) _messages.Add(new ChatMessage(ChatRole.Assistant, example.Assistant)); + _maxNuggetMessages = _messages.Count; } - _maxNuggetMessages = _messages.Count; - } - - private void TrimRuntimeMessages() - { - lock (_messages) + private void TrimRuntimeMessages() { - var maxMessages = _maxNuggetMessages + _maxRuntimeMessages; - if (_messages.Count > maxMessages) + lock (_messages) { - _messages.RemoveRange(_maxNuggetMessages, _messages.Count - maxMessages); + var maxMessages = _maxNuggetMessages + _maxRuntimeMessages; + if (_messages.Count > maxMessages) + { + _messages.RemoveRange(_maxNuggetMessages, _messages.Count - maxMessages); + } } } - } - private string GetNuggetAPIsAndInstructions(IEnumerable otherNuggets) - { - var sb = new StringBuilder(); - foreach (var nugget in otherNuggets) + private string GetNuggetAPIsAndInstructions(IEnumerable otherNuggets) { - var api = nugget.Name; - if (api == null) continue; + var sb = new StringBuilder(); + foreach (var nugget in otherNuggets) + { + var api = nugget.Name; + if (api == null) continue; - var desc = nugget.Description; - var parameters = nugget.Parameters?.Count() > 0 ? string.Join(", ", nugget.Parameters) : null; - var instructions = nugget.Instructions?.Count() > 0 ? string.Join('\n', nugget.Instructions) : null; - var outputs = nugget.Outputs?.Count() > 0 ? string.Join('\n', nugget.Outputs) : null; + var desc = nugget.Description; + var parameters = nugget.Parameters?.Count() > 0 ? string.Join(", ", nugget.Parameters) : null; + var instructions = nugget.Instructions?.Count() > 0 ? string.Join('\n', nugget.Instructions) : null; + var outputs = nugget.Outputs?.Count() > 0 ? string.Join('\n', nugget.Outputs) : null; - var ok = api != null; - if (ok) sb.AppendLine($"- api: {api}"); + var ok = api != null; + if (ok) sb.AppendLine($"- api: {api}"); - ok = desc != null; - if (ok) sb.AppendLine($" description: {desc}"); + ok = desc != null; + if (ok) sb.AppendLine($" description: {desc}"); - ok = parameters != null; - if (ok) sb.AppendLine($" parameters: [ {parameters} ]"); + ok = parameters != null; + if (ok) sb.AppendLine($" parameters: [ {parameters} ]"); - ok = instructions != null; - if (ok) sb.AppendLine(" instructions: |\n" + space4 + instructions?.Replace("\n", lfSpace4)); + ok = instructions != null; + if (ok) sb.AppendLine(" instructions: |\n" + space4 + instructions?.Replace("\n", lfSpace4)); - ok = outputs != null; - if (ok) sb.AppendLine(" outputs: |\n" + space4 + outputs?.Replace("\n", lfSpace4)); + ok = outputs != null; + if (ok) sb.AppendLine(" outputs: |\n" + space4 + outputs?.Replace("\n", lfSpace4)); - sb.AppendLine(); - } + sb.AppendLine(); + } - return sb.ToString().Trim(); - } + return sb.ToString().Trim(); + } - private ChatMessage? InitSystemChatMessage(INugget? systemNugget, string nuggets) - { - var instructions = systemNugget?.Instructions?.Count() > 0 ? string.Join('\n', systemNugget.Instructions) : null; - if (instructions == null) return null; + private ChatMessage? InitSystemChatMessage(INugget? systemNugget, string nuggets) + { + var instructions = systemNugget?.Instructions?.Count() > 0 ? string.Join('\n', systemNugget.Instructions) : null; + if (instructions == null) return null; - instructions = instructions.Replace("{nuggets}", nuggets); - return new ChatMessage(ChatRole.System, instructions); - } + instructions = instructions.Replace("{nuggets}", nuggets); + return new ChatMessage(ChatRole.System, instructions); + } - internal struct NuggetTriggerCallback - { - internal string GroupId; - internal string CallbackId; - internal string NuggetName; - internal string? NuggetParameter; - internal Action Callback; - } + internal struct NuggetTriggerCallback + { + internal string GroupId; + internal string CallbackId; + internal string NuggetName; + internal string? NuggetParameter; + internal Action Callback; + } - private readonly IServiceProvider _serviceProvider; - private readonly IOpenAiCompletionService _completionService; - private readonly IBroadcastMessageService _broadcastMessageService; - private readonly List _messages = new(); + private readonly IServiceProvider _serviceProvider; + private readonly IOpenAiCompletionService _completionService; + private readonly IBroadcastMessageService _broadcastMessageService; + private readonly List _messages = new List(); - private int _maxNuggetMessages; - private readonly int _maxRuntimeMessages = 4; + private int _maxNuggetMessages; + private readonly int _maxRuntimeMessages = 4; - private Dictionary> _nuggetCallbacks = new(); - private Dictionary> _nuggets = new(); + private Dictionary> _nuggetCallbacks = new Dictionary>(); + private Dictionary> _nuggets = new Dictionary>(); - private string space4 = " "; - private string lfSpace4 = "\n "; - private ILocalContext? _nuggetContext; -} + private string space4 = " "; + private string lfSpace4 = "\n "; + private ILocalContext? _nuggetContext; + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/OpenAICompletionService.cs b/src/cs/CommandSystemServices/OpenAICompletionService.cs index 12de7eda..43f4c95d 100644 --- a/src/cs/CommandSystemServices/OpenAICompletionService.cs +++ b/src/cs/CommandSystemServices/OpenAICompletionService.cs @@ -1,58 +1,101 @@ -using Microsoft.CognitiveServices.Speech; -using Microsoft.CognitiveServices.Speech.Audio; + +/* Unmerged change from project 'macaroni_core (net6.0-windows)' +Before: +using Microsoft.CognitiveServices.Speech; +After: +using Azure; +using Azure.AI.OpenAI; +using Microsoft.CognitiveServices.Speech; +*/ + +/* Unmerged change from project 'macaroni_core (netstandard2.1)' +Before: +using Microsoft.CognitiveServices.Speech; +After: +using Azure; +using Azure.AI.OpenAI; +using Microsoft.CognitiveServices.Speech; +*/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using Azure; +using Azure.AI.OpenAI; using Microsoft.Extensions.DependencyInjection; -using System.Diagnostics; +using Newtonsoft.Json; + +/* Unmerged change from project 'macaroni_core (net6.0-windows)' +Before: using System.Text; using Newtonsoft.Json; using Azure.AI.OpenAI; using Azure; +After: +using System.Diagnostics; +using System.Text; +*/ -namespace macaroni; +/* Unmerged change from project 'macaroni_core (netstandard2.1)' +Before: +using System.Text; +using Newtonsoft.Json; +using Azure.AI.OpenAI; +using Azure; +After: +using System.Diagnostics; +using System.Text; +*/ +using System.Text; +using System.Threading.Tasks; -internal class OpenAiCompletionService : IOpenAiCompletionService +namespace macaroni { - public OpenAiCompletionService(IServiceProvider services) + internal class OpenAiCompletionService : IOpenAiCompletionService { - _serviceProvider = services; - } + public OpenAiCompletionService(IServiceProvider services) + { + _serviceProvider = services; + } - public async Task CompleteChat(IList messages, string? key, string? endpoint, string? deployment, string? maxTokens, string? temperature, string? frequencyPenalty, string? presencePenalty, string? topP, string? stop) - { - var service = _serviceProvider.GetRequiredService(); - service.GetOpenAiConnectionInfo(out var defaultKey, out var defaultEndpoint, out var defaultDeployment); + public async Task CompleteChat(IList messages, string? key, string? endpoint, string? deployment, string? maxTokens, string? temperature, string? frequencyPenalty, string? presencePenalty, string? topP, string? stop) + { + var service = _serviceProvider.GetRequiredService(); + service.GetOpenAiConnectionInfo(out var defaultKey, out var defaultEndpoint, out var defaultDeployment); - key ??= defaultKey; - endpoint ??= defaultEndpoint; - deployment ??= defaultDeployment; + key ??= defaultKey; + endpoint ??= defaultEndpoint; + deployment ??= defaultDeployment; - var client = new OpenAIClient( - new Uri(endpoint!), - new AzureKeyCredential(key!)); + var client = new OpenAIClient( + new Uri(endpoint!), + new AzureKeyCredential(key!)); - var options = new ChatCompletionsOptions(); - messages.ToList().ForEach(m => options.Messages.Add(m)); + var options = new ChatCompletionsOptions(); + messages.ToList().ForEach(m => options.Messages.Add(m)); - options.MaxTokens = TryParse(maxTokens, _defaultMaxTokens); - options.Temperature = TryParse(temperature, _defaultTemperature); - options.FrequencyPenalty = TryParse(frequencyPenalty, _defaultFrequencyPenalty); - options.PresencePenalty = TryParse(presencePenalty, _defaultPresencePenalty); + options.MaxTokens = TryParse(maxTokens, _defaultMaxTokens); + options.Temperature = TryParse(temperature, _defaultTemperature); + options.FrequencyPenalty = TryParse(frequencyPenalty, _defaultFrequencyPenalty); + options.PresencePenalty = TryParse(presencePenalty, _defaultPresencePenalty); - if (!string.IsNullOrEmpty(stop)) - { - var stops = stop.Split('\n', StringSplitOptions.RemoveEmptyEntries).ToList(); - stops.ForEach(s => options.StopSequences.Add(s)); - } + if (!string.IsNullOrEmpty(stop)) + { + var stops = stop.Split('\n', StringSplitOptions.RemoveEmptyEntries).ToList(); + stops.ForEach(s => options.StopSequences.Add(s)); + } - var response = await client.GetChatCompletionsAsync(deployment, options); - return response.Value.Choices[0].Message.Content; - } + var response = await client.GetChatCompletionsAsync(deployment, options); + return response.Value.Choices[0].Message.Content; + } - public async Task Complete(string prompt, string? key, string? endpoint, string? deployment, string? maxTokens, string? temperature, string? frequencyPenalty, string? presencePenalty, string? topP, string? stop) - { - using (var client = new HttpClient()) - using (var request = GetCompleteRequestMessage(key, endpoint, deployment)) + public async Task Complete(string prompt, string? key, string? endpoint, string? deployment, string? maxTokens, string? temperature, string? frequencyPenalty, string? presencePenalty, string? topP, string? stop) { - object[] body = new object[]{ new { + using (var client = new HttpClient()) + using (var request = GetCompleteRequestMessage(key, endpoint, deployment)) + { + object[] body = new object[]{ new { prompt = prompt, temperature = TryParse(temperature, _defaultTemperature), max_tokens = TryParse(maxTokens, _defaultMaxTokens), @@ -61,108 +104,109 @@ public async Task Complete(string prompt, string? key, string? endpoint, top_p = TryParse(topP, _defaultTopP), stop = !string.IsNullOrEmpty(stop) ? stop.Split('\n', StringSplitOptions.RemoveEmptyEntries) : null } }; - var requestBody = JsonConvert.SerializeObject(body[0]); + var requestBody = JsonConvert.SerializeObject(body[0]); - request.Content = new StringContent(requestBody, Encoding.UTF8, "application/json"); + request.Content = new StringContent(requestBody, Encoding.UTF8, "application/json"); - var response = await client.SendAsync(request); - var asString = await response.Content.ReadAsStringAsync(); - var result = JsonConvert.DeserializeObject(asString); + var response = await client.SendAsync(request); + var asString = await response.Content.ReadAsStringAsync(); + var result = JsonConvert.DeserializeObject(asString); - return result.Error?.Message - ?? result.Choices?[0].Text - ?? string.Empty; + return result.Error?.Message + ?? result.Choices?[0].Text + ?? string.Empty; + } } - } - private int TryParse(string? s, int defaultValue) - { - return !string.IsNullOrEmpty(s) && int.TryParse(s, out var parsed) ? parsed : defaultValue; - } + private int TryParse(string? s, int defaultValue) + { + return !string.IsNullOrEmpty(s) && int.TryParse(s, out var parsed) ? parsed : defaultValue; + } - private float TryParse(string? s, float defaultValue) - { - return !string.IsNullOrEmpty(s) && float.TryParse(s, out var parsed) ? parsed : defaultValue; - } + private float TryParse(string? s, float defaultValue) + { + return !string.IsNullOrEmpty(s) && float.TryParse(s, out var parsed) ? parsed : defaultValue; + } - private HttpRequestMessage GetCompleteRequestMessage(string? key, string? endpoint, string? deployment) - { - var service = _serviceProvider.GetRequiredService(); - service.GetOpenAiConnectionInfo(out var defaultKey, out var defaultEndpoint, out var defaultDeployment); + private HttpRequestMessage GetCompleteRequestMessage(string? key, string? endpoint, string? deployment) + { + var service = _serviceProvider.GetRequiredService(); + service.GetOpenAiConnectionInfo(out var defaultKey, out var defaultEndpoint, out var defaultDeployment); - key ??= defaultKey; - endpoint ??= defaultEndpoint; - deployment ??= defaultDeployment; + key ??= defaultKey; + endpoint ??= defaultEndpoint; + deployment ??= defaultDeployment; - var uri = GetOpenAiCompletionUri(endpoint, deployment); + var uri = GetOpenAiCompletionUri(endpoint, deployment); - var request = new HttpRequestMessage(); - request.Method = HttpMethod.Post; - request.RequestUri = new Uri(uri); - request.Headers.Add(SubscriptionKeyHeader, key); + var request = new HttpRequestMessage(); + request.Method = HttpMethod.Post; + request.RequestUri = new Uri(uri); + request.Headers.Add(SubscriptionKeyHeader, key); - return request; - } + return request; + } - private static string GetOpenAiCompletionUri(string? endpoint, string? deployment) - { - var sb = new StringBuilder(); - sb.Append(EnsureEndpoint(endpoint)); - sb.Append(GetOpenAiCompletionRoute(deployment)); - var uri = sb.ToString(); - return uri; - } + private static string GetOpenAiCompletionUri(string? endpoint, string? deployment) + { + var sb = new StringBuilder(); + sb.Append(EnsureEndpoint(endpoint)); + sb.Append(GetOpenAiCompletionRoute(deployment)); + var uri = sb.ToString(); + return uri; + } - private static string EnsureEndpoint(string? endpoint) - { - return endpoint ?? "https://api.openai.azure.com/"; - } + private static string EnsureEndpoint(string? endpoint) + { + return endpoint ?? "https://api.openai.azure.com/"; + } - private static string GetOpenAiCompletionRoute(string? deployment) - { - return $"/openai/deployments/{deployment}/completions?api-version=2022-06-01-preview"; - } + private static string GetOpenAiCompletionRoute(string? deployment) + { + return $"/openai/deployments/{deployment}/completions?api-version=2022-06-01-preview"; + } - #region supporting model classes + #region supporting model classes - public struct CompletionResult - { - [JsonProperty(PropertyName = "id")] - public string? Id { get; set; } + public struct CompletionResult + { + [JsonProperty(PropertyName = "id")] + public string? Id { get; set; } - [JsonProperty(PropertyName = "error")] - public ResultError? Error { get; set; } + [JsonProperty(PropertyName = "error")] + public ResultError? Error { get; set; } - [JsonProperty(PropertyName = "choices")] - public ResultChoice[]? Choices { get; set; } - } + [JsonProperty(PropertyName = "choices")] + public ResultChoice[]? Choices { get; set; } + } - public struct ResultError - { - [JsonProperty(PropertyName = "message")] - public string? Message { get; set; } - } + public struct ResultError + { + [JsonProperty(PropertyName = "message")] + public string? Message { get; set; } + } - public struct ResultChoice - { - [JsonProperty(PropertyName = "text")] - public string? Text { get; set; } + public struct ResultChoice + { + [JsonProperty(PropertyName = "text")] + public string? Text { get; set; } - [JsonProperty(PropertyName = "index")] - public int? Index { get; set; } + [JsonProperty(PropertyName = "index")] + public int? Index { get; set; } - [JsonProperty(PropertyName = "finish_reason")] - public string? FinishReason { get; set; } - } + [JsonProperty(PropertyName = "finish_reason")] + public string? FinishReason { get; set; } + } - #endregion + #endregion - private readonly IServiceProvider _serviceProvider; + private readonly IServiceProvider _serviceProvider; - private const string SubscriptionKeyHeader = "api-key"; - private const int _defaultMaxTokens = 100; - private const float _defaultTemperature = 0.2f; - private const float _defaultFrequencyPenalty = 0.0f; - private const float _defaultPresencePenalty = 0.0f; - private const float _defaultTopP = 0.5f; -} + private const string SubscriptionKeyHeader = "api-key"; + private const int _defaultMaxTokens = 100; + private const float _defaultTemperature = 0.2f; + private const float _defaultFrequencyPenalty = 0.0f; + private const float _defaultPresencePenalty = 0.0f; + private const float _defaultTopP = 0.5f; + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/OpenAIConfigService.cs b/src/cs/CommandSystemServices/OpenAIConfigService.cs index 96ae782d..76dd8187 100644 --- a/src/cs/CommandSystemServices/OpenAIConfigService.cs +++ b/src/cs/CommandSystemServices/OpenAIConfigService.cs @@ -1,23 +1,23 @@ -using Microsoft.CognitiveServices.Speech; -using Microsoft.CognitiveServices.Speech.Intent; +using System; using Microsoft.Extensions.DependencyInjection; -namespace macaroni; - -internal class OpenAiConfigService : IOpenAiConfigService +namespace macaroni { - public OpenAiConfigService(IServiceProvider services) + internal class OpenAiConfigService : IOpenAiConfigService { - _serviceProvider = services; - } + public OpenAiConfigService(IServiceProvider services) + { + _serviceProvider = services; + } - public void GetOpenAiConnectionInfo(out string? key, out string? endpoint, out string? deployment) - { - var settings = _serviceProvider.GetRequiredService(); - key = settings.Get("OPEN_AI_KEY")?.Trim(); - endpoint = settings.Get("OPEN_AI_ENDPOINT")?.Trim(); - deployment = settings.Get("OPEN_AI_DEPLOYMENT")?.Trim(); - } + public void GetOpenAiConnectionInfo(out string? key, out string? endpoint, out string? deployment) + { + var settings = _serviceProvider.GetRequiredService(); + key = settings.Get("OPEN_AI_KEY")?.Trim(); + endpoint = settings.Get("OPEN_AI_ENDPOINT")?.Trim(); + deployment = settings.Get("OPEN_AI_DEPLOYMENT")?.Trim(); + } - private readonly IServiceProvider _serviceProvider; -} + private readonly IServiceProvider _serviceProvider; + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/ProtectedSettingsMemoryCache.cs b/src/cs/CommandSystemServices/ProtectedSettingsMemoryCache.cs index e6e83788..a292f7ff 100644 --- a/src/cs/CommandSystemServices/ProtectedSettingsMemoryCache.cs +++ b/src/cs/CommandSystemServices/ProtectedSettingsMemoryCache.cs @@ -1,23 +1,26 @@ -namespace macaroni; +using System.Collections.Generic; -public class ProtectedSettingsMemoryCache : IProtectedSecretSettingsCache +namespace macaroni { - public void Set(string name, string? value) + public class ProtectedSettingsMemoryCache : IProtectedSecretSettingsCache { - if (value != null) + public void Set(string name, string? value) { - _memoryCache[name] = value; + if (value != null) + { + _memoryCache[name] = value; + } + else if (_memoryCache.ContainsKey(name)) + { + _memoryCache.Remove(name); + } } - else if (_memoryCache.ContainsKey(name)) + + public bool TryGet(string name, out string? value) { - _memoryCache.Remove(name); + return _memoryCache.TryGetValue(name, out value); } - } - public bool TryGet(string name, out string? value) - { - return _memoryCache.TryGetValue(name, out value); + private Dictionary _memoryCache = new Dictionary(); } - - private Dictionary _memoryCache = new(); -} +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/RandomNumberService.cs b/src/cs/CommandSystemServices/RandomNumberService.cs index e879d72c..74ec819b 100644 --- a/src/cs/CommandSystemServices/RandomNumberService.cs +++ b/src/cs/CommandSystemServices/RandomNumberService.cs @@ -1,15 +1,18 @@ -using System.Diagnostics; +using System; +using System.Collections.Generic; +using System.Linq; -namespace macaroni; - -internal class RandomNumberService : IRandomNumberService +namespace macaroni { - string IRandomNumberService.PickRandom(IEnumerable values) + internal class RandomNumberService : IRandomNumberService { - var array = values.ToArray(); - var random = _random.Next(array.Count()); - return array[random]; - } + string IRandomNumberService.PickRandom(IEnumerable values) + { + var array = values.ToArray(); + var random = _random.Next(array.Count()); + return array[random]; + } - private Random _random = new(); -} + private Random _random = new Random(); + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/RunAppService.cs b/src/cs/CommandSystemServices/RunAppService.cs index 488e5a67..258a335c 100644 --- a/src/cs/CommandSystemServices/RunAppService.cs +++ b/src/cs/CommandSystemServices/RunAppService.cs @@ -1,231 +1,236 @@ +using System; +using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; using System.Diagnostics; +using System.Linq; +using System.Threading; -namespace macaroni; - -internal class RunAppService : IRunAppService +namespace macaroni { - public RunAppService(IServiceProvider serviceProvider) + internal class RunAppService : IRunAppService { - _serviceProvider = serviceProvider; - _sendKeys = _serviceProvider.GetService(); - } - - public void Run(string processOrCommand, string? arguments) - { - var process = StartProcess(processOrCommand, arguments); - if (process == null) + public RunAppService(IServiceProvider serviceProvider) { - process = StartCommand(processOrCommand, arguments); + _serviceProvider = serviceProvider; + _sendKeys = _serviceProvider.GetService(); } - if (process == null && arguments == null && processOrCommand.StartsWith("https:") && OS.IsAndroid()) + + public void Run(string processOrCommand, string? arguments) { - var androidIntents = _serviceProvider.GetRequiredService (); - androidIntents.StartActivity("android.intent.action.VIEW", processOrCommand, null); + var process = StartProcess(processOrCommand, arguments); + if (process == null) + { + process = StartCommand(processOrCommand, arguments); + } + if (process == null && arguments == null && processOrCommand.StartsWith("https:") && OS.IsAndroid()) + { + var androidIntents = _serviceProvider.GetRequiredService(); + androidIntents.StartActivity("android.intent.action.VIEW", processOrCommand, null); + } } - } - public Process? StartProcess(string process, string? arguments) - { - SendEmptyKeys(); - try + public Process? StartProcess(string process, string? arguments) { - var start = arguments == null - ? new ProcessStartInfo(process) - : new ProcessStartInfo(process, arguments); + SendEmptyKeys(); + try + { + var start = arguments == null + ? new ProcessStartInfo(process) + : new ProcessStartInfo(process, arguments); - start.UseShellExecute = false; - return Process.Start(start); - } - catch (Exception ex) - { - MR.DBG_TRACE_WARNING(ex.ToString()); + start.UseShellExecute = false; + return Process.Start(start); + } + catch (Exception ex) + { + MR.DBG_TRACE_WARNING(ex.ToString()); + } + return null; } - return null; - } - public Process? StartCommand(string command, string? arguments) - { - SendEmptyKeys(); - try + public Process? StartCommand(string command, string? arguments) { - var start = arguments == null - ? new ProcessStartInfo(command) - : new ProcessStartInfo(command, arguments); - - if (OS.IsWindows()) start.UseShellExecute = true; + SendEmptyKeys(); + try + { + var start = arguments == null + ? new ProcessStartInfo(command) + : new ProcessStartInfo(command, arguments); + + if (OS.IsWindows()) start.UseShellExecute = true; - return Process.Start(start); + return Process.Start(start); + } + catch (Exception ex) + { + MR.DBG_TRACE_WARNING(ex.ToString()); + } + return null; } - catch (Exception ex) + + public bool SwitchTo(string? title, string? process, string? titleOrProcess, string? exclude) { - MR.DBG_TRACE_WARNING(ex.ToString()); + return FindAndSwitchTo(title, process, titleOrProcess, exclude); } - return null; - } - - public bool SwitchTo(string? title, string? process, string? titleOrProcess, string? exclude) - { - return FindAndSwitchTo(title, process, titleOrProcess, exclude); - } - public bool Minimize(string? title, string? process, string? titleOrProcess, string? exclude, bool all = false) - { - return all - ? CheckMultiLineAndThen(title, process, titleOrProcess, exclude, FindAndMinimizeAll) - : FindAndMinimize(title, process, titleOrProcess, exclude); - } - - public bool Maximize(string? title, string? process, string? titleOrProcess, string? exclude, bool all = false) - { - return all - ? CheckMultiLineAndThen(title, process, titleOrProcess, exclude, FindAndMaximizeAll) - : FindAndMaximize(title, process, titleOrProcess, exclude); - } + public bool Minimize(string? title, string? process, string? titleOrProcess, string? exclude, bool all = false) + { + return all + ? CheckMultiLineAndThen(title, process, titleOrProcess, exclude, FindAndMinimizeAll) + : FindAndMinimize(title, process, titleOrProcess, exclude); + } - public bool Restore(string? title, string? process, string? titleOrProcess, string? exclude, bool all = false) - { - return all - ? CheckMultiLineAndThen(title, process, titleOrProcess, exclude, FindAndRestoreAll) - : FindAndRestore(title, process, titleOrProcess, exclude); - } + public bool Maximize(string? title, string? process, string? titleOrProcess, string? exclude, bool all = false) + { + return all + ? CheckMultiLineAndThen(title, process, titleOrProcess, exclude, FindAndMaximizeAll) + : FindAndMaximize(title, process, titleOrProcess, exclude); + } - public bool Close(string? title, string? process, string? titleOrProcess, string? exclude, bool all = false) - { - return all - ? CheckMultiLineAndThen(title, process, titleOrProcess, exclude, FindAndCloseAll) - : FindAndClose(title, process, titleOrProcess, exclude); - } + public bool Restore(string? title, string? process, string? titleOrProcess, string? exclude, bool all = false) + { + return all + ? CheckMultiLineAndThen(title, process, titleOrProcess, exclude, FindAndRestoreAll) + : FindAndRestore(title, process, titleOrProcess, exclude); + } - private bool CheckMultiLineAndThen(string? title, string? process, string? titleOrProcess, string? exclude, Func fn) - { - var multiTitle = Split(title) ?? Enumerable.Empty(); - var multiProcess = Split(process) ?? Enumerable.Empty(); - var multiTitleOrProcess = Split(titleOrProcess) ?? Enumerable.Empty(); + public bool Close(string? title, string? process, string? titleOrProcess, string? exclude, bool all = false) + { + return all + ? CheckMultiLineAndThen(title, process, titleOrProcess, exclude, FindAndCloseAll) + : FindAndClose(title, process, titleOrProcess, exclude); + } - var count = 0; - count += multiTitle.Count(t => fn(t, process, titleOrProcess, exclude)); - count += multiProcess.Count(p => fn(title, p, titleOrProcess, exclude)); - count += multiTitleOrProcess.Count(tp => fn(title, process, tp, exclude)); + private bool CheckMultiLineAndThen(string? title, string? process, string? titleOrProcess, string? exclude, Func fn) + { + var multiTitle = Split(title) ?? Enumerable.Empty(); + var multiProcess = Split(process) ?? Enumerable.Empty(); + var multiTitleOrProcess = Split(titleOrProcess) ?? Enumerable.Empty(); - return count > 0 || fn(title, process, titleOrProcess, exclude); - } + var count = 0; + count += multiTitle.Count(t => fn(t, process, titleOrProcess, exclude)); + count += multiProcess.Count(p => fn(title, p, titleOrProcess, exclude)); + count += multiTitleOrProcess.Count(tp => fn(title, process, tp, exclude)); - private IEnumerable? Split(string? titleOrProcess) - { - return titleOrProcess != null - ? titleOrProcess.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) - : null; - } + return count > 0 || fn(title, process, titleOrProcess, exclude); + } - private bool FindAndSwitchTo(string? title, string? process, string? titleOrProcess, string? exclude) - { - return FindAndThen(title, process, titleOrProcess, exclude, SwitchTo); - } + private IEnumerable? Split(string? titleOrProcess) + { + return titleOrProcess != null + ? titleOrProcess.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) + : null; + } - private bool FindAndMinimize(string? title, string? process, string? titleOrProcess, string? exclude) - { - return FindAndThen(title, process, titleOrProcess, exclude, Minimize); - } + private bool FindAndSwitchTo(string? title, string? process, string? titleOrProcess, string? exclude) + { + return FindAndThen(title, process, titleOrProcess, exclude, SwitchTo); + } - private bool FindAndMinimizeAll(string? title, string? process, string? titleOrProcess, string? exclude) - { - return FindAllAndThen(title, process, titleOrProcess, exclude, Minimize); - } + private bool FindAndMinimize(string? title, string? process, string? titleOrProcess, string? exclude) + { + return FindAndThen(title, process, titleOrProcess, exclude, Minimize); + } - private bool FindAndMaximize(string? title, string? process, string? titleOrProcess, string? exclude) - { - return FindAndThen(title, process, titleOrProcess, exclude, hwnd => Maximize(hwnd) && SwitchTo(hwnd)); - } + private bool FindAndMinimizeAll(string? title, string? process, string? titleOrProcess, string? exclude) + { + return FindAllAndThen(title, process, titleOrProcess, exclude, Minimize); + } - private bool FindAndMaximizeAll(string? title, string? process, string? titleOrProcess, string? exclude) - { - return FindAllAndThen(title, process, titleOrProcess, exclude, Maximize); - } + private bool FindAndMaximize(string? title, string? process, string? titleOrProcess, string? exclude) + { + return FindAndThen(title, process, titleOrProcess, exclude, hwnd => Maximize(hwnd) && SwitchTo(hwnd)); + } - private bool FindAndRestore(string? title, string? process, string? titleOrProcess, string? exclude) - { - return FindAndThen(title, process, titleOrProcess, exclude, Restore); - } + private bool FindAndMaximizeAll(string? title, string? process, string? titleOrProcess, string? exclude) + { + return FindAllAndThen(title, process, titleOrProcess, exclude, Maximize); + } - private bool FindAndRestoreAll(string? title, string? process, string? titleOrProcess, string? exclude) - { - return FindAllAndThen(title, process, titleOrProcess, exclude, Restore); - } + private bool FindAndRestore(string? title, string? process, string? titleOrProcess, string? exclude) + { + return FindAndThen(title, process, titleOrProcess, exclude, Restore); + } - private bool FindAndClose(string? title, string? process, string? titleOrProcess, string? exclude) - { - return FindAndThen(title, process, titleOrProcess, exclude, Close); - } + private bool FindAndRestoreAll(string? title, string? process, string? titleOrProcess, string? exclude) + { + return FindAllAndThen(title, process, titleOrProcess, exclude, Restore); + } - private bool FindAndCloseAll(string? title, string? process, string? titleOrProcess, string? exclude) - { - return FindAllAndThen(title, process, titleOrProcess, exclude, Close); - } + private bool FindAndClose(string? title, string? process, string? titleOrProcess, string? exclude) + { + return FindAndThen(title, process, titleOrProcess, exclude, Close); + } - private static bool FindAndThen(string? title, string? process, string? titleOrProcess, string? exclude, Func fn) - { - var hwnd = WindowHelpers.FindByTitleAndProcess(titleOrProcess, title, process, exclude); - return hwnd != IntPtr.Zero && fn(hwnd); - } + private bool FindAndCloseAll(string? title, string? process, string? titleOrProcess, string? exclude) + { + return FindAllAndThen(title, process, titleOrProcess, exclude, Close); + } - private static bool FindAllAndThen(string? title, string? process, string? titleOrProcess, string? exclude, Func fn) - { - var hwnds = WindowHelpers.FindAllByTitleAndProcess(titleOrProcess, title, process, exclude); - return hwnds.All(hwnd => hwnd != IntPtr.Zero && fn(hwnd)); - } + private static bool FindAndThen(string? title, string? process, string? titleOrProcess, string? exclude, Func fn) + { + var hwnd = WindowHelpers.FindByTitleAndProcess(titleOrProcess, title, process, exclude); + return hwnd != IntPtr.Zero && fn(hwnd); + } - private bool SwitchTo(IntPtr hwnd) - { - if (hwnd != IntPtr.Zero) + private static bool FindAllAndThen(string? title, string? process, string? titleOrProcess, string? exclude, Func fn) { - WindowHelpers.SetForegroundWindow(hwnd); - SendEmptyKeys(); + var hwnds = WindowHelpers.FindAllByTitleAndProcess(titleOrProcess, title, process, exclude); + return hwnds.All(hwnd => hwnd != IntPtr.Zero && fn(hwnd)); + } - var wp = new WindowHelpers.WINDOWPLACEMENT(); - WindowHelpers.GetWindowPlacement(hwnd, ref wp); - if (wp.ShowCmd == WindowHelpers.ShowWindowCommands.ShowMinimized) + private bool SwitchTo(IntPtr hwnd) + { + if (hwnd != IntPtr.Zero) { - WindowHelpers.ShowWindow(hwnd, WindowHelpers.ShowWindowCommands.Restore); - } + WindowHelpers.SetForegroundWindow(hwnd); + SendEmptyKeys(); - for (var stop = DateTime.UtcNow.AddMilliseconds(5000); DateTime.UtcNow < stop; Thread.Sleep(100)) - { - if (WindowHelpers.GetForegroundWindow() == hwnd) + var wp = new WindowHelpers.WINDOWPLACEMENT(); + WindowHelpers.GetWindowPlacement(hwnd, ref wp); + if (wp.ShowCmd == WindowHelpers.ShowWindowCommands.ShowMinimized) + { + WindowHelpers.ShowWindow(hwnd, WindowHelpers.ShowWindowCommands.Restore); + } + + for (var stop = DateTime.UtcNow.AddMilliseconds(5000); DateTime.UtcNow < stop; Thread.Sleep(100)) { - return true; + if (WindowHelpers.GetForegroundWindow() == hwnd) + { + return true; + } } } + return false; } - return false; - } - private bool Minimize(IntPtr hwnd) - { - return WindowHelpers.Minimize(hwnd); - } + private bool Minimize(IntPtr hwnd) + { + return WindowHelpers.Minimize(hwnd); + } - private bool Maximize(IntPtr hwnd) - { - return WindowHelpers.Maximize(hwnd); - } + private bool Maximize(IntPtr hwnd) + { + return WindowHelpers.Maximize(hwnd); + } - private bool Restore(IntPtr hwnd) - { - SendEmptyKeys(); - return WindowHelpers.Restore(hwnd); - } + private bool Restore(IntPtr hwnd) + { + SendEmptyKeys(); + return WindowHelpers.Restore(hwnd); + } - private bool Close(IntPtr hwnd) - { - return WindowHelpers.Close(hwnd); - } + private bool Close(IntPtr hwnd) + { + return WindowHelpers.Close(hwnd); + } - private void SendEmptyKeys() - { - _sendKeys?.SendKeys("{vk 0}", 1); - } + private void SendEmptyKeys() + { + _sendKeys?.SendKeys("{vk 0}", 1); + } - private readonly IServiceProvider _serviceProvider; - private ISendKeysService? _sendKeys; -} + private readonly IServiceProvider _serviceProvider; + private ISendKeysService? _sendKeys; + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/SpeakingState.cs b/src/cs/CommandSystemServices/SpeakingState.cs index 3ce96d2a..920a7f00 100644 --- a/src/cs/CommandSystemServices/SpeakingState.cs +++ b/src/cs/CommandSystemServices/SpeakingState.cs @@ -1,7 +1,9 @@ -namespace macaroni; - -public enum SpeakingState +namespace macaroni { - Off = 0, - On = 1 -} + + public enum SpeakingState + { + Off = 0, + On = 1 + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/SpeechConfigService.cs b/src/cs/CommandSystemServices/SpeechConfigService.cs index 0248963e..9c4b9614 100644 --- a/src/cs/CommandSystemServices/SpeechConfigService.cs +++ b/src/cs/CommandSystemServices/SpeechConfigService.cs @@ -1,92 +1,94 @@ -using Microsoft.CognitiveServices.Speech; -using Microsoft.CognitiveServices.Speech.Intent; +using System; +using System.Linq; +using Microsoft.CognitiveServices.Speech; using Microsoft.Extensions.DependencyInjection; -namespace macaroni; - -internal class SpeechConfigService : ISpeechConfigService +namespace macaroni { - public SpeechConfigService(IServiceProvider services, ISystemContext context) + internal class SpeechConfigService : ISpeechConfigService { - _serviceProvider = services; - _settings = _serviceProvider.GetRequiredService(); - } + public SpeechConfigService(IServiceProvider services, ISystemContext context) + { + _serviceProvider = services; + _settings = _serviceProvider.GetRequiredService(); + } - public string GetDefaultLanguage() - { - var defaultDefault = _settings.Get("DEFAULT_LANGUAGE", null) ?? "en-US"; - var defaultLanguage = _settings.Get("SPEECH_DEFAULT_LANGUAGE", defaultDefault); + public string GetDefaultLanguage() + { + var defaultDefault = _settings.Get("DEFAULT_LANGUAGE", null) ?? "en-US"; + var defaultLanguage = _settings.Get("SPEECH_DEFAULT_LANGUAGE", defaultDefault); - if (string.IsNullOrEmpty(defaultLanguage)) defaultLanguage = defaultDefault; + if (string.IsNullOrEmpty(defaultLanguage)) defaultLanguage = defaultDefault; - return defaultLanguage!.Trim('\r', '\n', ' '); - } + return defaultLanguage!.Trim('\r', '\n', ' '); + } - public SpeechConfig GetSpeechConfig(SpeechConfigKind kind) - { - var key = _settings.Get("SPEECH_KEY")?.Trim(); - var region = _settings.Get("SPEECH_REGION", string.Empty)?.Trim(); - var endpoint = kind == SpeechConfigKind.SpeechRecognition - ? _settings.Get("SPEECH_RECOGNITION_ENDPOINT", string.Empty)?.Trim() - : _settings.Get("SPEECH_SYNTHESIS_ENDPOINT", string.Empty)?.Trim(); + public SpeechConfig GetSpeechConfig(SpeechConfigKind kind) + { + var key = _settings.Get("SPEECH_KEY")?.Trim(); + var region = _settings.Get("SPEECH_REGION", string.Empty)?.Trim(); + var endpoint = kind == SpeechConfigKind.SpeechRecognition + ? _settings.Get("SPEECH_RECOGNITION_ENDPOINT", string.Empty)?.Trim() + : _settings.Get("SPEECH_SYNTHESIS_ENDPOINT", string.Empty)?.Trim(); - var config = !string.IsNullOrEmpty(endpoint) - ? SpeechConfig.FromEndpoint(new Uri(endpoint), key) - : SpeechConfig.FromSubscription(key, region); + var config = !string.IsNullOrEmpty(endpoint) + ? SpeechConfig.FromEndpoint(new Uri(endpoint), key) + : SpeechConfig.FromSubscription(key, region); - config.SetProperty(PropertyId.Speech_SegmentationSilenceTimeoutMs, GetSegmentationTimeout()); + config.SetProperty(PropertyId.Speech_SegmentationSilenceTimeoutMs, GetSegmentationTimeout()); - var endpointId = kind == SpeechConfigKind.SpeechRecognition - ? _settings.Get("SPEECH_CUSTOM_RECOGNITION_ENDPOINT_ID", string.Empty) - : _settings.Get("SPEECH_CUSTOM_SYNTHESIS_ENDPOINT_ID", string.Empty); - if (!string.IsNullOrEmpty(endpointId)) config.EndpointId = endpointId; + var endpointId = kind == SpeechConfigKind.SpeechRecognition + ? _settings.Get("SPEECH_CUSTOM_RECOGNITION_ENDPOINT_ID", string.Empty) + : _settings.Get("SPEECH_CUSTOM_SYNTHESIS_ENDPOINT_ID", string.Empty); + if (!string.IsNullOrEmpty(endpointId)) config.EndpointId = endpointId; - var language = GetDefaultLanguage(); - if (language != null && kind == SpeechConfigKind.SpeechRecognition) config.SpeechRecognitionLanguage = language; + var language = GetDefaultLanguage(); + if (language != null && kind == SpeechConfigKind.SpeechRecognition) config.SpeechRecognitionLanguage = language; - return config; - } + return config; + } - public EmbeddedSpeechConfig? GetEmbeddedSpeechConfig() - { - string?[] embeddedPaths = { + public EmbeddedSpeechConfig? GetEmbeddedSpeechConfig() + { + string?[] embeddedPaths = { _settings.Get("EMBEDDED_SPEECH_RECOGNITION_MODEL_PATH", ""), _settings.Get("EMBEDDED_SPEECH_SYNTHESIS_VOICE_PATH", "") }; - var pathsOk = embeddedPaths.All(x => !string.IsNullOrEmpty(x)); - if (pathsOk) - { - var modelName = _settings.Get("EMBEDDED_SPEECH_RECOGNITION_MODEL_NAME", ""); - var modelKey = _settings.Get("EMBEDDED_SPEECH_RECOGNITION_MODEL_KEY", ""); - var voiceName = _settings.Get("EMBEDDED_SPEECH_SYNTHESIS_VOICE_NAME", ""); - var voiceKey = _settings.Get("EMBEDDED_SPEECH_SYNTHESIS_VOICE_KEY", ""); - - if (!string.IsNullOrEmpty(modelName) && !string.IsNullOrEmpty(voiceName)) + var pathsOk = embeddedPaths.All(x => !string.IsNullOrEmpty(x)); + if (pathsOk) { - var config = EmbeddedSpeechConfig.FromPaths(embeddedPaths); - config.SetSpeechRecognitionModel(modelName, modelKey); - config.SetSpeechSynthesisVoice(voiceName, voiceKey); - config.SetProperty(PropertyId.Speech_SegmentationSilenceTimeoutMs, GetSegmentationTimeout()); - config.SetProperty("EmbeddedSpeech-DisableTelemetry", "true"); + var modelName = _settings.Get("EMBEDDED_SPEECH_RECOGNITION_MODEL_NAME", ""); + var modelKey = _settings.Get("EMBEDDED_SPEECH_RECOGNITION_MODEL_KEY", ""); + var voiceName = _settings.Get("EMBEDDED_SPEECH_SYNTHESIS_VOICE_NAME", ""); + var voiceKey = _settings.Get("EMBEDDED_SPEECH_SYNTHESIS_VOICE_KEY", ""); - if (voiceName.Contains("Neural")) + if (!string.IsNullOrEmpty(modelName) && !string.IsNullOrEmpty(voiceName)) { - config.SetSpeechSynthesisOutputFormat(SpeechSynthesisOutputFormat.Riff24Khz16BitMonoPcm); + var config = EmbeddedSpeechConfig.FromPaths(embeddedPaths); + config.SetSpeechRecognitionModel(modelName, modelKey); + config.SetSpeechSynthesisVoice(voiceName, voiceKey); + config.SetProperty(PropertyId.Speech_SegmentationSilenceTimeoutMs, GetSegmentationTimeout()); + config.SetProperty("EmbeddedSpeech-DisableTelemetry", "true"); + + if (voiceName.Contains("Neural")) + { + config.SetSpeechSynthesisOutputFormat(SpeechSynthesisOutputFormat.Riff24Khz16BitMonoPcm); + } + + return config; } - - return config; } + + return null; } - return null; - } + private string? GetSegmentationTimeout() + { + return _settings.Get("SPEECH_SEGMENTATION_TIMEOUT", "500"); + } - private string? GetSegmentationTimeout() - { - return _settings.Get("SPEECH_SEGMENTATION_TIMEOUT", "500"); + private readonly IServiceProvider _serviceProvider; + private readonly ICommandSystemSettings _settings; } - - private readonly IServiceProvider _serviceProvider; - private readonly ICommandSystemSettings _settings; -} +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/SpeechSynthesisService.cs b/src/cs/CommandSystemServices/SpeechSynthesisService.cs index c1aa631c..a4caf98d 100644 --- a/src/cs/CommandSystemServices/SpeechSynthesisService.cs +++ b/src/cs/CommandSystemServices/SpeechSynthesisService.cs @@ -1,345 +1,349 @@ -using Microsoft.CognitiveServices.Speech; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.CognitiveServices.Speech; using Microsoft.CognitiveServices.Speech.Audio; using Microsoft.Extensions.DependencyInjection; -using System; -using System.Diagnostics; -namespace macaroni; - -internal class SpeechSynthesisService : ISynthesisService +namespace macaroni { - public SpeechSynthesisService(IServiceProvider services, IBroadcastMessageService broadcastMessageService, IOnScreenDisplayService osd) - { - _serviceProvider = services; - _broadcastMessageService = broadcastMessageService; - _osd = osd; - } - public Task SpeakText(string text, string? voice, string? output, string? bargeIn) + internal class SpeechSynthesisService : ISynthesisService { - var info = GetVoiceInfo(voice); - if (!string.IsNullOrEmpty(info?.ShortName)) voice = info?.ShortName; - - var interactive = string.IsNullOrEmpty(output); - if (interactive) BroadcastSpeakingStateChanged(SpeakingState.On); - - var offline = info?.VoiceType == SynthesisVoiceType.OfflineStandard || info?.VoiceType == SynthesisVoiceType.OfflineNeural; - var speakTextWithSsml = offline && !string.IsNullOrEmpty(voice); - - var stashed = SetBargeInState(bargeIn); - - lock (this) + public SpeechSynthesisService(IServiceProvider services, IBroadcastMessageService broadcastMessageService, IOnScreenDisplayService osd) { - var name = EnsureSynthesizer(voice, output)?.Name; - MR.DBG_TRACE_VERBOSE($"SpeakText w/ voice={name}"); - - if (interactive) _osd?.DisplayText(text, "TTS"); - - var speak = speakTextWithSsml - ? _synthesizer!.SpeakSsmlAsync(ConvertTextToSsml(text, voice)) - : _synthesizer!.SpeakTextAsync(text); - - return WrapInProgress(interactive, stashed, DateTime.Now, speak).Task; + _serviceProvider = services; + _broadcastMessageService = broadcastMessageService; + _osd = osd; } - } - private string ConvertTextToSsml(string text, string? voice = null) - { - return !string.IsNullOrEmpty(voice) - ? ConvertTextToSsmlWithVoice(text, voice) - : ConvertTextToSsmlWithoutVoice(text); - } + public Task SpeakText(string text, string? voice, string? output, string? bargeIn) + { + var info = GetVoiceInfo(voice); + if (!string.IsNullOrEmpty(info?.ShortName)) voice = info?.ShortName; - private string ConvertTextToSsmlWithVoice(string text, string voice) - { - return "" + - $"" + - $" " + - text + - $" " + - " " + - "" + - ""; - } + var interactive = string.IsNullOrEmpty(output); + if (interactive) BroadcastSpeakingStateChanged(SpeakingState.On); - private string ConvertTextToSsmlWithoutVoice(string text) - { - return "" + - $"" + - $" " + - text + - $" " + - " " + - "" + - ""; - } + var offline = info?.VoiceType == SynthesisVoiceType.OfflineStandard || info?.VoiceType == SynthesisVoiceType.OfflineNeural; + var speakTextWithSsml = offline && !string.IsNullOrEmpty(voice); - public Task SpeakSsml(string ssml, string? voice, string? output, string? bargeIn) - { - voice = EnsureSynthesizer(voice, output)?.Name; - MR.DBG_TRACE_VERBOSE($"SpeakSsml w/ voice={voice}"); + var stashed = SetBargeInState(bargeIn); - if (_synthesizer == null) throw new ArgumentException("synthesizer null"); + lock (this) + { + var name = EnsureSynthesizer(voice, output)?.Name; + MR.DBG_TRACE_VERBOSE($"SpeakText w/ voice={name}"); - var interactive = string.IsNullOrEmpty(output); - if (interactive) BroadcastSpeakingStateChanged(SpeakingState.On); + if (interactive) _osd?.DisplayText(text, "TTS"); - var stashed = SetBargeInState(bargeIn); + var speak = speakTextWithSsml + ? _synthesizer!.SpeakSsmlAsync(ConvertTextToSsml(text, voice)) + : _synthesizer!.SpeakTextAsync(text); - lock (this) - { - var speak = _synthesizer.SpeakSsmlAsync(ssml); - return WrapInProgress(interactive, stashed, DateTime.Now, speak).Task; + return WrapInProgress(interactive, stashed, DateTime.Now, speak).Task; + } } - } - - public Task StopSpeaking() - { - _stopped = DateTime.Now; - MR.DBG_TRACE_INFO($"StopSpeaking at {_stopped}"); - lock (this) + private string ConvertTextToSsml(string text, string? voice = null) { - return _synthesizer?.StopSpeakingAsync() ?? Task.CompletedTask; + return !string.IsNullOrEmpty(voice) + ? ConvertTextToSsmlWithVoice(text, voice) + : ConvertTextToSsmlWithoutVoice(text); } - } - - private UInt64 SetBargeInState(string? bargeIn) - { - EnsureInitIntentRecognizerService(); - if (_intentService != null) + private string ConvertTextToSsmlWithVoice(string text, string voice) { - var bargeInState = bargeIn == "no-barge-in" - ? _intentService.GetState() - : !string.IsNullOrEmpty(bargeIn) - ? ListeningStateHelpers.Parse(bargeIn) - : _intentService.GetDefaultState(); - return _intentService.SetState(bargeInState); + return "" + + $"" + + $" " + + text + + $" " + + " " + + "" + + ""; } - return 0; - } - - private VoiceInfo? EnsureSynthesizer(string? voice, string? output) - { - var info = GetVoiceInfo(voice); - var voiceNameMatches = _voiceInfo?.Name == voice || _voiceInfo?.ShortName == voice; - if (_synthesizer == null || voice == null || !voiceNameMatches || _synthesizerOutput != output) + private string ConvertTextToSsmlWithoutVoice(string text) { - StopSpeaking().Wait(100); + return "" + + $"" + + $" " + + text + + $" " + + " " + + "" + + ""; + } - _voiceInfo = info; - _synthesizerOutput = output; + public Task SpeakSsml(string ssml, string? voice, string? output, string? bargeIn) + { + voice = EnsureSynthesizer(voice, output)?.Name; + MR.DBG_TRACE_VERBOSE($"SpeakSsml w/ voice={voice}"); - _synthesizer = CreateSpeechSynthesizer(); - EnsureInitIntentRecognizerService(); - } + if (_synthesizer == null) throw new ArgumentException("synthesizer null"); - return _voiceInfo; - } + var interactive = string.IsNullOrEmpty(output); + if (interactive) BroadcastSpeakingStateChanged(SpeakingState.On); - private void EnsureInitIntentRecognizerService() - { - _intentService = _serviceProvider.GetService(); - } + var stashed = SetBargeInState(bargeIn); - private SpeechSynthesizer CreateSpeechSynthesizer() - { - var audio = GetAudioConfig(_synthesizerOutput); + lock (this) + { + var speak = _synthesizer.SpeakSsmlAsync(ssml); + return WrapInProgress(interactive, stashed, DateTime.Now, speak).Task; + } + } - var embeddedConfig = GetEmbeddedSpeechConfig(); - if (embeddedConfig != null) + public Task StopSpeaking() { - try + _stopped = DateTime.Now; + MR.DBG_TRACE_INFO($"StopSpeaking at {_stopped}"); + + lock (this) { - return new SpeechSynthesizer(embeddedConfig, audio); + return _synthesizer?.StopSpeakingAsync() ?? Task.CompletedTask; } - catch (Exception) + } + + private UInt64 SetBargeInState(string? bargeIn) + { + EnsureInitIntentRecognizerService(); + + if (_intentService != null) { - MR.DBG_TRACE_ERROR("Failed to create embedded SpeechSynthesizer"); + var bargeInState = bargeIn == "no-barge-in" + ? _intentService.GetState() + : !string.IsNullOrEmpty(bargeIn) + ? ListeningStateHelpers.Parse(bargeIn) + : _intentService.GetDefaultState(); + return _intentService.SetState(bargeInState); } + + return 0; } - return new SpeechSynthesizer(GetSpeechConfig(_voiceInfo?.Name), audio); - } + private VoiceInfo? EnsureSynthesizer(string? voice, string? output) + { + var info = GetVoiceInfo(voice); + var voiceNameMatches = _voiceInfo?.Name == voice || _voiceInfo?.ShortName == voice; + if (_synthesizer == null || voice == null || !voiceNameMatches || _synthesizerOutput != output) + { + StopSpeaking().Wait(100); - private string GetDefaultLanguage() - { - var service = _serviceProvider.GetRequiredService(); - return service.GetDefaultLanguage(); - } + _voiceInfo = info; + _synthesizerOutput = output; - private SpeechConfig GetSpeechConfig(string? voice) - { - var service = _serviceProvider.GetRequiredService(); - var config = service.GetSpeechConfig(SpeechConfigKind.SpeechSynthesis); + _synthesizer = CreateSpeechSynthesizer(); + EnsureInitIntentRecognizerService(); + } + + return _voiceInfo; + } - if (!string.IsNullOrEmpty(voice)) + private void EnsureInitIntentRecognizerService() { - config.SpeechSynthesisVoiceName = voice; + _intentService = _serviceProvider.GetService(); } - return config; - } + private SpeechSynthesizer CreateSpeechSynthesizer() + { + var audio = GetAudioConfig(_synthesizerOutput); - private EmbeddedSpeechConfig? GetEmbeddedSpeechConfig() - { - var service = _serviceProvider.GetRequiredService(); - return service.GetEmbeddedSpeechConfig(); - } + var embeddedConfig = GetEmbeddedSpeechConfig(); + if (embeddedConfig != null) + { + try + { + return new SpeechSynthesizer(embeddedConfig, audio); + } + catch (Exception) + { + MR.DBG_TRACE_ERROR("Failed to create embedded SpeechSynthesizer"); + } + } - private void EnsureVoiceList() - { - lock (this) + return new SpeechSynthesizer(GetSpeechConfig(_voiceInfo?.Name), audio); + } + + private string GetDefaultLanguage() { - if (_voices == null) - { - var service = _serviceProvider.GetRequiredService(); + var service = _serviceProvider.GetRequiredService(); + return service.GetDefaultLanguage(); + } - var voices = new List(); - _embedded = GetEmbeddedVoices(service, voices); - _online = GetOnlineVoices(service, voices); + private SpeechConfig GetSpeechConfig(string? voice) + { + var service = _serviceProvider.GetRequiredService(); + var config = service.GetSpeechConfig(SpeechConfigKind.SpeechSynthesis); - _voices = voices; + if (!string.IsNullOrEmpty(voice)) + { + config.SpeechSynthesisVoiceName = voice; } + + return config; } - } - private static bool GetEmbeddedVoices(ISpeechConfigService service, List voices) - { - try + private EmbeddedSpeechConfig? GetEmbeddedSpeechConfig() { - var embedded = service.GetEmbeddedSpeechConfig(); - if (embedded != null) + var service = _serviceProvider.GetRequiredService(); + return service.GetEmbeddedSpeechConfig(); + } + + private void EnsureVoiceList() + { + lock (this) { - var synthesizer = new SpeechSynthesizer(embedded); - var task = synthesizer.GetVoicesAsync(); - task.Wait(); - voices.AddRange(task.Result.Voices); - return task.Result.Voices.Count > 0; + if (_voices == null) + { + var service = _serviceProvider.GetRequiredService(); + + var voices = new List(); + _embedded = GetEmbeddedVoices(service, voices); + _online = GetOnlineVoices(service, voices); + + _voices = voices; + } } } - catch (Exception ex) + + private static bool GetEmbeddedVoices(ISpeechConfigService service, List voices) { - MR.DBG_TRACE_ERROR($"Couldn't get embedded voice list\nEXCEPTION: {ex}"); + try + { + var embedded = service.GetEmbeddedSpeechConfig(); + if (embedded != null) + { + var synthesizer = new SpeechSynthesizer(embedded); + var task = synthesizer.GetVoicesAsync(); + task.Wait(); + voices.AddRange(task.Result.Voices); + return task.Result.Voices.Count > 0; + } + } + catch (Exception ex) + { + MR.DBG_TRACE_ERROR($"Couldn't get embedded voice list\nEXCEPTION: {ex}"); + } + return false; } - return false; - } - private static bool GetOnlineVoices(ISpeechConfigService service, List voices) - { - try + private static bool GetOnlineVoices(ISpeechConfigService service, List voices) { - var online = service.GetSpeechConfig(SpeechConfigKind.SpeechSynthesis); - if (online != null) + try + { + var online = service.GetSpeechConfig(SpeechConfigKind.SpeechSynthesis); + if (online != null) + { + var synthesizer = new SpeechSynthesizer(online); + var task = synthesizer.GetVoicesAsync(); + task.Wait(); + voices.AddRange(task.Result.Voices); + return task.Result.Voices.Count > 0; + } + } + catch (Exception ex) { - var synthesizer = new SpeechSynthesizer(online); - var task = synthesizer.GetVoicesAsync(); - task.Wait(); - voices.AddRange(task.Result.Voices); - return task.Result.Voices.Count > 0; + MR.DBG_TRACE_ERROR($"Couldn't get online voice list\nEXCEPTION: {ex}"); } + return false; } - catch (Exception ex) + + private VoiceInfo? GetVoiceInfo(string? voiceOrLanguage) { - MR.DBG_TRACE_ERROR($"Couldn't get online voice list\nEXCEPTION: {ex}"); - } - return false; - } + EnsureVoiceList(); + if (voiceOrLanguage == null && _embedded) return _voices?.First(); - private VoiceInfo? GetVoiceInfo(string? voiceOrLanguage) - { - EnsureVoiceList(); - if (voiceOrLanguage == null && _embedded) return _voices?.First(); + voiceOrLanguage = voiceOrLanguage ?? GetDefaultLanguage(); - voiceOrLanguage = voiceOrLanguage ?? GetDefaultLanguage(); + var voice = _voices?.FirstOrDefault(x => x.Name == voiceOrLanguage || x.ShortName == voiceOrLanguage || x.LocalName == voiceOrLanguage); + if (voice != null) return voice; - var voice = _voices?.FirstOrDefault(x => x.Name == voiceOrLanguage || x.ShortName == voiceOrLanguage || x.LocalName == voiceOrLanguage); - if (voice != null) return voice; + voice = _voices?.FirstOrDefault(x => x.Locale == voiceOrLanguage); + if (voice != null) return voice; - voice = _voices?.FirstOrDefault(x => x.Locale == voiceOrLanguage); - if (voice != null) return voice; + if (!voiceOrLanguage.Contains('-') && voiceOrLanguage.Length <= 3) + { + var check = $"{voiceOrLanguage}-{voiceOrLanguage.ToUpper()}"; - if (!voiceOrLanguage.Contains('-') && voiceOrLanguage.Length <= 3) - { - var check = $"{voiceOrLanguage}-{voiceOrLanguage.ToUpper()}"; + voice = _voices?.FirstOrDefault(x => x.Locale == check); + if (voice != null) return voice; + } - voice = _voices?.FirstOrDefault(x => x.Locale == check); + voice = _voices?.FirstOrDefault(x => x.ShortName.StartsWith(voiceOrLanguage)); if (voice != null) return voice; - } - - voice = _voices?.FirstOrDefault(x => x.ShortName.StartsWith(voiceOrLanguage)); - if (voice != null) return voice; - return null; - } + return null; + } - private AudioConfig GetAudioConfig(string? output) - { - return string.IsNullOrEmpty(output) - ? AudioConfig.FromDefaultSpeakerOutput() - : AudioConfig.FromWavFileOutput(output); - } + private AudioConfig GetAudioConfig(string? output) + { + return string.IsNullOrEmpty(output) + ? AudioConfig.FromDefaultSpeakerOutput() + : AudioConfig.FromWavFileOutput(output); + } - private TaskCompletionSource WrapInProgress(bool interactive, ulong stashed, DateTime started, Task task) - { - MR.DBG_TRACE_VERBOSE($"WrapInProgress... {started}"); - var tcs = NewInProgress(); - task.ContinueWith(task => + private TaskCompletionSource WrapInProgress(bool interactive, ulong stashed, DateTime started, Task task) { - RemoveInProgress(tcs); - tcs.SetResult(_stopped < started - ? task.Result - : null); + MR.DBG_TRACE_VERBOSE($"WrapInProgress... {started}"); + var tcs = NewInProgress(); + task.ContinueWith(task => + { + RemoveInProgress(tcs); + tcs.SetResult(_stopped < started + ? task.Result + : null); - _intentService!.RestoreState(stashed); - MR.DBG_TRACE_VERBOSE($"WrapInProgress... {started} ... Completed at {DateTime.Now}!"); + _intentService!.RestoreState(stashed); + MR.DBG_TRACE_VERBOSE($"WrapInProgress... {started} ... Completed at {DateTime.Now}!"); - if (interactive) BroadcastSpeakingStateChanged(SpeakingState.Off); + if (interactive) BroadcastSpeakingStateChanged(SpeakingState.Off); - return task.Result; - }); - return tcs; - } + return task.Result; + }); + return tcs; + } - private TaskCompletionSource NewInProgress() - { - var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - lock (this) + private TaskCompletionSource NewInProgress() { - _inProgress.Add(tcs); + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + lock (this) + { + _inProgress.Add(tcs); + } + return tcs; } - return tcs; - } - private void RemoveInProgress(TaskCompletionSource tcs) - { - lock (this) + private void RemoveInProgress(TaskCompletionSource tcs) { - _inProgress.Remove(tcs); + lock (this) + { + _inProgress.Remove(tcs); + } } - } - private void BroadcastSpeakingStateChanged(SpeakingState state) - { - _broadcastMessageService.BroadcastMessage("synthesizer.state.changed", state.ToString(), null); - } + private void BroadcastSpeakingStateChanged(SpeakingState state) + { + _broadcastMessageService.BroadcastMessage("synthesizer.state.changed", state.ToString(), null); + } - private DateTime _stopped = DateTime.MinValue; - private List> _inProgress = new(); + private DateTime _stopped = DateTime.MinValue; + private List> _inProgress = new List>(); - private const int _defaultIncreaseSpeakingRate = 5; - private readonly IServiceProvider _serviceProvider; - private readonly IBroadcastMessageService _broadcastMessageService; - private readonly IOnScreenDisplayService _osd; - private IIntentRecognizerService? _intentService; + private const int _defaultIncreaseSpeakingRate = 5; + private readonly IServiceProvider _serviceProvider; + private readonly IBroadcastMessageService _broadcastMessageService; + private readonly IOnScreenDisplayService _osd; + private IIntentRecognizerService? _intentService; - private SpeechSynthesizer? _synthesizer; - private string? _synthesizerOutput; + private SpeechSynthesizer? _synthesizer; + private string? _synthesizerOutput; - private VoiceInfo? _voiceInfo; - private IEnumerable? _voices; - private bool _online = false; - private bool _embedded = false; -} + private VoiceInfo? _voiceInfo; + private IEnumerable? _voices; + private bool _online = false; + private bool _embedded = false; + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/StartStopHelperBackgroundService.cs b/src/cs/CommandSystemServices/StartStopHelperBackgroundService.cs index 2b4e79b5..ac143b34 100644 --- a/src/cs/CommandSystemServices/StartStopHelperBackgroundService.cs +++ b/src/cs/CommandSystemServices/StartStopHelperBackgroundService.cs @@ -1,51 +1,57 @@ -namespace macaroni; +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Hosting; -public abstract class StartStopHelperBackgroundService : BackgroundService +namespace macaroni { - public StartStopHelperBackgroundService(IServiceProvider services) + public abstract class StartStopHelperBackgroundService : BackgroundService { - _services = services; - } - - public override Task StartAsync(CancellationToken cancellationToken) - { - if (_running) + public StartStopHelperBackgroundService(IServiceProvider services) { - return Task.CompletedTask; + _services = services; } - _running = true; + public override Task StartAsync(CancellationToken cancellationToken) + { + if (_running) + { + return Task.CompletedTask; + } - return Task.WhenAll( - this.StartAsync(), - base.StartAsync(cancellationToken) - ); - } + _running = true; - public override Task StopAsync(CancellationToken cancellationToken) - { - if (!_running) - { - return Task.CompletedTask; + return Task.WhenAll( + this.StartAsync(), + base.StartAsync(cancellationToken) + ); } - _running = false; + public override Task StopAsync(CancellationToken cancellationToken) + { + if (!_running) + { + return Task.CompletedTask; + } - return Task.WhenAll( - this.StopAsync(), - base.StopAsync(cancellationToken) - ); - } + _running = false; - abstract protected Task StartAsync(); + return Task.WhenAll( + this.StopAsync(), + base.StopAsync(cancellationToken) + ); + } - abstract protected Task StopAsync(); + abstract protected Task StartAsync(); - protected override Task ExecuteAsync(CancellationToken stoppingToken) - { - return Task.CompletedTask; - } + abstract protected Task StopAsync(); - protected readonly IServiceProvider _services; - private bool _running = false; -} + protected override Task ExecuteAsync(CancellationToken stoppingToken) + { + return Task.CompletedTask; + } + + protected readonly IServiceProvider _services; + private bool _running = false; + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/TimeIntervalService.cs b/src/cs/CommandSystemServices/TimeIntervalService.cs index d34db200..7479bdb8 100644 --- a/src/cs/CommandSystemServices/TimeIntervalService.cs +++ b/src/cs/CommandSystemServices/TimeIntervalService.cs @@ -1,122 +1,129 @@ +using System; using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; -namespace macaroni; - -internal class TimeIntervalService : ITimeIntervalService +namespace macaroni { - public int SetInterval(Action action, int milliseconds) - { - var id = GetNextId(); - var interval = MsToTicks(milliseconds); - return AddCallback(id, action, interval); - } - - public void ClearInterval(int intervalId) - { - RemoveCallback(intervalId); - } - - class CallbackAction + internal class TimeIntervalService : ITimeIntervalService { - public Action? Action; - public long Epoch; - public long Interval; - - public long TicksUntilExpired(long now) + public int SetInterval(Action action, int milliseconds) { - return Epoch + Interval - now; + var id = GetNextId(); + var interval = MsToTicks(milliseconds); + return AddCallback(id, action, interval); } - } - private int AddCallback(int id, Action action, long interval) - { - var callback = new CallbackAction() + public void ClearInterval(int intervalId) { - Action = action, - Interval = interval, - Epoch = GetNowTicks() - }; - _actions[id] = callback; - ResetInterval(); - return id; - } + RemoveCallback(intervalId); + } - private void RemoveCallback(int intervalId) - { - _actions.Remove(intervalId, out _); - } + class CallbackAction + { + public Action? Action; + public long Epoch; + public long Interval; + + public long TicksUntilExpired(long now) + { + return Epoch + Interval - now; + } + } - private void ResetInterval() - { - var now = GetNowTicks(); - var min = _actions.Values.Min(callback => callback.TicksUntilExpired(now)); - var delay = Math.Max(0, (int)TicksToMs(min)); + private int AddCallback(int id, Action action, long interval) + { + var callback = new CallbackAction() + { + Action = action, + Interval = interval, + Epoch = GetNowTicks() + }; + _actions[id] = callback; + ResetInterval(); + return id; + } - MR.DBG_TRACE_INFO($"Timer set for {delay} ms ..."); + private void RemoveCallback(int intervalId) + { + _actions.Remove(intervalId, out _); + } - SetInterval(delay); - } + private void ResetInterval() + { + var now = GetNowTicks(); + var min = _actions.Values.Min(callback => callback.TicksUntilExpired(now)); + var delay = Math.Max(0, (int)TicksToMs(min)); - private void SetInterval(int delay) - { - _timer ??= new(s => NotifyCallbacks()); - _timer!.Change(delay, Timeout.Infinite); - } + MR.DBG_TRACE_INFO($"Timer set for {delay} ms ..."); - private void NotifyCallbacks() - { - List expired; + SetInterval(delay); + } - lock (this) + private void SetInterval(int delay) { - var now = GetNowTicks(); - expired = _actions.Values - .Where(callback => callback.TicksUntilExpired(now) <= 0) - .ToList(); - expired.ForEach(callback => callback.Epoch = now); + _timer ??= new Timer(s => NotifyCallbacks()); + _timer!.Change(delay, Timeout.Infinite); } - expired.ForEach(callback => - Task.Run(() => { - MR.DBG_TRACE_INFO("Calling callback..."); - callback.Action?.Invoke(); - MR.DBG_TRACE_INFO("Calling callback... done!"); - })); - - if (expired.Count > 0) + private void NotifyCallbacks() { - ResetInterval(); + List expired; + + lock (this) + { + var now = GetNowTicks(); + expired = _actions.Values + .Where(callback => callback.TicksUntilExpired(now) <= 0) + .ToList(); + expired.ForEach(callback => callback.Epoch = now); + } + + expired.ForEach(callback => + Task.Run(() => + { + MR.DBG_TRACE_INFO("Calling callback..."); + callback.Action?.Invoke(); + MR.DBG_TRACE_INFO("Calling callback... done!"); + })); + + if (expired.Count > 0) + { + ResetInterval(); + } } - } - private static long GetNowTicks() - { - return DateTime.Now.Ticks; - } + private static long GetNowTicks() + { + return DateTime.Now.Ticks; + } - private static long TicksToMs(long ticks) - { - return ticks / TimeSpan.TicksPerMillisecond; - } + private static long TicksToMs(long ticks) + { + return ticks / TimeSpan.TicksPerMillisecond; + } - private static long MsToTicks(int ms) - { - return ms * TimeSpan.TicksPerMillisecond; - } + private static long MsToTicks(int ms) + { + return ms * TimeSpan.TicksPerMillisecond; + } - private int GetNextId() - { - int id = 0; - while (id == 0 || _actions.ContainsKey(id)) + private int GetNextId() { - id = Interlocked.Increment(ref _nextId); + int id = 0; + while (id == 0 || _actions.ContainsKey(id)) + { + id = Interlocked.Increment(ref _nextId); + } + return id; } - return id; - } - private ConcurrentDictionary _actions = new(); - private System.Threading.Timer? _timer; + private ConcurrentDictionary _actions = new ConcurrentDictionary(); + private System.Threading.Timer? _timer; - private int _nextId; -} + private int _nextId; + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/TranslatorConfigService.cs b/src/cs/CommandSystemServices/TranslatorConfigService.cs index 3be692df..2953ffae 100644 --- a/src/cs/CommandSystemServices/TranslatorConfigService.cs +++ b/src/cs/CommandSystemServices/TranslatorConfigService.cs @@ -1,23 +1,23 @@ -using Microsoft.CognitiveServices.Speech; -using Microsoft.CognitiveServices.Speech.Intent; +using System; using Microsoft.Extensions.DependencyInjection; -namespace macaroni; - -internal class TranslatorServiceConfig : ITranslatorServiceConfig +namespace macaroni { - public TranslatorServiceConfig(IServiceProvider services) + internal class TranslatorServiceConfig : ITranslatorServiceConfig { - _serviceProvider = services; - } + public TranslatorServiceConfig(IServiceProvider services) + { + _serviceProvider = services; + } - public void GetTranslatorConnectionInfo(out string? key, out string? endpoint, out string? region) - { - var settings = _serviceProvider.GetRequiredService(); - key = settings.Get("TRANSLATOR_KEY")?.Trim(); - endpoint = settings.Get("TRANSLATOR_ENDPOINT")?.Trim(); - region = settings.Get("TRANSLATOR_REGION")?.Trim(); - } + public void GetTranslatorConnectionInfo(out string? key, out string? endpoint, out string? region) + { + var settings = _serviceProvider.GetRequiredService(); + key = settings.Get("TRANSLATOR_KEY")?.Trim(); + endpoint = settings.Get("TRANSLATOR_ENDPOINT")?.Trim(); + region = settings.Get("TRANSLATOR_REGION")?.Trim(); + } - private readonly IServiceProvider _serviceProvider; -} + private readonly IServiceProvider _serviceProvider; + } +} \ No newline at end of file diff --git a/src/cs/CommandSystemServices/TranslatorService.cs b/src/cs/CommandSystemServices/TranslatorService.cs index f84b8339..fda051e8 100644 --- a/src/cs/CommandSystemServices/TranslatorService.cs +++ b/src/cs/CommandSystemServices/TranslatorService.cs @@ -1,157 +1,173 @@ -using Microsoft.CognitiveServices.Speech; -using Microsoft.CognitiveServices.Speech.Audio; +using System; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; -using System.Diagnostics; +using Newtonsoft.Json; +/* Unmerged change from project 'macaroni_core (net6.0-windows)' +Before: +using Newtonsoft.Json; +After: using System.Text; +*/ + +/* Unmerged change from project 'macaroni_core (netstandard2.1)' +Before: using Newtonsoft.Json; +After: +using System.Text; +*/ -namespace macaroni; -internal class TranslatorService : ITranslatorService +namespace macaroni { - public TranslatorService(IServiceProvider services) + internal class TranslatorService : ITranslatorService { - _serviceProvider = services; - } + public TranslatorService(IServiceProvider services) + { + _serviceProvider = services; + } - public string Translate(string text, string? from, string? to) - { - var task = Task.Run(async () => { - return await TranslateAsync(text, from, to); - }); - task.Wait(); - return task.Result; - } + public string Translate(string text, string? from, string? to) + { + var task = Task.Run(async () => + { + return await TranslateAsync(text, from, to); + }); + task.Wait(); + return task.Result; + } - public async Task TranslateAsync(string text, string? from, string? to) - { - using (var client = new HttpClient()) - using (var request = GetTranslateRequestMessage(from, to)) + public async Task TranslateAsync(string text, string? from, string? to) { - object[] body = new object[] { new { Text = text } }; - var requestBody = JsonConvert.SerializeObject(body); + using (var client = new HttpClient()) + using (var request = GetTranslateRequestMessage(from, to)) + { + object[] body = new object[] { new { Text = text } }; + var requestBody = JsonConvert.SerializeObject(body); - request.Content = new StringContent(requestBody, Encoding.UTF8, "application/json"); + request.Content = new StringContent(requestBody, Encoding.UTF8, "application/json"); - var response = await client.SendAsync(request); - var asString = await response.Content.ReadAsStringAsync(); - var result = JsonConvert.DeserializeObject(asString); + var response = await client.SendAsync(request); + var asString = await response.Content.ReadAsStringAsync(); + var result = JsonConvert.DeserializeObject(asString); - return result?[0].Translations?[0].Text ?? string.Empty; + return result?[0].Translations?[0].Text ?? string.Empty; + } } - } - private HttpRequestMessage GetTranslateRequestMessage(string? from, string? to) - { - var service = _serviceProvider.GetRequiredService(); - service.GetTranslatorConnectionInfo(out var key, out var endpoint, out var region); + private HttpRequestMessage GetTranslateRequestMessage(string? from, string? to) + { + var service = _serviceProvider.GetRequiredService(); + service.GetTranslatorConnectionInfo(out var key, out var endpoint, out var region); - var uri = GetTranslateUri(endpoint, from, to); + var uri = GetTranslateUri(endpoint, from, to); - var request = new HttpRequestMessage(); - request.Method = HttpMethod.Post; - request.RequestUri = new Uri(uri); - request.Headers.Add(SubscriptionKeyHeader, key); - if (region != null) - { - request.Headers.Add(SubscriptionRegionHeader, region); - } + var request = new HttpRequestMessage(); + request.Method = HttpMethod.Post; + request.RequestUri = new Uri(uri); + request.Headers.Add(SubscriptionKeyHeader, key); + if (region != null) + { + request.Headers.Add(SubscriptionRegionHeader, region); + } - return request; - } + return request; + } - private string GetTranslateUri(string? endpoint, string? from, string? to) - { - var sb = new StringBuilder(); - sb.Append(EnsureEndpoint(endpoint)); - sb.Append(GetTranslateRoute()); - sb.Append(FromLanguageQueryParam(from)); - sb.Append(ToLanguageQueryParam(to)); - var uri = sb.ToString(); - return uri; - } + private string GetTranslateUri(string? endpoint, string? from, string? to) + { + var sb = new StringBuilder(); + sb.Append(EnsureEndpoint(endpoint)); + sb.Append(GetTranslateRoute()); + sb.Append(FromLanguageQueryParam(from)); + sb.Append(ToLanguageQueryParam(to)); + var uri = sb.ToString(); + return uri; + } - private static string EnsureEndpoint(string? endpoint) - { - return endpoint ?? "https://api.cognitive.microsofttranslator.com"; - } + private static string EnsureEndpoint(string? endpoint) + { + return endpoint ?? "https://api.cognitive.microsofttranslator.com"; + } - private static string GetTranslateRoute() - { - return "/translate?api-version=3.0"; - } + private static string GetTranslateRoute() + { + return "/translate?api-version=3.0"; + } - private static string FromLanguageQueryParam(string? from) - { - return !string.IsNullOrEmpty(from) - ? $"&from={from}" - : string.Empty; - } + private static string FromLanguageQueryParam(string? from) + { + return !string.IsNullOrEmpty(from) + ? $"&from={from}" + : string.Empty; + } - private string ToLanguageQueryParam(string? to) - { - return string.IsNullOrEmpty(to) - ? $"&to={GetDefaultLanguage()}" - : $"&to={to}"; - } + private string ToLanguageQueryParam(string? to) + { + return string.IsNullOrEmpty(to) + ? $"&to={GetDefaultLanguage()}" + : $"&to={to}"; + } - private string GetDefaultLanguage() - { - var settings = _serviceProvider.GetRequiredService(); + private string GetDefaultLanguage() + { + var settings = _serviceProvider.GetRequiredService(); - var defaultDefault = settings.Get("DEFAULT_LANGUAGE", null) ?? "en-US"; - var defaultLanguage = settings.Get("TRANSLATOR_DEFAULT_LANGUAGE", defaultDefault); + var defaultDefault = settings.Get("DEFAULT_LANGUAGE", null) ?? "en-US"; + var defaultLanguage = settings.Get("TRANSLATOR_DEFAULT_LANGUAGE", defaultDefault); - if (string.IsNullOrEmpty(defaultLanguage)) defaultLanguage = defaultDefault; + if (string.IsNullOrEmpty(defaultLanguage)) defaultLanguage = defaultDefault; - return defaultLanguage!.Trim('\r', '\n', ' '); - } + return defaultLanguage!.Trim('\r', '\n', ' '); + } - #region supporting model classes + #region supporting model classes - public struct TranslationResult - { - public DetectedLanguage? DetectedLanguage { get; set; } - public TextResult? SourceText { get; set; } - public Translation[]? Translations { get; set; } - } + public struct TranslationResult + { + public DetectedLanguage? DetectedLanguage { get; set; } + public TextResult? SourceText { get; set; } + public Translation[]? Translations { get; set; } + } - public struct DetectedLanguage - { - public string? Language { get; set; } - public float? Score { get; set; } - } + public struct DetectedLanguage + { + public string? Language { get; set; } + public float? Score { get; set; } + } - public struct TextResult - { - public string? Text { get; set; } - public string? Script { get; set; } - } + public struct TextResult + { + public string? Text { get; set; } + public string? Script { get; set; } + } - public struct Translation - { - public string? Text { get; set; } - public TextResult? Transliteration { get; set; } - public string? To { get; set; } - public Alignment? Alignment { get; set; } - public SentenceLength? SentLen { get; set; } - } + public struct Translation + { + public string? Text { get; set; } + public TextResult? Transliteration { get; set; } + public string? To { get; set; } + public Alignment? Alignment { get; set; } + public SentenceLength? SentLen { get; set; } + } - public struct Alignment - { - public string? Proj { get; set; } - } + public struct Alignment + { + public string? Proj { get; set; } + } - public struct SentenceLength - { - public int[]? SrcSentLen { get; set; } - public int[]? TransSentLen { get; set; } - } + public struct SentenceLength + { + public int[]? SrcSentLen { get; set; } + public int[]? TransSentLen { get; set; } + } - #endregion + #endregion - private readonly IServiceProvider _serviceProvider; + private readonly IServiceProvider _serviceProvider; - private const string SubscriptionKeyHeader = "Ocp-Apim-Subscription-Key"; - private const string SubscriptionRegionHeader = "Ocp-Apim-Subscription-Region"; -} + private const string SubscriptionKeyHeader = "Ocp-Apim-Subscription-Key"; + private const string SubscriptionRegionHeader = "Ocp-Apim-Subscription-Region"; + } +} \ No newline at end of file diff --git a/src/cs/ContextResolution/CallbackContextResolver.cs b/src/cs/ContextResolution/CallbackContextResolver.cs index 621dfd45..4ad85e31 100644 --- a/src/cs/ContextResolution/CallbackContextResolver.cs +++ b/src/cs/ContextResolution/CallbackContextResolver.cs @@ -1,8 +1,9 @@ -namespace macaroni; - -internal class CallbackContextResolver : ResolutionContext, ISystemContextResolver +namespace macaroni { - public CallbackContextResolver() + internal class CallbackContextResolver : ResolutionContext, ISystemContextResolver { + public CallbackContextResolver() + { + } } -} +} \ No newline at end of file diff --git a/src/cs/ContextResolution/ClipboardContextResolver.cs b/src/cs/ContextResolution/ClipboardContextResolver.cs index 78c6e59f..01ad94f3 100644 --- a/src/cs/ContextResolution/ClipboardContextResolver.cs +++ b/src/cs/ContextResolution/ClipboardContextResolver.cs @@ -1,36 +1,37 @@ -using Azure.AI.Vision.ImageAnalysis; +using System; using Microsoft.Extensions.DependencyInjection; -namespace macaroni; - -internal class ClipboardContextResolver : ISystemContextResolver +namespace macaroni { - public ClipboardContextResolver(IServiceProvider serviceProvider) + internal class ClipboardContextResolver : ISystemContextResolver { - _serviceProvider = serviceProvider; - } + public ClipboardContextResolver(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } - public object? Get(string key, object? defaultValue) - { - return key switch + public object? Get(string key, object? defaultValue) { - "clipboard.text" => GetClipboardContentAsText() ?? defaultValue, - "clipboard.image" => GetClipboardContentAsImage() ?? defaultValue, - _ => defaultValue - }; - } + return key switch + { + "clipboard.text" => GetClipboardContentAsText() ?? defaultValue, + "clipboard.image" => GetClipboardContentAsImage() ?? defaultValue, + _ => defaultValue + }; + } - private string? GetClipboardContentAsText() - { - var clipboard = _serviceProvider.GetRequiredService(); - return clipboard.GetText(); - } + private string? GetClipboardContentAsText() + { + var clipboard = _serviceProvider.GetRequiredService(); + return clipboard.GetText(); + } - private object? GetClipboardContentAsImage() - { - var clipboard = _serviceProvider.GetRequiredService(); - return clipboard.GetImage(); - } + private object? GetClipboardContentAsImage() + { + var clipboard = _serviceProvider.GetRequiredService(); + return clipboard.GetImage(); + } - private readonly IServiceProvider _serviceProvider; -} + private readonly IServiceProvider _serviceProvider; + } +} \ No newline at end of file diff --git a/src/cs/ContextResolution/ExecutionContext.cs b/src/cs/ContextResolution/ExecutionContext.cs index fce131cd..54848f69 100644 --- a/src/cs/ContextResolution/ExecutionContext.cs +++ b/src/cs/ContextResolution/ExecutionContext.cs @@ -1,111 +1,113 @@ -using System.Text; +using System; +using System.Threading; -namespace macaroni; - -internal class ExecutionContext : ResolutionContext, IExecutionContext +namespace macaroni { - public ExecutionContext(ISystemContext context) - { - RegisterResolver(nameof(ExecutionContext), key => context.Get(key, null)); - } - - public void Start() + internal class ExecutionContext : ResolutionContext, IExecutionContext { - MR.DBG_TRACE_INFO($"-- ExecutionContext: Start() - Started"); + public ExecutionContext(ISystemContext context) + { + RegisterResolver(nameof(ExecutionContext), key => context.Get(key, null)); + } - try + public void Start() { - RunLock(); + MR.DBG_TRACE_INFO($"-- ExecutionContext: Start() - Started"); - lock (this) + try { - if (_result == ExecutionResult.Canceled || _result == ExecutionResult.Stopped) - { - throw new InvalidOperationException($"Cannot start an execution context that has already been stopped or canceled."); - } - else if (_result == ExecutionResult.Completed) - { - throw new InvalidOperationException($"Cannot start an execution context that has already completed."); - } - else if (_result == null || _result == ExecutionResult.Yielded) + RunLock(); + + lock (this) { - _turn++; + if (_result == ExecutionResult.Canceled || _result == ExecutionResult.Stopped) + { + throw new InvalidOperationException($"Cannot start an execution context that has already been stopped or canceled."); + } + else if (_result == ExecutionResult.Completed) + { + throw new InvalidOperationException($"Cannot start an execution context that has already completed."); + } + else if (_result == null || _result == ExecutionResult.Yielded) + { + _turn++; + } } } + catch (Exception) + { + RunUnlock(); + throw; + } } - catch (Exception) + + private void RunLock() { - RunUnlock(); - throw; + Monitor.Enter(_running); + _threadId = System.Threading.Thread.CurrentThread.ManagedThreadId; } - } - private void RunLock() - { - Monitor.Enter(_running); - _threadId = System.Threading.Thread.CurrentThread.ManagedThreadId; - } - - private void RunUnlock() - { - if (_threadId == System.Threading.Thread.CurrentThread.ManagedThreadId) + private void RunUnlock() { - Monitor.Exit(_running); - _threadId = 0; + if (_threadId == System.Threading.Thread.CurrentThread.ManagedThreadId) + { + Monitor.Exit(_running); + _threadId = 0; + } } - } - public void Yield() - { - MR.DBG_TRACE_INFO($"-- ExecutionContext: Yield() - Yielded"); - lock (this) + public void Yield() { - _result = ExecutionResult.Yielded; + MR.DBG_TRACE_INFO($"-- ExecutionContext: Yield() - Yielded"); + lock (this) + { + _result = ExecutionResult.Yielded; + } + RunUnlock(); } - RunUnlock(); - } - public void Stop() - { - MR.DBG_TRACE_INFO($"-- ExecutionContext: Stop() - Stopped"); - lock (this) + public void Stop() { - _result = ExecutionResult.Stopped; + MR.DBG_TRACE_INFO($"-- ExecutionContext: Stop() - Stopped"); + lock (this) + { + _result = ExecutionResult.Stopped; + } + RunUnlock(); } - RunUnlock(); - } - public void Cancel() - { - MR.DBG_TRACE_INFO($"-- ExecutionContext: Cancel() - Canceled"); - lock (this) + public void Cancel() { - _result = ExecutionResult.Canceled; + MR.DBG_TRACE_INFO($"-- ExecutionContext: Cancel() - Canceled"); + lock (this) + { + _result = ExecutionResult.Canceled; + } + RunUnlock(); } - RunUnlock(); - } - public void Complete() - { - MR.DBG_TRACE_INFO($"-- ExecutionContext: Complete() - Completed"); - lock (this) + public void Complete() { - _result = ExecutionResult.Completed; + MR.DBG_TRACE_INFO($"-- ExecutionContext: Complete() - Completed"); + lock (this) + { + _result = ExecutionResult.Completed; + } + RunUnlock(); } - RunUnlock(); - } - public ExecutionResult? Result => _result; + public ExecutionResult? Result => _result; - public override object? Get(string key, object? defaultValue) - { - return key == "context.turn" - ? _turn.ToString() - : base.Get(key, defaultValue); - } + public override object? Get(string key, object? defaultValue) + { + return key == "context.turn" + ? _turn.ToString() + : base.Get(key, defaultValue); + } - private uint _turn = 0; - private ExecutionResult? _result; - private object _running = new object(); - private int _threadId; + private uint _turn = 0; + private ExecutionResult? _result; + private object _running = new object(); + private int _threadId; + } } diff --git a/src/cs/ContextResolution/FoldersContextResolver.cs b/src/cs/ContextResolution/FoldersContextResolver.cs index 02d4c55b..71313fd7 100644 --- a/src/cs/ContextResolution/FoldersContextResolver.cs +++ b/src/cs/ContextResolution/FoldersContextResolver.cs @@ -1,52 +1,56 @@ -using Microsoft.Extensions.DependencyInjection; +using System; +using System.IO; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; -namespace macaroni; - -internal class FoldersContextResolver : ISystemContextResolver +namespace macaroni { - public FoldersContextResolver(IServiceProvider serviceProvider) + internal class FoldersContextResolver : ISystemContextResolver { - _serviceProvider = serviceProvider; - } + public FoldersContextResolver(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } - public object? Get(string key, object? defaultValue) - { - foreach (var prefix in _prefixes) + public object? Get(string key, object? defaultValue) { - if (key.StartsWith(prefix)) + foreach (var prefix in _prefixes) { - var value = GetFolderByName(key.Substring(prefix.Length)); - if (value != null) return value; + if (key.StartsWith(prefix)) + { + var value = GetFolderByName(key.Substring(prefix.Length)); + if (value != null) return value; + } } - } - return defaultValue; - } - - private string? GetFolderByName(string name) - { - if (string.Compare(name, "contentroot", true) == 0) - { - var env = _serviceProvider.GetRequiredService(); - return env.ContentRootPath; - } - else if (string.Compare(name, "temp", true) == 0) - { - return Path.GetTempPath(); + return defaultValue; } - else if (string.Compare(name, "macaroni", true) == 0) + + private string? GetFolderByName(string name) { - var location = typeof(FoldersContextResolver).Assembly.Location; - return new FileInfo(location).DirectoryName; - } + if (string.Compare(name, "contentroot", true) == 0) + { + var env = _serviceProvider.GetRequiredService(); + return env.ContentRootPath; + } + else if (string.Compare(name, "temp", true) == 0) + { + return Path.GetTempPath(); + } + else if (string.Compare(name, "macaroni", true) == 0) + { + var location = typeof(FoldersContextResolver).Assembly.Location; + return new FileInfo(location).DirectoryName; + } - var parsed = Enum.TryParse(name, true, out var folder) - || Enum.TryParse($"My{name}", true, out folder); + var parsed = Enum.TryParse(name, true, out var folder) + || Enum.TryParse($"My{name}", true, out folder); - return parsed ? Environment.GetFolderPath(folder) : null; - } + return parsed ? Environment.GetFolderPath(folder) : null; + } - private IServiceProvider _serviceProvider; + private IServiceProvider _serviceProvider; - private static readonly string[] _prefixes = { "folders.", "folder." }; -} + private static readonly string[] _prefixes = { "folders.", "folder." }; + } +} \ No newline at end of file diff --git a/src/cs/ContextResolution/GlobalNamedStateContextResolver.cs b/src/cs/ContextResolution/GlobalNamedStateContextResolver.cs index 6bfb053b..98d9ddf8 100644 --- a/src/cs/ContextResolution/GlobalNamedStateContextResolver.cs +++ b/src/cs/ContextResolution/GlobalNamedStateContextResolver.cs @@ -1,26 +1,24 @@ -using Azure.AI.Vision.ImageAnalysis; -using Microsoft.Extensions.DependencyInjection; - -namespace macaroni; - -internal class GlobalNamedStateContextResolver : ISystemContextResolver +namespace macaroni { - public GlobalNamedStateContextResolver(IGlobalNamedStateService namedStateService) + internal class GlobalNamedStateContextResolver : ISystemContextResolver { - _namedStateService = namedStateService; - } + public GlobalNamedStateContextResolver(IGlobalNamedStateService namedStateService) + { + _namedStateService = namedStateService; + } - public object? Get(string key, object? defaultValue) - { - var value = _namedStateService.GetNamedState(key); - if (value == null && key.StartsWith("global.")) + public object? Get(string key, object? defaultValue) { - var check = key.Substring("global.".Length); - value = _namedStateService.GetNamedState(check); + var value = _namedStateService.GetNamedState(key); + if (value == null && key.StartsWith("global.")) + { + var check = key.Substring("global.".Length); + value = _namedStateService.GetNamedState(check); + } + + return value ?? defaultValue; } - return value ?? defaultValue; + private readonly IGlobalNamedStateService _namedStateService; } - - private readonly IGlobalNamedStateService _namedStateService; -} +} \ No newline at end of file diff --git a/src/cs/ContextResolution/ImageAnalysisResultExtensions.cs b/src/cs/ContextResolution/ImageAnalysisResultExtensions.cs index cf2c8fbf..af65f01b 100644 --- a/src/cs/ContextResolution/ImageAnalysisResultExtensions.cs +++ b/src/cs/ContextResolution/ImageAnalysisResultExtensions.cs @@ -1,34 +1,36 @@ -using Azure.AI.Vision.ImageAnalysis; +using System.Linq; +using Azure.AI.Vision.ImageAnalysis; -namespace macaroni; - -public static class ImageAnalysisResultExtensions +namespace macaroni { - public static string AsTextRectangles(this ImageAnalysisResult result) + public static class ImageAnalysisResultExtensions { - return result.Reason == Azure.AI.Vision.ImageAnalysis.ImageAnalysisResultReason.Error - ? ImageAnalysisErrorDetails.FromResult(result).Message - : ImageAnalysisOCRTextFormatter.GetAsTextRectangles(result); - } + public static string AsTextRectangles(this ImageAnalysisResult result) + { + return result.Reason == Azure.AI.Vision.ImageAnalysis.ImageAnalysisResultReason.Error + ? ImageAnalysisErrorDetails.FromResult(result).Message + : ImageAnalysisOCRTextFormatter.GetAsTextRectangles(result); + } - public static string AsMonospaceTable(this ImageAnalysisResult result) - { - return result.Reason == Azure.AI.Vision.ImageAnalysis.ImageAnalysisResultReason.Error - ? ImageAnalysisErrorDetails.FromResult(result).Message - : ImageAnalysisOCRTextFormatter.GetAsMonospaceTable(result); - } + public static string AsMonospaceTable(this ImageAnalysisResult result) + { + return result.Reason == Azure.AI.Vision.ImageAnalysis.ImageAnalysisResultReason.Error + ? ImageAnalysisErrorDetails.FromResult(result).Message + : ImageAnalysisOCRTextFormatter.GetAsMonospaceTable(result); + } - public static string AsDescription(this ImageAnalysisResult result) - { - return result.Reason == Azure.AI.Vision.ImageAnalysis.ImageAnalysisResultReason.Error - ? ImageAnalysisErrorDetails.FromResult(result).Message - : GetDescription(result); - } + public static string AsDescription(this ImageAnalysisResult result) + { + return result.Reason == Azure.AI.Vision.ImageAnalysis.ImageAnalysisResultReason.Error + ? ImageAnalysisErrorDetails.FromResult(result).Message + : GetDescription(result); + } - private static string GetDescription(ImageAnalysisResult result) - { - return result.Descriptions != null && result.Descriptions.Count > 0 - ? result.Descriptions.First().Content - : string.Empty; + private static string GetDescription(ImageAnalysisResult result) + { + return result.Descriptions != null && result.Descriptions.Count > 0 + ? result.Descriptions.First().Content + : string.Empty; + } } } \ No newline at end of file diff --git a/src/cs/ContextResolution/ListeningContextResolver.cs b/src/cs/ContextResolution/ListeningContextResolver.cs index c6372220..88a208cb 100644 --- a/src/cs/ContextResolution/ListeningContextResolver.cs +++ b/src/cs/ContextResolution/ListeningContextResolver.cs @@ -1,18 +1,19 @@ -namespace macaroni; - -internal class ListeningContextResolver : ISystemContextResolver +namespace macaroni { - public ListeningContextResolver(IIntentRecognizerService intent) + internal class ListeningContextResolver : ISystemContextResolver { - _intent = intent; - } + public ListeningContextResolver(IIntentRecognizerService intent) + { + _intent = intent; + } - public object? Get(string key, object? defaultValue) - { - return key == "listening" - ? _intent.GetState().AsString() - : defaultValue; - } + public object? Get(string key, object? defaultValue) + { + return key == "listening" + ? _intent.GetState().AsString() + : defaultValue; + } - private IIntentRecognizerService _intent; -} + private IIntentRecognizerService _intent; + } +} \ No newline at end of file diff --git a/src/cs/ContextResolution/LocalContext.cs b/src/cs/ContextResolution/LocalContext.cs index b2881df9..03c3179b 100644 --- a/src/cs/ContextResolution/LocalContext.cs +++ b/src/cs/ContextResolution/LocalContext.cs @@ -1,5 +1,6 @@ -namespace macaroni; - -internal class LocalContext : ResolutionContext, ILocalContext +namespace macaroni { -} + internal class LocalContext : ResolutionContext, ILocalContext + { + } +} \ No newline at end of file diff --git a/src/cs/ContextResolution/ScreenCaptureContextResolver.cs b/src/cs/ContextResolution/ScreenCaptureContextResolver.cs index d57c740d..0f2d10c5 100644 --- a/src/cs/ContextResolution/ScreenCaptureContextResolver.cs +++ b/src/cs/ContextResolution/ScreenCaptureContextResolver.cs @@ -1,63 +1,65 @@ -using Microsoft.Extensions.DependencyInjection; +using System; +using Microsoft.Extensions.DependencyInjection; -namespace macaroni; - -internal class ScreenCaptureContextResolver : ISystemContextResolver +namespace macaroni { - public ScreenCaptureContextResolver(IServiceProvider serviceProvider) + internal class ScreenCaptureContextResolver : ISystemContextResolver { - _serviceProvider = serviceProvider; - } + public ScreenCaptureContextResolver(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } - public object? Get(string key, object? defaultValue) - { - return key switch - { - "screen.text" => GetScreenCaptureContentAsText() ?? defaultValue, - "screen.image" => GetScreenCaptureContentAsImage() ?? defaultValue, - "window.text" => GetWindowCaptureContentAsText() ?? defaultValue, - "window.image" => GetWindowCaptureContentAsImage() ?? defaultValue, - "focus.text" => GetFocusCaptureContentAsText() ?? defaultValue, - "focus.image" => GetFocusCaptureContentAsImage() ?? defaultValue, - _ => defaultValue - }; - } + public object? Get(string key, object? defaultValue) + { + return key switch + { + "screen.text" => GetScreenCaptureContentAsText() ?? defaultValue, + "screen.image" => GetScreenCaptureContentAsImage() ?? defaultValue, + "window.text" => GetWindowCaptureContentAsText() ?? defaultValue, + "window.image" => GetWindowCaptureContentAsImage() ?? defaultValue, + "focus.text" => GetFocusCaptureContentAsText() ?? defaultValue, + "focus.image" => GetFocusCaptureContentAsImage() ?? defaultValue, + _ => defaultValue + }; + } - private string? GetScreenCaptureContentAsText() - { - var capture = _serviceProvider.GetRequiredService(); - return capture.GetScreenText(); - } + private string? GetScreenCaptureContentAsText() + { + var capture = _serviceProvider.GetRequiredService(); + return capture.GetScreenText(); + } - private object? GetScreenCaptureContentAsImage() - { - var capture = _serviceProvider.GetRequiredService(); - return capture.GetScreenImage(); - } + private object? GetScreenCaptureContentAsImage() + { + var capture = _serviceProvider.GetRequiredService(); + return capture.GetScreenImage(); + } - private string? GetWindowCaptureContentAsText() - { - var capture = _serviceProvider.GetRequiredService(); - return capture.GetWindowText(); - } + private string? GetWindowCaptureContentAsText() + { + var capture = _serviceProvider.GetRequiredService(); + return capture.GetWindowText(); + } - private object? GetWindowCaptureContentAsImage() - { - var capture = _serviceProvider.GetRequiredService(); - return capture.GetWindowImage(); - } + private object? GetWindowCaptureContentAsImage() + { + var capture = _serviceProvider.GetRequiredService(); + return capture.GetWindowImage(); + } - private string? GetFocusCaptureContentAsText() - { - var capture = _serviceProvider.GetRequiredService(); - return capture.GetFocusText(); - } + private string? GetFocusCaptureContentAsText() + { + var capture = _serviceProvider.GetRequiredService(); + return capture.GetFocusText(); + } - private object? GetFocusCaptureContentAsImage() - { - var capture = _serviceProvider.GetRequiredService(); - return capture.GetFocusImage(); - } + private object? GetFocusCaptureContentAsImage() + { + var capture = _serviceProvider.GetRequiredService(); + return capture.GetFocusImage(); + } - private readonly IServiceProvider _serviceProvider; -} + private readonly IServiceProvider _serviceProvider; + } +} \ No newline at end of file diff --git a/src/cs/ContextResolution/SystemContext.cs b/src/cs/ContextResolution/SystemContext.cs index 0f998562..919489f4 100644 --- a/src/cs/ContextResolution/SystemContext.cs +++ b/src/cs/ContextResolution/SystemContext.cs @@ -1,29 +1,52 @@ -using System.Text; +using System.Collections.Generic; -namespace macaroni; - -internal class SystemContext : ResolutionContext, ISystemContext +namespace macaroni { - public SystemContext(IEnumerable resolvers, ICommandSystemSettings settings) + internal class SystemContext : ResolutionContext, ISystemContext { - _resolvers = resolvers; - _settings = settings; - - RegisterResolver(nameof(SystemContext), key => ResolveContext(_resolvers, key)); - } + public SystemContext(IEnumerable resolvers, ICommandSystemSettings settings) + { + _resolvers = resolvers; - private object? ResolveContext(IEnumerable resolvers, string name) - { - foreach (var resolver in resolvers) + /* Unmerged change from project 'macaroni_core (net6.0-windows)' + Before: + _settings = settings; + + RegisterResolver(nameof(SystemContext), key => ResolveContext(_resolvers, key)); + After: + _settings = settings; + + RegisterResolver(nameof(SystemContext), key => ResolveContext(_resolvers, key)); + */ + + /* Unmerged change from project 'macaroni_core (netstandard2.1)' + Before: + _settings = settings; + + RegisterResolver(nameof(SystemContext), key => ResolveContext(_resolvers, key)); + After: + _settings = settings; + + RegisterResolver(nameof(SystemContext), key => ResolveContext(_resolvers, key)); + */ + _settings = settings; + + RegisterResolver(nameof(SystemContext), key => ResolveContext(_resolvers, key)); + } + + private object? ResolveContext(IEnumerable resolvers, string name) { - object? resolved = resolver.Get(name, null); - if (resolved != null) return resolved; + foreach (var resolver in resolvers) + { + object? resolved = resolver.Get(name, null); + if (resolved != null) return resolved; + } + + var value = _settings.Get(name, string.Empty); + return string.IsNullOrEmpty(value) ? null : value; } - - var value = _settings.Get(name, string.Empty); - return string.IsNullOrEmpty(value) ? null : value; - } - private IEnumerable _resolvers; - private ICommandSystemSettings _settings; -} + private IEnumerable _resolvers; + private ICommandSystemSettings _settings; + } +} \ No newline at end of file diff --git a/src/cs/ContextResolution/TemplateReaderContextResolver.cs b/src/cs/ContextResolution/TemplateReaderContextResolver.cs index 3f4d23ed..eb793630 100644 --- a/src/cs/ContextResolution/TemplateReaderContextResolver.cs +++ b/src/cs/ContextResolution/TemplateReaderContextResolver.cs @@ -1,28 +1,33 @@ -namespace macaroni; +using System; +using System.Collections.Generic; +using System.IO; -class TemplateReaderContextResolver : ISystemContextResolver +namespace macaroni { - public TemplateReaderContextResolver(List> templateReaders) + class TemplateReaderContextResolver : ISystemContextResolver { - this.templateReaders = templateReaders; - } + public TemplateReaderContextResolver(List> templateReaders) + { + this.templateReaders = templateReaders; + } - public object? Get(string key, object? defaultValue) - { - if (key.StartsWith("template:")) + public object? Get(string key, object? defaultValue) { - key = key.Substring("template:".Length); - foreach (var reader in templateReaders) + if (key.StartsWith("template:")) { - var textReader = reader(key); - if (textReader != null) + key = key.Substring("template:".Length); + foreach (var reader in templateReaders) { - return textReader.ReadToEnd(); + var textReader = reader(key); + if (textReader != null) + { + return textReader.ReadToEnd(); + } } } + return defaultValue; } - return defaultValue; - } - private List> templateReaders; -} + private List> templateReaders; + } +} \ No newline at end of file diff --git a/src/cs/DataTypes/IntentResult.cs b/src/cs/DataTypes/IntentResult.cs index 9aa804ce..3104e9e5 100644 --- a/src/cs/DataTypes/IntentResult.cs +++ b/src/cs/DataTypes/IntentResult.cs @@ -1,9 +1,5 @@ -using Microsoft.CognitiveServices.Speech.Intent; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Collections.Generic; +using Microsoft.CognitiveServices.Speech.Intent; namespace macaroni.DataTypes { diff --git a/src/cs/ExtraTools/CommandSetYamlParserProgram.cs b/src/cs/ExtraTools/CommandSetYamlParserProgram.cs index 74edf794..4a976947 100644 --- a/src/cs/ExtraTools/CommandSetYamlParserProgram.cs +++ b/src/cs/ExtraTools/CommandSetYamlParserProgram.cs @@ -1,4 +1,6 @@ -namespace macaroni; +namespace macaroni +{ +} #if COMMAND_SET_YAML_PARSER_EXAMPLE diff --git a/src/cs/Helpers/CommandSystemException.cs b/src/cs/Helpers/CommandSystemException.cs index efab82f8..e30493ce 100644 --- a/src/cs/Helpers/CommandSystemException.cs +++ b/src/cs/Helpers/CommandSystemException.cs @@ -1,8 +1,12 @@ -namespace macaroni; +using System; -public class CommandSystemException : SystemException +namespace macaroni { - public CommandSystemException(string message) : base(message) + + public class CommandSystemException : SystemException { + public CommandSystemException(string message) : base(message) + { + } } -} +} \ No newline at end of file diff --git a/src/cs/Helpers/CommandSystemSettings.cs b/src/cs/Helpers/CommandSystemSettings.cs index 273616fb..fe05e9ac 100644 --- a/src/cs/Helpers/CommandSystemSettings.cs +++ b/src/cs/Helpers/CommandSystemSettings.cs @@ -1,73 +1,75 @@ +using System; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -namespace macaroni; - -internal class CommandSystemSettings : ICommandSystemSettings +namespace macaroni { - public CommandSystemSettings(IServiceProvider serviceProvider) + internal class CommandSystemSettings : ICommandSystemSettings { - _serviceProvider = serviceProvider; - _keyVaultService = serviceProvider.GetService(); - _developerSettings = serviceProvider.GetService(); - _secretSettings = serviceProvider.GetService(); - _protectedSettings = serviceProvider.GetService(); - _config = serviceProvider.GetService(); - } + public CommandSystemSettings(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + _keyVaultService = serviceProvider.GetService(); + _developerSettings = serviceProvider.GetService(); + _secretSettings = serviceProvider.GetService(); + _protectedSettings = serviceProvider.GetService(); + _config = serviceProvider.GetService(); + } - public string? Get(string name, string? defaultValue = null) - { - return ReadSettingFromEnvironmentOrFile(name, defaultValue); - } + public string? Get(string name, string? defaultValue = null) + { + return ReadSettingFromEnvironmentOrFile(name, defaultValue); + } - private string? ReadSettingFromEnvironmentOrFile(string name, string? defaultValue = null) - { - string? value = null; - - var tryDevSettings = value == null; - if (tryDevSettings) value = _developerSettings?.Get(name, null); + private string? ReadSettingFromEnvironmentOrFile(string name, string? defaultValue = null) + { + string? value = null; - var trySecrets = value == null; - if (trySecrets) _secretSettings?.TryGet(name, out value); + var tryDevSettings = value == null; + if (tryDevSettings) value = _developerSettings?.Get(name, null); - var tryEnv = value == null; - if (tryEnv) value = Environment.GetEnvironmentVariable(name); - - var tryFile = value == null && FileHelpers.FileExists(name); - if (tryFile) value = FileHelpers.FileReadAllText(name); + var trySecrets = value == null; + if (trySecrets) _secretSettings?.TryGet(name, out value); - var tryProtectedSettings = value == null; - if (tryProtectedSettings) _protectedSettings?.TryGet(name, out value); + var tryEnv = value == null; + if (tryEnv) value = Environment.GetEnvironmentVariable(name); - var tryConfig = value == null && _config != null; - if (tryConfig) value = FromConfig(name); + var tryFile = value == null && FileHelpers.FileExists(name); + if (tryFile) value = FileHelpers.FileReadAllText(name); - var tryKeyVault = value == null && Environment.GetEnvironmentVariable("MACARONI_NO_KEY_VAULT") == null && _keyVaultService != null; - if (tryKeyVault) - { - var ok = _keyVaultService!.TryGetSettingValue(name, out value, defaultValue != null); - if (!ok) value = null; - } + var tryProtectedSettings = value == null; + if (tryProtectedSettings) _protectedSettings?.TryGet(name, out value); - var useDefault = value == null; - if (useDefault) value = defaultValue; + var tryConfig = value == null && _config != null; + if (tryConfig) value = FromConfig(name); - var badValue = value == null; - if (badValue) throw FileHelpers.ErrorFileNotFoundException(name); + var tryKeyVault = value == null && Environment.GetEnvironmentVariable("MACARONI_NO_KEY_VAULT") == null && _keyVaultService != null; + if (tryKeyVault) + { + var ok = _keyVaultService!.TryGetSettingValue(name, out value, defaultValue != null); + if (!ok) value = null; + } - return value; - } + var useDefault = value == null; + if (useDefault) value = defaultValue; - private string? FromConfig(string name) - { - var value = _config?[name]; - return string.IsNullOrEmpty(value) ? null : value; - } + var badValue = value == null; + if (badValue) throw FileHelpers.ErrorFileNotFoundException(name); + + return value; + } - private readonly IServiceProvider _serviceProvider; - private IProtectedSecretSettingsCache? _protectedSettings; - private IKeyVaultSettingsService? _keyVaultService; - private IDeveloperSettings? _developerSettings; - private ISecretSettings? _secretSettings; - private IConfiguration? _config; -} + private string? FromConfig(string name) + { + var value = _config?[name]; + return string.IsNullOrEmpty(value) ? null : value; + } + + private readonly IServiceProvider _serviceProvider; + private IProtectedSecretSettingsCache? _protectedSettings; + private IKeyVaultSettingsService? _keyVaultService; + private IDeveloperSettings? _developerSettings; + private ISecretSettings? _secretSettings; + private IConfiguration? _config; + } +} \ No newline at end of file diff --git a/src/cs/Helpers/FileHelpers.cs b/src/cs/Helpers/FileHelpers.cs index f581294c..79bfebd9 100644 --- a/src/cs/Helpers/FileHelpers.cs +++ b/src/cs/Helpers/FileHelpers.cs @@ -1,68 +1,81 @@ -namespace macaroni; +using System.IO; +using System.Linq; -public class FileHelpers +namespace macaroni { - public static string? AdjustRelativeFileName(string baseFile, string relativeFile) + public class FileHelpers { - if (!File.Exists(relativeFile) && File.Exists(baseFile)) + public static string? AdjustRelativeFileName(string baseFile, string relativeFile) { - var baseDirectory = new FileInfo(baseFile)?.DirectoryName; - if (baseDirectory != null) + if (!File.Exists(relativeFile) && File.Exists(baseFile)) { - relativeFile = Path.Combine(baseDirectory, relativeFile); + var baseDirectory = new FileInfo(baseFile)?.DirectoryName; + if (baseDirectory != null) + { + relativeFile = Path.Combine(baseDirectory, relativeFile); + } } + return relativeFile; } - return relativeFile; - } - public static string? FindFile(string name) - { - var dir = new DirectoryInfo(Directory.GetCurrentDirectory()); - while (dir != null && dir.Exists) + public static string? FindFile(string name) { - var combined = Path.Combine(dir.FullName, name); - if (File.Exists(combined)) return combined; + if (!FileNameIsValid(name)) + return null; + + var dir = new DirectoryInfo(Directory.GetCurrentDirectory()); + while (dir != null && dir.Exists) + { + var combined = Path.Combine(dir.FullName, name); + if (File.Exists(combined)) return combined; - dir = dir.Parent; + dir = dir.Parent; + } + return null; } - return null; - } - public static bool FileExists(string name) - { - return FindFile(name) != null; - } - - public static string FileReadAllText(string name) - { - var file = FindFile(name) ?? throw new FileNotFoundException("File not found", name); + public static bool FileExists(string name) + { + return FindFile(name) != null; + } - var text = File.ReadAllText(file); - if (name == "MACRO_FOLDER" && text.StartsWith("MACRO_FOLDER=")) + public static string FileReadAllText(string name) { - var eq = text.IndexOf('='); - text = text.Substring(eq + 1); + var file = FindFile(name) ?? throw new FileNotFoundException("File not found", name); - var dir = new FileInfo(file).Directory?.FullName ?? "."; - text = Path.Combine(dir, text); - } + var text = File.ReadAllText(file); + if (name == "MACRO_FOLDER" && text.StartsWith("MACRO_FOLDER=")) + { + var eq = text.IndexOf('='); + text = text.Substring(eq + 1); - return text; - } + var dir = new FileInfo(file).Directory?.FullName ?? "."; + text = Path.Combine(dir, text); + } - public static string? TryFileReadAllText(string name) - { - return FileExists(name) ? FileReadAllText(name) : null; - } + return text; + } - public static FileNotFoundException ErrorFileNotFoundException(string name) - { - var title = $"'{name}' not found!"; - var message = $"Couldn't find environment variable or file named '{name}'"; + public static string? TryFileReadAllText(string name) + { + return FileExists(name) ? FileReadAllText(name) : null; + } + + private static readonly char[] invalidPathChars = new[] { '"' }; + public static bool FileNameIsValid(string str) + { + return !str.Any(invalidPathChars.Contains); + } + + public static FileNotFoundException ErrorFileNotFoundException(string name) + { + var title = $"'{name}' not found!"; + var message = $"Couldn't find environment variable or file named '{name}'"; - // var msgbox = CommandSystemApiBuilder.Services?.GetService(); - // msgbox?.Show(message, title); + // var msgbox = CommandSystemApiBuilder.Services?.GetService(); + // msgbox?.Show(message, title); - return new FileNotFoundException(message, name); + return new FileNotFoundException(message, name); + } } -} +} \ No newline at end of file diff --git a/src/cs/Helpers/FileMonitor.cs b/src/cs/Helpers/FileMonitor.cs index 117b62ad..af22e211 100644 --- a/src/cs/Helpers/FileMonitor.cs +++ b/src/cs/Helpers/FileMonitor.cs @@ -1,147 +1,154 @@ -namespace macaroni; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; -internal class FileMonitor +namespace macaroni { - public FileMonitor(string? path = null, string? filter = null) + internal class FileMonitor { - _path = string.IsNullOrEmpty(path) || !Directory.Exists(path) - ? Directory.GetCurrentDirectory() - : path; - _filter = string.IsNullOrEmpty(filter) - ? "*.*" - : filter; - - _watcher = new FileSystemWatcher(_path, _filter); - _watcher.IncludeSubdirectories = true; - - _watcher.Created += (s, e) => CoalesceFileChanges(e); - _watcher.Deleted += (s, e) => CoalesceFileChanges(e); - _watcher.Changed += (s, e) => CoalesceFileChanges(e); - _watcher.Renamed += (s, e) => CoalesceFileChanges(e); - _watcher.Error += (s, e) => CoalesceFileChanges(e); - } + public FileMonitor(string? path = null, string? filter = null) + { + _path = string.IsNullOrEmpty(path) || !Directory.Exists(path) + ? Directory.GetCurrentDirectory() + : path; + _filter = string.IsNullOrEmpty(filter) + ? "*.*" + : filter; + + _watcher = new FileSystemWatcher(_path, _filter); + _watcher.IncludeSubdirectories = true; + + _watcher.Created += (s, e) => CoalesceFileChanges(e); + _watcher.Deleted += (s, e) => CoalesceFileChanges(e); + _watcher.Changed += (s, e) => CoalesceFileChanges(e); + _watcher.Renamed += (s, e) => CoalesceFileChanges(e); + _watcher.Error += (s, e) => CoalesceFileChanges(e); + } - public void StartNotify(Action newFiles, Action changedFiles, Action deletedFiles, Action>? updatedFileList = null) - { - lock (this) + public void StartNotify(Action newFiles, Action changedFiles, Action deletedFiles, Action>? updatedFileList = null) { - _newFiles = newFiles; - _changedFiles = changedFiles; - _deletedFiles = deletedFiles; - _updatedFileList = updatedFileList; + lock (this) + { + _newFiles = newFiles; + _changedFiles = changedFiles; + _deletedFiles = deletedFiles; + _updatedFileList = updatedFileList; - _watcher.EnableRaisingEvents = true; + _watcher.EnableRaisingEvents = true; - RescanNow(); + RescanNow(); + } } - } - public void StopNotify() - { - lock (this) + public void StopNotify() { - _newFiles = null; - _changedFiles = null; - _deletedFiles = null; - _updatedFileList = null; + lock (this) + { + _newFiles = null; + _changedFiles = null; + _deletedFiles = null; + _updatedFileList = null; - _watcher.EnableRaisingEvents = false; + _watcher.EnableRaisingEvents = false; - RescanReset(); + RescanReset(); + } } - } - private void CoalesceFileChanges(ErrorEventArgs e) - { - DelayRescan(); - } + private void CoalesceFileChanges(ErrorEventArgs e) + { + DelayRescan(); + } - private void CoalesceFileChanges(FileSystemEventArgs e) - { - DelayRescan(); - } + private void CoalesceFileChanges(FileSystemEventArgs e) + { + DelayRescan(); + } - private void DelayRescan() - { - lock (this) + private void DelayRescan() { - if (_delayedRescan == null || _delayedRescan.IsCompleted) + lock (this) { - _delayedRescan = Task.Delay(500).ContinueWith(t => + if (_delayedRescan == null || _delayedRescan.IsCompleted) { - lock (this) RescanNow(); - }); + _delayedRescan = Task.Delay(500).ContinueWith(t => + { + lock (this) RescanNow(); + }); + } } } - } - private void RescanReset() - { - _filesLastRescan.Clear(); - } - - private void RescanNow() - { - var files = new DirectoryInfo(_path).GetFiles(_filter, SearchOption.AllDirectories); - EvaluateChanges(files, out var filesNew, out var filesChanged, out var filesDeleted); - - if (_deletedFiles != null) filesDeleted.ForEach(f => _deletedFiles(f)); - if (_changedFiles != null) filesChanged.ForEach(f => _changedFiles(f)); - if (_newFiles != null) filesNew.ForEach(f => _newFiles(f)); + private void RescanReset() + { + _filesLastRescan.Clear(); + } - var changed = filesNew.Count() > 0 || filesChanged.Count() > 0 || filesDeleted.Count() > 0; - if (changed && _updatedFileList != null) _updatedFileList(_filesLastRescan); - } + private void RescanNow() + { + var files = new DirectoryInfo(_path).GetFiles(_filter, SearchOption.AllDirectories); + EvaluateChanges(files, out var filesNew, out var filesChanged, out var filesDeleted); - private void EvaluateChanges(FileInfo[] currentFiles, out List filesNew, out List filesChanged, out List filesDeleted) - { - var filesNotDeleted = new List(); + if (_deletedFiles != null) filesDeleted.ForEach(f => _deletedFiles(f)); + if (_changedFiles != null) filesChanged.ForEach(f => _changedFiles(f)); + if (_newFiles != null) filesNew.ForEach(f => _newFiles(f)); - filesNew = new List(); - filesChanged = new List(); - filesDeleted = new List(); + var changed = filesNew.Count() > 0 || filesChanged.Count() > 0 || filesDeleted.Count() > 0; + if (changed && _updatedFileList != null) _updatedFileList(_filesLastRescan); + } - foreach (var current in currentFiles) + private void EvaluateChanges(FileInfo[] currentFiles, out List filesNew, out List filesChanged, out List filesDeleted) { - var previous = _filesLastRescan.Where(x => x.FullName == current.FullName).FirstOrDefault(); - if (previous == null) - { - filesNew.Add(current); - continue; - } + var filesNotDeleted = new List(); - var changed = previous.Length != current.Length - || previous.Attributes != current.Attributes - || previous.CreationTime != current.CreationTime - || previous.LastAccessTime != current.LastAccessTime - || previous.LastWriteTime != current.LastWriteTime; - if (changed) + filesNew = new List(); + filesChanged = new List(); + filesDeleted = new List(); + + foreach (var current in currentFiles) { - filesChanged.Add(current); - filesNotDeleted.Add(current); + var previous = _filesLastRescan.Where(x => x.FullName == current.FullName).FirstOrDefault(); + if (previous == null) + { + filesNew.Add(current); + continue; + } + + var changed = previous.Length != current.Length + || previous.Attributes != current.Attributes + || previous.CreationTime != current.CreationTime + || previous.LastAccessTime != current.LastAccessTime + || previous.LastWriteTime != current.LastWriteTime; + if (changed) + { + filesChanged.Add(current); + filesNotDeleted.Add(current); + } } - } - filesDeleted.AddRange( - _filesLastRescan.Where(previous => - !currentFiles.Any(current => - current.FullName == previous.FullName))); + filesDeleted.AddRange( + _filesLastRescan.Where(previous => + !currentFiles.Any(current => + current.FullName == previous.FullName))); - _filesLastRescan.Clear(); - _filesLastRescan.AddRange(currentFiles); - } + _filesLastRescan.Clear(); + _filesLastRescan.AddRange(currentFiles); + } - private readonly string _path; - private readonly string _filter; - private FileSystemWatcher _watcher; + private readonly string _path; + private readonly string _filter; + private FileSystemWatcher _watcher; - private Task? _delayedRescan; - private List _filesLastRescan = new List(); + private Task? _delayedRescan; + private List _filesLastRescan = new List(); - private Action? _newFiles; - private Action? _changedFiles; - private Action? _deletedFiles; - private Action>? _updatedFileList; + private Action? _newFiles; + private Action? _changedFiles; + private Action? _deletedFiles; + private Action>? _updatedFileList; + } } #if FILE_MONITOR_EXAMPLE_PROGRAM diff --git a/src/cs/Helpers/FileParseException.cs b/src/cs/Helpers/FileParseException.cs index 3a347ac0..bdf6b371 100644 --- a/src/cs/Helpers/FileParseException.cs +++ b/src/cs/Helpers/FileParseException.cs @@ -1,44 +1,48 @@ -namespace macaroni; +using System; -public class FileParseException : Exception +namespace macaroni { - public FileParseException(string message, string document, int line = 0, int column = 0) : base(message) - { - Document = document; - Line = line; - Column = column; - } - public FileParseException(string message, string document, Exception innerException) : base(message, innerException) + public class FileParseException : Exception { - Document = document; - } + public FileParseException(string message, string document, int line = 0, int column = 0) : base(message) + { + Document = document; + Line = line; + Column = column; + } - public string Document { get; } + public FileParseException(string message, string document, Exception innerException) : base(message, innerException) + { + Document = document; + } - public int Line { get; } - public int Column { get; } + public string Document { get; } - public string DocumentPosition - { - get + public int Line { get; } + public int Column { get; } + + public string DocumentPosition { - var where = Document; - if (Line > 0) + get { - where += $"({Line}"; - if (Column > 0) + var where = Document; + if (Line > 0) { - where += $",{Column}"; + where += $"({Line}"; + if (Column > 0) + { + where += $",{Column}"; + } + where += ")"; } - where += ")"; + return where; } - return where; } - } - public override string ToString() - { - return $"{DocumentPosition}: {Message}"; + public override string ToString() + { + return $"{DocumentPosition}: {Message}"; + } } -} +} \ No newline at end of file diff --git a/src/cs/Helpers/FileParseWarning.cs b/src/cs/Helpers/FileParseWarning.cs index 9a2bfad9..76f08da9 100644 --- a/src/cs/Helpers/FileParseWarning.cs +++ b/src/cs/Helpers/FileParseWarning.cs @@ -1,40 +1,44 @@ -namespace macaroni; - -public class FileParseWarning +namespace macaroni { - public FileParseWarning(string message, string document, int line = 0, int column = 0) + + public class FileParseWarning { - Message = message; - Document = document; - Line = line; - Column = column; - } + public FileParseWarning(string message, string document, int line = 0, int column = 0) + { + Message = message; + Document = document; + Line = line; + Column = column; + } - public string Message { get; } - public string Document { get; } - public int Line { get; } - public int Column { get; } + public string Message { get; } + public string Document { get; } + public int Line { get; } + public int Column { get; } - public string DocumentPosition - { - get + public string DocumentPosition { - var where = Document; - if (Line > 0) + get { - where += $"({Line}"; - if (Column > 0) + var where = Document; + if (Line > 0) { - where += $",{Column}"; + where += $"({Line}"; + if (Column > 0) + { + where += $",{Column}"; + } + + where += ")"; } - where += ")"; + + return where; } - return where; } - } - public override string ToString() - { - return $"{DocumentPosition}: {Message}"; + public override string ToString() + { + return $"{DocumentPosition}: {Message}"; + } } -} +} \ No newline at end of file diff --git a/src/cs/Helpers/ImageAnalysisOCRTextFormatter.cs b/src/cs/Helpers/ImageAnalysisOCRTextFormatter.cs index 5a51963f..29ff0b62 100644 --- a/src/cs/Helpers/ImageAnalysisOCRTextFormatter.cs +++ b/src/cs/Helpers/ImageAnalysisOCRTextFormatter.cs @@ -1,6 +1,8 @@ -using Azure.AI.Vision.ImageAnalysis; -using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using Azure.AI.Vision.ImageAnalysis; using System.Drawing; +using System.Linq; using System.Text; namespace macaroni @@ -38,7 +40,7 @@ public static string GetAsMonospaceTable(ImageAnalysisResult imageAnalysisResult // We'll query the expected number of spaces before a chunk by recursively querying (with a cache!) // how many spaces preceding elements on any row require and then adding "prorated" character counts // based on how much of a chunk is being displayed. - Dictionary spacesBeforeChunkCacheMap = new(); + Dictionary spacesBeforeChunkCacheMap = new Dictionary(); double GetSpacesBefore(DisplayChunk chunkToEvaluate) { if (spacesBeforeChunkCacheMap.TryGetValue(chunkToEvaluate, out double cachedSpaceCount)) @@ -87,10 +89,10 @@ double GetSpacesBefore(DisplayChunk chunkToEvaluate) return highestSpaces; } - StringBuilder resultBuilder = new(); + StringBuilder resultBuilder = new StringBuilder(); foreach (var row in sortedDisplayRows) { - StringBuilder lineBuilder = new(); + StringBuilder lineBuilder = new StringBuilder(); foreach (var chunk in row.Chunks) { var spacesBeforeChunk = (int)Math.Round(GetSpacesBefore(chunk)); @@ -109,11 +111,11 @@ double GetSpacesBefore(DisplayChunk chunkToEvaluate) private class DisplayRow { public IReadOnlyList Chunks => _chunks; - private List _chunks = new(); + private List _chunks = new List(); public static List GetRowsFromImageAnalysisResult(ImageAnalysisResult imageAnalysisResult) { - List result = new(); + List result = new List(); var allDisplayChunks = imageAnalysisResult.Text.Lines .Select(line => new DisplayChunk(line)) @@ -144,7 +146,7 @@ public static List GetRowsFromImageAnalysisResult(ImageAnalysisResul } if (createsNewRow) { - DisplayRow newRow = new(); + DisplayRow newRow = new DisplayRow(); newRow._chunks.Add(unsortedChunk); result.Insert(newRowIndex, newRow); } @@ -211,8 +213,8 @@ public DisplayChunk(DetectedTextLine line) private static Rectangle PointsToRect(IEnumerable points) { - Point upperLeft = new(int.MaxValue, int.MaxValue); - Point lowerRight = new(0, 0); + Point upperLeft = new Point(int.MaxValue, int.MaxValue); + Point lowerRight = new Point(0, 0); foreach (var point in points) { upperLeft.X = Math.Min(upperLeft.X, point.X); @@ -220,7 +222,7 @@ private static Rectangle PointsToRect(IEnumerable points) lowerRight.X = Math.Max(lowerRight.X, point.X); lowerRight.Y = Math.Max(lowerRight.Y, point.Y); } - return new(upperLeft.X, upperLeft.Y, lowerRight.X - upperLeft.X, lowerRight.Y - upperLeft.Y); + return new Rectangle(upperLeft.X, upperLeft.Y, lowerRight.X - upperLeft.X, lowerRight.Y - upperLeft.Y); } private ImageAnalysisOCRTextFormatter() diff --git a/src/cs/Helpers/OS.cs b/src/cs/Helpers/OS.cs index 934aca80..d028b67a 100644 --- a/src/cs/Helpers/OS.cs +++ b/src/cs/Helpers/OS.cs @@ -1,15 +1,17 @@ +using System; using System.Runtime.InteropServices; -namespace macaroni; - -public static class OS +namespace macaroni { - public static bool IsWindows() => RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - public static bool IsMac() => RuntimeInformation.IsOSPlatform(OSPlatform.OSX); - public static bool IsLinux() => RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && !IsAndroid(); - public static bool IsAndroid() + public static class OS { - return Environment.GetEnvironmentVariable("ANDROID_ROOT") != null && - Environment.GetEnvironmentVariable("ANDROID_DATA") != null; + public static bool IsWindows() => RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + public static bool IsMac() => RuntimeInformation.IsOSPlatform(OSPlatform.OSX); + public static bool IsLinux() => RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && !IsAndroid(); + public static bool IsAndroid() + { + return Environment.GetEnvironmentVariable("ANDROID_ROOT") != null && + Environment.GetEnvironmentVariable("ANDROID_DATA") != null; + } } -} +} \ No newline at end of file diff --git a/src/cs/Helpers/ParsedValueWarningChecker.cs b/src/cs/Helpers/ParsedValueWarningChecker.cs index bb292abe..062c8a5f 100644 --- a/src/cs/Helpers/ParsedValueWarningChecker.cs +++ b/src/cs/Helpers/ParsedValueWarningChecker.cs @@ -1,96 +1,101 @@ +using System; +using System.Collections.Generic; using System.Text; +using YamlDotNet.RepresentationModel; -namespace macaroni; - -internal class ParsedValueWarningChecker : IParsedValueWarningChecker +namespace macaroni { - public ParsedValueWarningChecker(IEnumerable? externValues = null) - { - this._externValues = externValues != null ? new HashSet(externValues) : null; - } - - public IEnumerable Warnings => _warnings; - public void CheckParsedValue(string file, string? mappingName, YamlNode? node, string? value) + internal class ParsedValueWarningChecker : IParsedValueWarningChecker { - if (value == null) return; - if (!value.Contains('{')) return; - if (IsVerbatimString(value)) return; + public ParsedValueWarningChecker(IEnumerable? externValues = null) + { + this._externValues = externValues != null ? new HashSet(externValues) : null; + } - var i = 0; - while (i < value.Length) + public IEnumerable Warnings => _warnings; + + public void CheckParsedValue(string file, string? mappingName, YamlNode? node, string? value) { - if (value[i] == '$' && i + 1 < value.Length && value[i + 1] == '{') - { - i++; - CheckParseValue(file, mappingName, node, value, ref i); - } - else + if (value == null) return; + if (!value.Contains('{')) return; + if (IsVerbatimString(value)) return; + + var i = 0; + while (i < value.Length) { - i++; + if (value[i] == '$' && i + 1 < value.Length && value[i + 1] == '{') + { + i++; + CheckParseValue(file, mappingName, node, value, ref i); + } + else + { + i++; + } } } - } - private bool IsVerbatimString(string value) - { - if (value.Length < 2) return false; - if (value[0] != '@') return false; - if (value[1] != '"') return false; - return true; - } - - private string CheckParseValue(string file, string? mappingName, YamlNode? node, string value, ref int i) - { - if (value[i] != '{') throw new InvalidOperationException($"CheckParseValue() '{{' not found; pos={i}"); - i += 1; // skipping '{' + private bool IsVerbatimString(string value) + { + if (value.Length < 2) return false; + if (value[0] != '@') return false; + if (value[1] != '"') return false; + return true; + } - var sb = new StringBuilder(); - while (i < value.Length && value[i] != '}') + private string CheckParseValue(string file, string? mappingName, YamlNode? node, string value, ref int i) { - if (value[i] == '$' && i + 1 < value.Length && value[i + 1] == '{') + if (value[i] != '{') throw new InvalidOperationException($"CheckParseValue() '{{' not found; pos={i}"); + i += 1; // skipping '{' + + var sb = new StringBuilder(); + while (i < value.Length && value[i] != '}') { - i++; - sb.Append(CheckParseValue(file, mappingName, node, value, ref i)); + if (value[i] == '$' && i + 1 < value.Length && value[i + 1] == '{') + { + i++; + sb.Append(CheckParseValue(file, mappingName, node, value, ref i)); + } + else + { + sb.Append(value[i]); + i++; + } } - else + + if (value[i] != '}') throw new InvalidOperationException($"CheckParseValue() '}}' not found; pos={i}"); + i += 1; // skipping '}' + + var name = sb.ToString(); + if (!CheckIsValid(name)) { - sb.Append(value[i]); - i++; + AddNewWarning(file, mappingName, node, value, name); } - } - if (value[i] != '}') throw new InvalidOperationException($"CheckParseValue() '}}' not found; pos={i}"); - i += 1; // skipping '}' + return "{" + name + "}"; + } - var name = sb.ToString(); - if (!CheckIsValid(name)) + private bool CheckIsValid(string name) { - AddNewWarning(file, mappingName, node, value, name); + return _externValues?.Contains(name) ?? false; } - return "{" + name + "}"; - } + private void AddNewWarning(string file, string? mappingName, YamlNode? node, string value, string name) + { + name = name.Replace("\n", "\\n").Replace("\r", "\\r"); + value = value.Replace("\n", "\\n").Replace("\r", "\\r"); - private bool CheckIsValid(string name) - { - return _externValues?.Contains(name) ?? false; - } + var message = !string.IsNullOrEmpty(mappingName) + ? $"WARNING: External interpolation '${{{name}}}' not found!\n Found while parsing '{mappingName}' value: '{value}'" + : $"WARNING: External interpolation '${{{name}}}' not found!\n Found while parsing value: '{value}'"; + var line = node?.Start.Line ?? 0; + var column = node?.Start.Column ?? 0; - private void AddNewWarning(string file, string? mappingName, YamlNode? node, string value, string name) - { - name = name.Replace("\n", "\\n").Replace("\r", "\\r"); - value = value.Replace("\n", "\\n").Replace("\r", "\\r"); - - var message = !string.IsNullOrEmpty(mappingName) - ? $"WARNING: External interpolation '${{{name}}}' not found!\n Found while parsing '{mappingName}' value: '{value}'" - : $"WARNING: External interpolation '${{{name}}}' not found!\n Found while parsing value: '{value}'"; - var line = node?.Start.Line ?? 0; - var column = node?.Start.Column ?? 0; - - _warnings.Add(new FileParseWarning(message, file, line, column)); - } + _warnings.Add(new FileParseWarning(message, file, line, column)); + } - private readonly List _warnings = new(); - private HashSet? _externValues; -} + private readonly List _warnings = new List(); + private HashSet? _externValues; + } +} \ No newline at end of file diff --git a/src/cs/Helpers/ResolutionContext.cs b/src/cs/Helpers/ResolutionContext.cs index e0ba3dad..8de892b0 100644 --- a/src/cs/Helpers/ResolutionContext.cs +++ b/src/cs/Helpers/ResolutionContext.cs @@ -1,235 +1,239 @@ -using System.Text; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; -namespace macaroni; - -internal class ResolutionContext +namespace macaroni { - public virtual object? Get(string key, object? defaultValue) + internal class ResolutionContext { - if (key == "context.keys") + public virtual object? Get(string key, object? defaultValue) { - return GetAll(key); - } + if (key == "context.keys") + { + return GetAll(key); + } - if (_context.ContainsKey(key)) - { - return _context[key]; - } + if (_context.ContainsKey(key)) + { + return _context[key]; + } - foreach (var resolver in _resolvers.Values.Reverse()) - { - var resolved = resolver != null ? resolver(key) : null; - if (resolved != null) + foreach (var resolver in _resolvers.Values.Reverse()) { - return resolved; + var resolved = resolver != null ? resolver(key) : null; + if (resolved != null) + { + return resolved; + } } + + return defaultValue; } - return defaultValue; - } + public void Set(string key, object value, SetValueKind kind) + { + MR.DBG_TRACE_INFO($"ResolutionContext.Set: '{key}'='{value}', kind={kind}'"); - public void Set(string key, object value, SetValueKind kind) - { - MR.DBG_TRACE_INFO($"ResolutionContext.Set: '{key}'='{value}', kind={kind}'"); + if (kind == SetValueKind.OverrideAllResolvers) + { + SetValueOverrideAllResolvers(key, value); + } + else + { + SetValueInterleavedWithResolvers(key, value); + } + } - if (kind == SetValueKind.OverrideAllResolvers) + private void SetValueOverrideAllResolvers(string key, object value) { - SetValueOverrideAllResolvers(key, value); + _context.Remove(key); + _context.Add(key, value); } - else + + private void SetValueInterleavedWithResolvers(string key, object value) { - SetValueInterleavedWithResolvers(key, value); + RegisterResolver("this", name => ResolveInterleaved(name, key, value)); } - } - private void SetValueOverrideAllResolvers(string key, object value) - { - _context.Remove(key); - _context.Add(key, value); - } - - private void SetValueInterleavedWithResolvers(string key, object value) - { - RegisterResolver("this", name => ResolveInterleaved(name, key, value)); - } - - private object? ResolveInterleaved(string name, string key, object value) - { - return name == "context.keys" - ? key - : name == key - ? value - : null; - } + private object? ResolveInterleaved(string name, string key, object value) + { + return name == "context.keys" + ? key + : name == key + ? value + : null; + } - public string RegisterResolver(string name, Func resolver) - { - lock (_resolvers) + public string RegisterResolver(string name, Func resolver) { - var number = 0; - for (;;) + lock (_resolvers) { - var key = $"{name}{number++}"; - if (_resolvers.TryAdd(key, resolver)) + var number = 0; + for (; ; ) { - return key; + var key = $"{name}{number++}"; + if (_resolvers.TryAdd(key, resolver)) + { + return key; + } } } } - } - - public string? Resolve(string? text, bool deleteUnresolved = false) - { - if (IsVerbatimString(text)) return GetVerbatimString(text!); - if (string.IsNullOrEmpty(text) || !text.Contains('{')) return text; - var i = 0; - var resolved = new StringBuilder(); - while (i < text.Length) + public string? Resolve(string? text, bool deleteUnresolved = false) { - if (text[i] == '{') - { - resolved.Append(Interpolate(text, ref i, deleteUnresolved)); - } - else if (text[i] == '$' && i + 1 < text.Length && text[i + 1] == '{') - { - i++; - resolved.Append(Interpolate(text, ref i, deleteUnresolved)); - } - else + if (IsVerbatimString(text)) return GetVerbatimString(text!); + if (string.IsNullOrEmpty(text) || !text.Contains('{')) return text; + + var i = 0; + var resolved = new StringBuilder(); + while (i < text.Length) { - resolved.Append(text[i]); - i++; + if (text[i] == '{') + { + resolved.Append(Interpolate(text, ref i, deleteUnresolved)); + } + else if (text[i] == '$' && i + 1 < text.Length && text[i + 1] == '{') + { + i++; + resolved.Append(Interpolate(text, ref i, deleteUnresolved)); + } + else + { + resolved.Append(text[i]); + i++; + } } - } - return resolved.ToString(); - } + return resolved.ToString(); + } - private bool IsVerbatimString(string? text) - { - return text != null && text.StartsWith("@\"") && text.EndsWith("\""); - } + private bool IsVerbatimString(string? text) + { + return text != null && text.StartsWith("@\"") && text.EndsWith("\""); + } - private string? GetVerbatimString(string text) - { - text = text.Substring(2); - return text.Substring(0, text.Length - 1); - } + private string? GetVerbatimString(string text) + { + text = text.Substring(2); + return text.Substring(0, text.Length - 1); + } - public IImage? ResolveImage(string? text) - { - if (!string.IsNullOrEmpty(text) && text.StartsWith('{') && text.EndsWith('}')) + public IImage? ResolveImage(string? text) { - var check = Get(text.Substring(1, text.Length - 2), null); - if (check != null && check is IImage) + if (!string.IsNullOrEmpty(text) && text.StartsWith('{') && text.EndsWith('}')) { - return check as IImage; + var check = Get(text.Substring(1, text.Length - 2), null); + if (check != null && check is IImage) + { + return check as IImage; + } } - } - return null; - } + return null; + } - private string Interpolate(string text, ref int i, bool deleteUnresolved) - { - if (text[i] != '{') throw new InvalidOperationException($"Interpolate() '{{' not found; pos={i}"); - i += 1; // skipping '{' + private string Interpolate(string text, ref int i, bool deleteUnresolved) + { + if (text[i] != '{') throw new InvalidOperationException($"Interpolate() '{{' not found; pos={i}"); + i += 1; // skipping '{' - var sb = new StringBuilder(); + var sb = new StringBuilder(); - while (i < text.Length && text[i] != '}') - { - if (text[i] == '{') - { - sb.Append(Interpolate(text, ref i, deleteUnresolved)); - } - else if (text[i] == '$' && i + 1 < text.Length && text[i + 1] == '{') - { - i++; - sb.Append(Interpolate(text, ref i, deleteUnresolved)); - } - else + while (i < text.Length && text[i] != '}') { - sb.Append(text[i]); - i++; + if (text[i] == '{') + { + sb.Append(Interpolate(text, ref i, deleteUnresolved)); + } + else if (text[i] == '$' && i + 1 < text.Length && text[i + 1] == '{') + { + i++; + sb.Append(Interpolate(text, ref i, deleteUnresolved)); + } + else + { + sb.Append(text[i]); + i++; + } } - } - - if (text[i] != '}') throw new InvalidOperationException($"Interpolate() '}}' not found; pos={i}"); - i += 1; // skipping '}' - var name = sb.ToString(); - var resolved = Get(name, null); + if (text[i] != '}') throw new InvalidOperationException($"Interpolate() '}}' not found; pos={i}"); + i += 1; // skipping '}' - var list = resolved as IEnumerable; - if (list != null) return string.Join('\n', list); + var name = sb.ToString(); + var resolved = Get(name, null); - var str = resolved as string; - str ??= resolved?.ToString(); - if (str != null) return str; + var list = resolved as IEnumerable; + if (list != null) return string.Join('\n', list); - if (name.EndsWith(".value")) - { - var check = name.Substring(0, name.Length - ".value".Length); - resolved = Get(check, null); + var str = resolved as string; + str ??= resolved?.ToString(); + if (str != null) return str; - if (resolved != null && resolved is string) + if (name.EndsWith(".value")) { - var match = resolved as string; - list = Get($"values.{check}", null) as IEnumerable; - if (list != null) - { - var z = list.ToList(); - match = list.First(x => string.Compare(x.Before(':'), match, StringComparison.OrdinalIgnoreCase) == 0); - } + var check = name.Substring(0, name.Length - ".value".Length); + resolved = Get(check, null); - if (match != null) + if (resolved != null && resolved is string) { - return match.After(':'); + var match = resolved as string; + list = Get($"values.{check}", null) as IEnumerable; + if (list != null) + { + var z = list.ToList(); + match = list.First(x => string.Compare(x.Before(':'), match, StringComparison.OrdinalIgnoreCase) == 0); + } + + if (match != null) + { + return match.After(':'); + } } } - } - return deleteUnresolved ? string.Empty : $"{{{name}}}"; - } - - private string GetAll(string key) - { - var sb = new StringBuilder(); - sb.AppendLine(string.Join('\n', _context.Keys)); + return deleteUnresolved ? string.Empty : $"{{{name}}}"; + } - foreach (var resolver in _resolvers.Values.Reverse()) + private string GetAll(string key) { - var resolved = resolver != null ? resolver(key) : null; - if (resolved != null) - { - var list = resolved as IEnumerable; - if (list != null) - { - sb.Append(string.Join('\n', list)); - continue; - } + var sb = new StringBuilder(); + sb.AppendLine(string.Join('\n', _context.Keys)); - var str = resolved as string; - str ??= resolved?.ToString(); - if (str != null) + foreach (var resolver in _resolvers.Values.Reverse()) + { + var resolved = resolver != null ? resolver(key) : null; + if (resolved != null) { - sb.AppendLine(str); - continue; + var list = resolved as IEnumerable; + if (list != null) + { + sb.Append(string.Join('\n', list)); + continue; + } + + var str = resolved as string; + str ??= resolved?.ToString(); + if (str != null) + { + sb.AppendLine(str); + continue; + } } } - } - var items = sb.ToString() - .Split("\n\r".ToCharArray(), StringSplitOptions.RemoveEmptyEntries) - .Distinct() - .ToList(); - items.Sort(); + var items = sb.ToString() + .Split("\n\r".ToCharArray(), StringSplitOptions.RemoveEmptyEntries) + .Distinct() + .ToList(); + items.Sort(); - return string.Join('\n', items); - } + return string.Join('\n', items); + } - private Dictionary _context = new(); - private Dictionary> _resolvers = new(); -} + private Dictionary _context = new Dictionary(); + private Dictionary> _resolvers = new Dictionary>(); + } +} \ No newline at end of file diff --git a/src/cs/Helpers/SingleThreadedApartmentTaskScheduler.cs b/src/cs/Helpers/SingleThreadedApartmentTaskScheduler.cs index 8e9cb11f..ba108928 100644 --- a/src/cs/Helpers/SingleThreadedApartmentTaskScheduler.cs +++ b/src/cs/Helpers/SingleThreadedApartmentTaskScheduler.cs @@ -1,98 +1,101 @@ -namespace macaroni; +using System.Threading; +using System.Threading.Tasks; -using System; -using System.Collections.Generic; - -internal class SingleThreadedApartmentTaskScheduler : TaskScheduler +namespace macaroni { - public sealed override int MaximumConcurrencyLevel - { - get { return 1; } - } + using System; + using System.Collections.Generic; - protected sealed override void QueueTask(Task task) + internal class SingleThreadedApartmentTaskScheduler : TaskScheduler { - lock (_tasks) + public sealed override int MaximumConcurrencyLevel { - EnsureStart(); - _tasks.AddLast(task); - Monitor.Pulse(_tasks); + get { return 1; } } - } - private void EnsureStart() - { - if (_thread == null) + protected sealed override void QueueTask(Task task) { - _thread = new Thread(_ => ThreadProc()); - - #pragma warning disable CA1416 - if (OS.IsWindows()) _thread.SetApartmentState(ApartmentState.STA); - #pragma warning restore CA1416 - - _thread.Start(); + lock (_tasks) + { + EnsureStart(); + _tasks.AddLast(task); + Monitor.Pulse(_tasks); + } } - } - private void ThreadProc() - { - do + private void EnsureStart() { - var task = GetTask(); - base.TryExecuteTask(task); + if (_thread == null) + { + _thread = new Thread(_ => ThreadProc()); + +#pragma warning disable CA1416 + if (OS.IsWindows()) _thread.SetApartmentState(ApartmentState.STA); +#pragma warning restore CA1416 + + _thread.Start(); + } } - while (true); - } - private Task GetTask() - { - lock (_tasks) + private void ThreadProc() { - if (_tasks.Count == 0) + do { - Monitor.Wait(_tasks); + var task = GetTask(); + base.TryExecuteTask(task); } + while (true); + } - var next = _tasks.First; - if (next != null && next.Value != null) + private Task GetTask() + { + lock (_tasks) { - _tasks.RemoveFirst(); - return next.Value; - } - } + if (_tasks.Count == 0) + { + Monitor.Wait(_tasks); + } - throw new NotImplementedException(); - } + var next = _tasks.First; + if (next != null && next.Value != null) + { + _tasks.RemoveFirst(); + return next.Value; + } + } - protected sealed override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) - { - return false; - } + throw new NotImplementedException(); + } - protected sealed override bool TryDequeue(Task task) - { - lock (_tasks) + protected sealed override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) { - return _tasks.Remove(task); + return false; } - } - protected sealed override IEnumerable GetScheduledTasks() - { - bool lockTaken = false; - try + protected sealed override bool TryDequeue(Task task) { - Monitor.TryEnter(_tasks, ref lockTaken); - if (lockTaken) return _tasks; - else throw new NotSupportedException(); + lock (_tasks) + { + return _tasks.Remove(task); + } } - finally + + protected sealed override IEnumerable GetScheduledTasks() { - if (lockTaken) Monitor.Exit(_tasks); + bool lockTaken = false; + try + { + Monitor.TryEnter(_tasks, ref lockTaken); + if (lockTaken) return _tasks; + else throw new NotSupportedException(); + } + finally + { + if (lockTaken) Monitor.Exit(_tasks); + } } - } - - private Thread? _thread; - private readonly LinkedList _tasks = new LinkedList(); -} + private Thread? _thread; + private readonly LinkedList _tasks = new LinkedList(); + } +} \ No newline at end of file diff --git a/src/cs/Helpers/WindowHelpers.cs b/src/cs/Helpers/WindowHelpers.cs index 93dc0352..56fda67f 100644 --- a/src/cs/Helpers/WindowHelpers.cs +++ b/src/cs/Helpers/WindowHelpers.cs @@ -1,333 +1,337 @@ +using System; +using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Runtime.InteropServices; -using System.Text; +using macaroni.interop; -namespace macaroni; - -public class WindowHelpers +namespace macaroni { - public static IntPtr FindByTitleAndProcess(string? titleOrProcess, string? title, string? process, string? exclude) - { - var currentProcessId = Process.GetCurrentProcess().Id; - var checkWindows = WindowInfo.GetVisibleWindows().Where(x => x.Value.ProcessId != currentProcessId).ToList(); - - var match = checkWindows.FirstOrDefault(x => WindowInfo.TitleAndProcessMatch(x.Value, titleOrProcess, title, process, Split(exclude))); - return match.Key; - } - - public static IEnumerable FindAllByTitleAndProcess(string? titleOrProcess, string? title, string? process, string? exclude) - { - var currentProcessId = Process.GetCurrentProcess().Id; - var checkWindows = WindowInfo.GetVisibleWindows().Where(x => x.Value.ProcessId != currentProcessId).ToList(); - - return checkWindows - .Where(x => WindowInfo.TitleAndProcessMatch(x.Value, titleOrProcess, title, process, Split(exclude))) - .Select(x => x.Key); - } - - public static IntPtr FindByTitle(string title) - { - var currentProcessId = Process.GetCurrentProcess().Id; - var checkWindows = WindowInfo.GetVisibleWindows().Where(x => x.Value.ProcessId != currentProcessId).ToList(); - - var match = checkWindows.FirstOrDefault(x => WindowInfo.TitleMatches(x.Value, null, title)); - return match.Key; - } - - public static IntPtr FindByProcess(string? process) - { - var currentProcessId = Process.GetCurrentProcess().Id; - var checkWindows = WindowInfo.GetVisibleWindows().Where(x => x.Value.ProcessId != currentProcessId).ToList(); - - var match = checkWindows.FirstOrDefault(x => WindowInfo.ProcessMatches(x.Value, null, process)); - return match.Key; - } - - public static bool Restore(IntPtr hwnd) - { - return ShowWindow(hwnd, ShowWindowCommands.Restore) && SetForegroundWindow(hwnd); - } - - public static bool Minimize(IntPtr hwnd) - { - return ShowWindow(hwnd, ShowWindowCommands.Minimize); - } - - public static bool Maximize(IntPtr hwnd) - { - return ShowWindow(hwnd, ShowWindowCommands.Maximize); - } - - public static bool Close(IntPtr hwnd) - { - const uint WM_CLOSE = 0x0010; - return PostMessage(hwnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero); - } - - private static IEnumerable? Split(string? multiline) + public class WindowHelpers { - return multiline != null - ? multiline.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) - : null; - } - - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool SetForegroundWindow(IntPtr hWnd); - - [DllImport("user32.dll")] - public static extern IntPtr GetForegroundWindow(); - - [DllImport("user32.dll")] - public static extern bool ShowWindow(IntPtr hWnd, ShowWindowCommands nCmdShow); - - [return: MarshalAs(UnmanagedType.Bool)] - [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] - public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); - - [StructLayout(LayoutKind.Sequential)] - public struct RECT - { - public int Left, Top, Right, Bottom; - - public RECT(int left, int top, int right, int bottom) + public static IntPtr FindByTitleAndProcess(string? titleOrProcess, string? title, string? process, string? exclude) { - Left = left; - Top = top; - Right = right; - Bottom = bottom; - } - - public RECT(System.Drawing.Rectangle r) : this(r.Left, r.Top, r.Right, r.Bottom) { } + var currentProcessId = Process.GetCurrentProcess().Id; + var checkWindows = WindowInfo.GetVisibleWindows().Where(x => x.Value.ProcessId != currentProcessId).ToList(); - public int X - { - get { return Left; } - set { Right -= (Left - value); Left = value; } + var match = checkWindows.FirstOrDefault(x => WindowInfo.TitleAndProcessMatch(x.Value, titleOrProcess, title, process, Split(exclude))); + return match.Key; } - public int Y + public static IEnumerable FindAllByTitleAndProcess(string? titleOrProcess, string? title, string? process, string? exclude) { - get { return Top; } - set { Bottom -= (Top - value); Top = value; } - } + var currentProcessId = Process.GetCurrentProcess().Id; + var checkWindows = WindowInfo.GetVisibleWindows().Where(x => x.Value.ProcessId != currentProcessId).ToList(); - public int Height - { - get { return Bottom - Top; } - set { Bottom = value + Top; } + return checkWindows + .Where(x => WindowInfo.TitleAndProcessMatch(x.Value, titleOrProcess, title, process, Split(exclude))) + .Select(x => x.Key); } - public int Width + public static IntPtr FindByTitle(string title) { - get { return Right - Left; } - set { Right = value + Left; } - } + var currentProcessId = Process.GetCurrentProcess().Id; + var checkWindows = WindowInfo.GetVisibleWindows().Where(x => x.Value.ProcessId != currentProcessId).ToList(); - public System.Drawing.Point Location - { - get { return new System.Drawing.Point(Left, Top); } - set { X = value.X; Y = value.Y; } + var match = checkWindows.FirstOrDefault(x => WindowInfo.TitleMatches(x.Value, null, title)); + return match.Key; } - public System.Drawing.Size Size + public static IntPtr FindByProcess(string? process) { - get { return new System.Drawing.Size(Width, Height); } - set { Width = value.Width; Height = value.Height; } - } + var currentProcessId = Process.GetCurrentProcess().Id; + var checkWindows = WindowInfo.GetVisibleWindows().Where(x => x.Value.ProcessId != currentProcessId).ToList(); - public static implicit operator System.Drawing.Rectangle(RECT r) - { - return new System.Drawing.Rectangle(r.Left, r.Top, r.Width, r.Height); + var match = checkWindows.FirstOrDefault(x => WindowInfo.ProcessMatches(x.Value, null, process)); + return match.Key; } - public static implicit operator RECT(System.Drawing.Rectangle r) + public static bool Restore(IntPtr hwnd) { - return new RECT(r); + return ShowWindow(hwnd, ShowWindowCommands.Restore) && SetForegroundWindow(hwnd); } - public static bool operator ==(RECT r1, RECT r2) + public static bool Minimize(IntPtr hwnd) { - return r1.Equals(r2); + return ShowWindow(hwnd, ShowWindowCommands.Minimize); } - public static bool operator !=(RECT r1, RECT r2) + public static bool Maximize(IntPtr hwnd) { - return !r1.Equals(r2); + return ShowWindow(hwnd, ShowWindowCommands.Maximize); } - public bool Equals(RECT r) + public static bool Close(IntPtr hwnd) { - return r.Left == Left && r.Top == Top && r.Right == Right && r.Bottom == Bottom; + const uint WM_CLOSE = 0x0010; + return PostMessage(hwnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero); } - public override bool Equals(object? obj) + private static IEnumerable? Split(string? multiline) { - if (obj is RECT) - return Equals((RECT)obj); - else if (obj is System.Drawing.Rectangle) - return Equals(new RECT((System.Drawing.Rectangle)obj)); - return false; + return multiline != null + ? multiline.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) + : null; } - public override int GetHashCode() - { - return ((System.Drawing.Rectangle)this).GetHashCode(); - } + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetForegroundWindow(IntPtr hWnd); - public override string ToString() - { - return string.Format(System.Globalization.CultureInfo.CurrentCulture, "{{Left={0},Top={1},Right={2},Bottom={3}}}", Left, Top, Right, Bottom); - } - } + [DllImport("user32.dll")] + public static extern IntPtr GetForegroundWindow(); - [StructLayout(LayoutKind.Sequential)] - public struct POINT - { - public int X; - public int Y; + [DllImport("user32.dll")] + public static extern bool ShowWindow(IntPtr hWnd, ShowWindowCommands nCmdShow); + + [return: MarshalAs(UnmanagedType.Bool)] + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); - public POINT(int x, int y) + [StructLayout(LayoutKind.Sequential)] + public struct RECT { - this.X = x; - this.Y = y; + public int Left, Top, Right, Bottom; + + public RECT(int left, int top, int right, int bottom) + { + Left = left; + Top = top; + Right = right; + Bottom = bottom; + } + + public RECT(System.Drawing.Rectangle r) : this(r.Left, r.Top, r.Right, r.Bottom) { } + + public int X + { + get { return Left; } + set { Right -= (Left - value); Left = value; } + } + + public int Y + { + get { return Top; } + set { Bottom -= (Top - value); Top = value; } + } + + public int Height + { + get { return Bottom - Top; } + set { Bottom = value + Top; } + } + + public int Width + { + get { return Right - Left; } + set { Right = value + Left; } + } + + public System.Drawing.Point Location + { + get { return new System.Drawing.Point(Left, Top); } + set { X = value.X; Y = value.Y; } + } + + public System.Drawing.Size Size + { + get { return new System.Drawing.Size(Width, Height); } + set { Width = value.Width; Height = value.Height; } + } + + public static implicit operator System.Drawing.Rectangle(RECT r) + { + return new System.Drawing.Rectangle(r.Left, r.Top, r.Width, r.Height); + } + + public static implicit operator RECT(System.Drawing.Rectangle r) + { + return new RECT(r); + } + + public static bool operator ==(RECT r1, RECT r2) + { + return r1.Equals(r2); + } + + public static bool operator !=(RECT r1, RECT r2) + { + return !r1.Equals(r2); + } + + public bool Equals(RECT r) + { + return r.Left == Left && r.Top == Top && r.Right == Right && r.Bottom == Bottom; + } + + public override bool Equals(object? obj) + { + if (obj is RECT) + return Equals((RECT)obj); + else if (obj is System.Drawing.Rectangle) + return Equals(new RECT((System.Drawing.Rectangle)obj)); + return false; + } + + public override int GetHashCode() + { + return ((System.Drawing.Rectangle)this).GetHashCode(); + } + + public override string ToString() + { + return string.Format(System.Globalization.CultureInfo.CurrentCulture, "{{Left={0},Top={1},Right={2},Bottom={3}}}", Left, Top, Right, Bottom); + } } - public static implicit operator System.Drawing.Point(POINT p) + [StructLayout(LayoutKind.Sequential)] + public struct POINT { - return new System.Drawing.Point(p.X, p.Y); + public int X; + public int Y; + + public POINT(int x, int y) + { + this.X = x; + this.Y = y; + } + + public static implicit operator System.Drawing.Point(POINT p) + { + return new System.Drawing.Point(p.X, p.Y); + } + + public static implicit operator POINT(System.Drawing.Point p) + { + return new POINT(p.X, p.Y); + } } - public static implicit operator POINT(System.Drawing.Point p) + public enum ShowWindowCommands { - return new POINT(p.X, p.Y); + /// + /// Hides the window and activates another window. + /// + Hide = 0, + /// + /// Activates and displays a window. If the window is minimized or + /// maximized, the system restores it to its original size and position. + /// An application should specify this flag when displaying the window + /// for the first time. + /// + Normal = 1, + /// + /// Activates the window and displays it as a minimized window. + /// + ShowMinimized = 2, + /// + /// Maximizes the specified window. + /// + Maximize = 3, // is this the right value? + /// + /// Activates the window and displays it as a maximized window. + /// + ShowMaximized = 3, + /// + /// Displays a window in its most recent size and position. This value + /// is similar to , except + /// the window is not activated. + /// + ShowNoActivate = 4, + /// + /// Activates the window and displays it in its current size and position. + /// + Show = 5, + /// + /// Minimizes the specified window and activates the next top-level + /// window in the Z order. + /// + Minimize = 6, + /// + /// Displays the window as a minimized window. This value is similar to + /// , except the + /// window is not activated. + /// + ShowMinNoActive = 7, + /// + /// Displays the window in its current size and position. This value is + /// similar to , except the + /// window is not activated. + /// + ShowNA = 8, + /// + /// Activates and displays the window. If the window is minimized or + /// maximized, the system restores it to its original size and position. + /// An application should specify this flag when restoring a minimized window. + /// + Restore = 9, + /// + /// Sets the show state based on the SW_* value specified in the + /// STARTUPINFO structure passed to the CreateProcess function by the + /// program that started the application. + /// + ShowDefault = 10, + /// + /// Windows 2000/XP: Minimizes a window, even if the thread + /// that owns the window is not responding. This flag should only be + /// used when minimizing windows from a different thread. + /// + ForceMinimize = 11 } - } - - public enum ShowWindowCommands - { - /// - /// Hides the window and activates another window. - /// - Hide = 0, - /// - /// Activates and displays a window. If the window is minimized or - /// maximized, the system restores it to its original size and position. - /// An application should specify this flag when displaying the window - /// for the first time. - /// - Normal = 1, - /// - /// Activates the window and displays it as a minimized window. - /// - ShowMinimized = 2, - /// - /// Maximizes the specified window. - /// - Maximize = 3, // is this the right value? - /// - /// Activates the window and displays it as a maximized window. - /// - ShowMaximized = 3, - /// - /// Displays a window in its most recent size and position. This value - /// is similar to , except - /// the window is not activated. - /// - ShowNoActivate = 4, - /// - /// Activates the window and displays it in its current size and position. - /// - Show = 5, - /// - /// Minimizes the specified window and activates the next top-level - /// window in the Z order. - /// - Minimize = 6, - /// - /// Displays the window as a minimized window. This value is similar to - /// , except the - /// window is not activated. - /// - ShowMinNoActive = 7, - /// - /// Displays the window in its current size and position. This value is - /// similar to , except the - /// window is not activated. - /// - ShowNA = 8, - /// - /// Activates and displays the window. If the window is minimized or - /// maximized, the system restores it to its original size and position. - /// An application should specify this flag when restoring a minimized window. - /// - Restore = 9, - /// - /// Sets the show state based on the SW_* value specified in the - /// STARTUPINFO structure passed to the CreateProcess function by the - /// program that started the application. - /// - ShowDefault = 10, - /// - /// Windows 2000/XP: Minimizes a window, even if the thread - /// that owns the window is not responding. This flag should only be - /// used when minimizing windows from a different thread. - /// - ForceMinimize = 11 - } - [Serializable] - [StructLayout(LayoutKind.Sequential)] - public struct WINDOWPLACEMENT - { - /// - /// The length of the structure, in bytes. Before calling the GetWindowPlacement or SetWindowPlacement functions, set this member to sizeof(WINDOWPLACEMENT). - /// - /// GetWindowPlacement and SetWindowPlacement fail if this member is not set correctly. - /// - /// - public int Length; - - /// - /// Specifies flags that control the position of the minimized window and the method by which the window is restored. - /// - public int Flags; - - /// - /// The current show state of the window. - /// - public ShowWindowCommands ShowCmd; - - /// - /// The coordinates of the window's upper-left corner when the window is minimized. - /// - public POINT MinPosition; - - /// - /// The coordinates of the window's upper-left corner when the window is maximized. - /// - public POINT MaxPosition; - - /// - /// The window's coordinates when the window is in the restored position. - /// - public RECT NormalPosition; - - /// - /// Gets the default (empty) value. - /// - public static WINDOWPLACEMENT Default + [Serializable] + [StructLayout(LayoutKind.Sequential)] + public struct WINDOWPLACEMENT { - get + /// + /// The length of the structure, in bytes. Before calling the GetWindowPlacement or SetWindowPlacement functions, set this member to sizeof(WINDOWPLACEMENT). + /// + /// GetWindowPlacement and SetWindowPlacement fail if this member is not set correctly. + /// + /// + public int Length; + + /// + /// Specifies flags that control the position of the minimized window and the method by which the window is restored. + /// + public int Flags; + + /// + /// The current show state of the window. + /// + public ShowWindowCommands ShowCmd; + + /// + /// The coordinates of the window's upper-left corner when the window is minimized. + /// + public POINT MinPosition; + + /// + /// The coordinates of the window's upper-left corner when the window is maximized. + /// + public POINT MaxPosition; + + /// + /// The window's coordinates when the window is in the restored position. + /// + public RECT NormalPosition; + + /// + /// Gets the default (empty) value. + /// + public static WINDOWPLACEMENT Default { - WINDOWPLACEMENT result = new WINDOWPLACEMENT(); - result.Length = Marshal.SizeOf(result); - return result; + get + { + WINDOWPLACEMENT result = new WINDOWPLACEMENT(); + result.Length = Marshal.SizeOf(result); + return result; + } } } - } - [DllImport("user32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl); -} + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl); + } +} \ No newline at end of file diff --git a/src/cs/Helpers/WindowInfo.cs b/src/cs/Helpers/WindowInfo.cs index ea7cd168..a5a5859f 100644 --- a/src/cs/Helpers/WindowInfo.cs +++ b/src/cs/Helpers/WindowInfo.cs @@ -1,141 +1,144 @@ -using System.Diagnostics; +using System; +using System.Collections.Generic; +using System.Linq; using System.Text; -namespace macaroni; - -public class WindowInfo +namespace macaroni { - public IntPtr hwnd; - public string? Title; - public string? Process; - public uint ProcessId; - - public override string ToString() + public class WindowInfo { - return $"{Process}\t{Title}"; - } + public IntPtr hwnd; + public string? Title; + public string? Process; + public uint ProcessId; - public static WindowInfo? FromHwnd(IntPtr hwnd) - { - if (hwnd == IntPtr.Zero) return null; + public override string ToString() + { + return $"{Process}\t{Title}"; + } - var title = TitleFromHwnd(hwnd); - var file = ProcessPathFromHwnd(hwnd, out uint id); - if (title == null || file == null) return null; + public static WindowInfo? FromHwnd(IntPtr hwnd) + { + if (hwnd == IntPtr.Zero) return null; - return new WindowInfo() { hwnd = hwnd, Process = file, ProcessId = id, Title = title }; - } + var title = TitleFromHwnd(hwnd); + var file = ProcessPathFromHwnd(hwnd, out uint id); + if (title == null || file == null) return null; - public static IDictionary GetVisibleWindows() - { - var shellWindow = window_interop.GetShellWindow(); - var windows = new Dictionary(); + return new WindowInfo() { hwnd = hwnd, Process = file, ProcessId = id, Title = title }; + } - window_interop.EnumWindows((hwnd, lparam) => + public static IDictionary GetVisibleWindows() { - if (hwnd == IntPtr.Zero) return true; - if (hwnd == shellWindow) return true; - if (!window_interop.IsWindowVisible(hwnd)) return true; + var shellWindow = window_interop.GetShellWindow(); + var windows = new Dictionary(); - var info = WindowInfo.FromHwnd(hwnd); - if (info == null) return true; + window_interop.EnumWindows((hwnd, lparam) => + { + if (hwnd == IntPtr.Zero) return true; + if (hwnd == shellWindow) return true; + if (!window_interop.IsWindowVisible(hwnd)) return true; - windows.Add(hwnd, info); - return true; - }, 0); + var info = WindowInfo.FromHwnd(hwnd); + if (info == null) return true; - return windows; - } + windows.Add(hwnd, info); + return true; + }, 0); - public static string? ProcessPathFromHwnd(IntPtr hwnd, out uint pid) - { - window_interop.GetWindowThreadProcessId(hwnd, out pid); - if (pid == 0) return null; + return windows; + } - var process = window_interop.OpenProcess(window_interop.PROCESS_QUERY_INFORMATION, false, pid); - if (process == IntPtr.Zero) return null; + public static string? ProcessPathFromHwnd(IntPtr hwnd, out uint pid) + { + window_interop.GetWindowThreadProcessId(hwnd, out pid); + if (pid == 0) return null; - var sb = new StringBuilder(1024); - window_interop.GetProcessImageFileName(process, sb, sb.Capacity); - window_interop.CloseHandle(process); + var process = window_interop.OpenProcess(window_interop.PROCESS_QUERY_INFORMATION, false, pid); + if (process == IntPtr.Zero) return null; - return sb.Length > 0 ? sb.ToString() : null; - } + var sb = new StringBuilder(1024); + window_interop.GetProcessImageFileName(process, sb, sb.Capacity); + window_interop.CloseHandle(process); - public static string? TitleFromHwnd(IntPtr hwnd) - { - var length = window_interop.GetWindowTextLength(hwnd); - if (length == 0) return null; + return sb.Length > 0 ? sb.ToString() : null; + } - var title = new StringBuilder(length + 1); - window_interop.GetWindowText(hwnd, title, length + 1); + public static string? TitleFromHwnd(IntPtr hwnd) + { + var length = window_interop.GetWindowTextLength(hwnd); + if (length == 0) return null; - return title.ToString(); - } + var title = new StringBuilder(length + 1); + window_interop.GetWindowText(hwnd, title, length + 1); - public static bool TitleAndProcessMatch(IntPtr hwnd, string? titleOrProcess, string? title, string? process, IEnumerable? exclude) - { - var info = FromHwnd(hwnd); - return info != null && TitleAndProcessMatch(info, titleOrProcess, title, process, exclude); - } + return title.ToString(); + } - public static bool TitleAndProcessMatch(WindowInfo info, string? titleOrProcess, string? title, string? process, IEnumerable? exclude) - { - bool titleOk = TitleMatches(info, exclude, titleOrProcess, title); - bool processOk = ProcessMatches(info, exclude, titleOrProcess, process); + public static bool TitleAndProcessMatch(IntPtr hwnd, string? titleOrProcess, string? title, string? process, IEnumerable? exclude) + { + var info = FromHwnd(hwnd); + return info != null && TitleAndProcessMatch(info, titleOrProcess, title, process, exclude); + } - return (title == null || titleOk) && - (process == null || processOk) && - (titleOrProcess == null || titleOk || processOk); - } + public static bool TitleAndProcessMatch(WindowInfo info, string? titleOrProcess, string? title, string? process, IEnumerable? exclude) + { + bool titleOk = TitleMatches(info, exclude, titleOrProcess, title); + bool processOk = ProcessMatches(info, exclude, titleOrProcess, process); - public static bool ProcessMatches(WindowInfo info, IEnumerable? exclude, params string?[] check) - { - return info.Process != null && check.Any(process => ProcessMatches(info, process, exclude)); - } + return (title == null || titleOk) && + (process == null || processOk) && + (titleOrProcess == null || titleOk || processOk); + } - public static bool TitleMatches(WindowInfo info, IEnumerable? exclude, params string?[] check) - { - return info.Title != null && check.Any(title => TitleMatches(info, title, exclude)); - } + public static bool ProcessMatches(WindowInfo info, IEnumerable? exclude, params string?[] check) + { + return info.Process != null && check.Any(process => ProcessMatches(info, process, exclude)); + } - private static bool ProcessMatches(WindowInfo info, string? process, IEnumerable? exclude) - { - return ProcessMatches(info, process) && !ShouldExcludeProcess(info, exclude); - } + public static bool TitleMatches(WindowInfo info, IEnumerable? exclude, params string?[] check) + { + return info.Title != null && check.Any(title => TitleMatches(info, title, exclude)); + } - private static bool TitleMatches(WindowInfo info, string? title, IEnumerable? exclude) - { - return TitleMatches(info, title) && !ShouldExcludeTitle(info, exclude); - } + private static bool ProcessMatches(WindowInfo info, string? process, IEnumerable? exclude) + { + return ProcessMatches(info, process) && !ShouldExcludeProcess(info, exclude); + } - private static bool ProcessMatches(WindowInfo info, string? process) - { - return !string.IsNullOrEmpty(process) && info.Process!.Contains(process, StringComparison.InvariantCultureIgnoreCase); - } + private static bool TitleMatches(WindowInfo info, string? title, IEnumerable? exclude) + { + return TitleMatches(info, title) && !ShouldExcludeTitle(info, exclude); + } - private static bool TitleMatches(WindowInfo info, string? title) - { - return !string.IsNullOrEmpty(title) && info.Title!.Contains(title, StringComparison.InvariantCultureIgnoreCase); - } + private static bool ProcessMatches(WindowInfo info, string? process) + { + return !string.IsNullOrEmpty(process) && info.Process!.Contains(process, StringComparison.InvariantCultureIgnoreCase); + } - private static bool ShouldExcludeProcess(WindowInfo info, IEnumerable? exclude) - { - return exclude != null && exclude.Any(x => ShouldExcludeProcess(info, x)); - } + private static bool TitleMatches(WindowInfo info, string? title) + { + return !string.IsNullOrEmpty(title) && info.Title!.Contains(title, StringComparison.InvariantCultureIgnoreCase); + } - private static bool ShouldExcludeTitle(WindowInfo info, IEnumerable? exclude) - { - return exclude != null && exclude.Any(x => ShouldExcludeTitle(info, x)); - } + private static bool ShouldExcludeProcess(WindowInfo info, IEnumerable? exclude) + { + return exclude != null && exclude.Any(x => ShouldExcludeProcess(info, x)); + } - private static bool ShouldExcludeProcess(WindowInfo info, string exclude) - { - return !string.IsNullOrEmpty(exclude) && info.Process!.Contains(exclude, StringComparison.InvariantCultureIgnoreCase); - } + private static bool ShouldExcludeTitle(WindowInfo info, IEnumerable? exclude) + { + return exclude != null && exclude.Any(x => ShouldExcludeTitle(info, x)); + } - private static bool ShouldExcludeTitle(WindowInfo info, string exclude) - { - return !string.IsNullOrEmpty(exclude) && info.Title!.Contains(exclude, StringComparison.InvariantCultureIgnoreCase); + private static bool ShouldExcludeProcess(WindowInfo info, string exclude) + { + return !string.IsNullOrEmpty(exclude) && info.Process!.Contains(exclude, StringComparison.InvariantCultureIgnoreCase); + } + + private static bool ShouldExcludeTitle(WindowInfo info, string exclude) + { + return !string.IsNullOrEmpty(exclude) && info.Title!.Contains(exclude, StringComparison.InvariantCultureIgnoreCase); + } } -} +} \ No newline at end of file diff --git a/src/cs/Helpers/YamlParserBase.cs b/src/cs/Helpers/YamlParserBase.cs index a6a1f5dc..6a942ae3 100644 --- a/src/cs/Helpers/YamlParserBase.cs +++ b/src/cs/Helpers/YamlParserBase.cs @@ -1,382 +1,387 @@ -global using YamlDotNet.RepresentationModel; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using YamlDotNet.RepresentationModel; using YamlDotNet.Serialization; -namespace macaroni; - -public class YamlParserBase +namespace macaroni { - protected YamlParserBase(IResolutionContext context) - { - _context = context; - } - - protected YamlStream ParseYamlStream(string file) - { - using var reader = File.OpenText(file); - return ParseYamlStream(file, reader); - } - - protected YamlStream ParseYamlStream(string documentName, TextReader text) + public class YamlParserBase { - var stream = new YamlStream(); - try + protected YamlParserBase(IResolutionContext context) { - stream.Load(text); - return stream; + _context = context; } - catch (YamlDotNet.Core.YamlException ex) + + protected YamlStream ParseYamlStream(string file) { - throw ErrorParsingYamlException(documentName, ex.Start.Line, ex.Start.Column, $"Unexpected YamlException ({ex.GetType().Name})", ex.Message); + using var reader = File.OpenText(file); + return ParseYamlStream(file, reader); } - catch (Exception ex) + + protected YamlStream ParseYamlStream(string documentName, TextReader text) { - throw ErrorParsingYamlException(documentName, $"Unexpected Exception ({ex.GetType()})", ex.Message); + var stream = new YamlStream(); + try + { + stream.Load(text); + return stream; + } + catch (YamlDotNet.Core.YamlException ex) + { + throw ErrorParsingYamlException(documentName, ex.Start.Line, ex.Start.Column, $"Unexpected YamlException ({ex.GetType().Name})", ex.Message); + } + catch (Exception ex) + { + throw ErrorParsingYamlException(documentName, $"Unexpected Exception ({ex.GetType()})", ex.Message); + } } - } - protected IEnumerable RequireSequenceOf(string file, YamlSequenceNode sequence, string kindOfSequence, Func factory, Func errorUnexpectedNode) - { - var items = sequence.Children.SelectMany(node => RequireTemplateSequenceOrOneOf(file, node, kindOfSequence, factory, errorUnexpectedNode)).ToList(); - return items.Count() == 0 - ? throw errorUnexpectedNode(file, sequence) - : items; - } - - protected IEnumerable RequireTemplateSequenceOrOneOf(string file, YamlNode node, string kindOfSequence, Func factory, Func unexpectedNodeError) - { - var sequence = CheckForTemplateSequence(ref file, node, kindOfSequence, out YamlNode? callerSpecifiedParameters); - return sequence == null - ? new[] { factory(file, node) } - : callerSpecifiedParameters == null - ? RequireSequenceOf(file, sequence, kindOfSequence, factory, unexpectedNodeError) - : RequireTemplateSequenceOf(file, sequence, kindOfSequence, callerSpecifiedParameters, factory, unexpectedNodeError); - } + protected IEnumerable RequireSequenceOf(string file, YamlSequenceNode sequence, string kindOfSequence, Func factory, Func errorUnexpectedNode) + { + var items = sequence.Children.SelectMany(node => RequireTemplateSequenceOrOneOf(file, node, kindOfSequence, factory, errorUnexpectedNode)).ToList(); + return items.Count() == 0 + ? throw errorUnexpectedNode(file, sequence) + : items; + } - protected IEnumerable RequireTemplateSequenceOf(string file, YamlSequenceNode sequence, string kindOfSequence, YamlNode callerSpecifiedParameters, Func factory, Func unexpectedNodeError) - { - var foundBeforeReplacements = RequireSequenceOf(file, sequence, kindOfSequence, factory, unexpectedNodeError); - System.Diagnostics.Debug.Assert(foundBeforeReplacements.Count() >= 1); // ensure that without caller specified parameter replacements, it parses; this ensures error messages can be correct w.r.t. line numbers first + protected IEnumerable RequireTemplateSequenceOrOneOf(string file, YamlNode node, string kindOfSequence, Func factory, Func unexpectedNodeError) + { + var sequence = CheckForTemplateSequence(ref file, node, kindOfSequence, out YamlNode? callerSpecifiedParameters); + return sequence == null + ? new[] { factory(file, node) } + : callerSpecifiedParameters == null + ? RequireSequenceOf(file, sequence, kindOfSequence, factory, unexpectedNodeError) + : RequireTemplateSequenceOf(file, sequence, kindOfSequence, callerSpecifiedParameters, factory, unexpectedNodeError); + } - var writer = new StringWriter(); - var serializer = new SerializerBuilder().Build(); - serializer.Serialize(writer, sequence); - var yaml = writer.ToString(); + protected IEnumerable RequireTemplateSequenceOf(string file, YamlSequenceNode sequence, string kindOfSequence, YamlNode callerSpecifiedParameters, Func factory, Func unexpectedNodeError) + { + var foundBeforeReplacements = RequireSequenceOf(file, sequence, kindOfSequence, factory, unexpectedNodeError); + System.Diagnostics.Debug.Assert(foundBeforeReplacements.Count() >= 1); // ensure that without caller specified parameter replacements, it parses; this ensures error messages can be correct w.r.t. line numbers first - yaml = ReplaceTemplateParameters(callerSpecifiedParameters, yaml); + var writer = new StringWriter(); + var serializer = new SerializerBuilder().Build(); + serializer.Serialize(writer, sequence); + var yaml = writer.ToString(); - using var reader = new StringReader(yaml); - var parsed = ParseYamlStream(file, reader); - if (parsed.Documents.Count() != 1) throw ErrorTemplateContainsOneDocument(file, parsed); + yaml = ReplaceTemplateParameters(callerSpecifiedParameters, yaml); - var rootNode = parsed.Documents[0].RootNode; - var templateSequence = rootNode as YamlSequenceNode; - if (templateSequence == null) throw ErrorInvalidTemplateSequenceNodeType(file, rootNode, kindOfSequence, file); + using var reader = new StringReader(yaml); + var parsed = ParseYamlStream(file, reader); + if (parsed.Documents.Count() != 1) throw ErrorTemplateContainsOneDocument(file, parsed); - return RequireSequenceOf(file, templateSequence, kindOfSequence, factory, unexpectedNodeError); - } + var rootNode = parsed.Documents[0].RootNode; + var templateSequence = rootNode as YamlSequenceNode; + if (templateSequence == null) throw ErrorInvalidTemplateSequenceNodeType(file, rootNode, kindOfSequence, file); - protected YamlSequenceNode? CheckForTemplateSequence(ref string file, YamlNode node, string kindOfSequence, out YamlNode? callerSpecifiedParameters) - { - callerSpecifiedParameters = null; + return RequireSequenceOf(file, templateSequence, kindOfSequence, factory, unexpectedNodeError); + } - var mapping = node as YamlMappingNode; - if (mapping == null) return null; + protected YamlSequenceNode? CheckForTemplateSequence(ref string file, YamlNode node, string kindOfSequence, out YamlNode? callerSpecifiedParameters) + { + callerSpecifiedParameters = null; - var checkFileName = GetScalarString(file, mapping, "template", null, null); - if (checkFileName == null) return null; + var mapping = node as YamlMappingNode; + if (mapping == null) return null; - checkFileName = _context.Resolve(checkFileName); - if (string.IsNullOrEmpty(checkFileName)) return null; + var checkFileName = GetScalarString(file, mapping, "template", null, null); + if (checkFileName == null) return null; - var checkTemplateOverride = "{template:" + checkFileName + "}"; - var templateOverride = _context.Resolve(checkTemplateOverride, true); - var isTemplateOverride = !string.IsNullOrEmpty(templateOverride); + checkFileName = _context.Resolve(checkFileName); + if (string.IsNullOrEmpty(checkFileName)) return null; - var templateFileName = isTemplateOverride ? checkTemplateOverride : FileHelpers.AdjustRelativeFileName(file, checkFileName); - if (templateFileName == null) throw FileHelpers.ErrorFileNotFoundException(checkFileName); + var checkTemplateOverride = "{template:" + checkFileName + "}"; + var templateOverride = _context.Resolve(checkTemplateOverride, true); + var isTemplateOverride = !string.IsNullOrEmpty(templateOverride); - var parsed = isTemplateOverride - ? ParseYamlStream(templateFileName, new StringReader(templateOverride!)) - : ParseYamlStream(templateFileName); + var templateFileName = isTemplateOverride ? checkTemplateOverride : FileHelpers.AdjustRelativeFileName(file, checkFileName); + if (templateFileName == null) throw FileHelpers.ErrorFileNotFoundException(checkFileName); - if (parsed.Documents.Count() != 1) throw ErrorTemplateContainsOneDocument(templateFileName, parsed); + var parsed = isTemplateOverride + ? ParseYamlStream(templateFileName, new StringReader(templateOverride!)) + : ParseYamlStream(templateFileName); - var rootNode = parsed.Documents[0].RootNode; - var templateSequence = rootNode as YamlSequenceNode; - if (templateSequence == null) throw ErrorInvalidTemplateSequenceNodeType(templateFileName, rootNode, kindOfSequence, file); + if (parsed.Documents.Count() != 1) throw ErrorTemplateContainsOneDocument(templateFileName, parsed); - file = templateFileName; - callerSpecifiedParameters = mapping.Children.ContainsKey("parameters") - ? mapping.Children["parameters"] - : null; + var rootNode = parsed.Documents[0].RootNode; + var templateSequence = rootNode as YamlSequenceNode; + if (templateSequence == null) throw ErrorInvalidTemplateSequenceNodeType(templateFileName, rootNode, kindOfSequence, file); - return templateSequence; - } + file = templateFileName; + callerSpecifiedParameters = mapping.Children.ContainsKey("parameters") + ? mapping.Children["parameters"] + : null; - protected IEnumerable? GetScalarStrings(string file, YamlMappingNode mapping, string mappingName, IParsedValueWarningChecker? warnings) - { - var single = GetScalarString(file, mapping, mappingName, null, warnings); - if (single != null) return new[] { single }; + return templateSequence; + } - var sequence = mapping.Children.ContainsKey(mappingName) - ? mapping.Children[mappingName] as YamlSequenceNode - : null; + protected IEnumerable? GetScalarStrings(string file, YamlMappingNode mapping, string mappingName, IParsedValueWarningChecker? warnings) + { + var single = GetScalarString(file, mapping, mappingName, null, warnings); + if (single != null) return new[] { single }; - return GetScalarStrings(file, sequence, warnings); - } + var sequence = mapping.Children.ContainsKey(mappingName) + ? mapping.Children[mappingName] as YamlSequenceNode + : null; - protected IEnumerable? GetScalarStrings(string file, YamlSequenceNode? sequence, IParsedValueWarningChecker? warnings) - { - if (sequence == null) return null; - if (sequence.Children.Count() == 0) return null; + return GetScalarStrings(file, sequence, warnings); + } - return RequireSequenceOf(file, sequence, "string", - (file, node) => StringFromNode(file, node, warnings), - (file, node) => ExpectedSequenceOrStringValue(file, node)); - } + protected IEnumerable? GetScalarStrings(string file, YamlSequenceNode? sequence, IParsedValueWarningChecker? warnings) + { + if (sequence == null) return null; + if (sequence.Children.Count() == 0) return null; - protected string? GetScalarString(string file, YamlMappingNode mapping, string mappingName, string? defaultValue, IParsedValueWarningChecker? warnings) - { - var ok = mapping.Children.ContainsKey(mappingName); - if (!ok) return defaultValue; + return RequireSequenceOf(file, sequence, "string", + (file, node) => StringFromNode(file, node, warnings), + (file, node) => ExpectedSequenceOrStringValue(file, node)); + } - var node = mapping.Children[mappingName] as YamlScalarNode; - var value = node?.Value ?? defaultValue; + protected string? GetScalarString(string file, YamlMappingNode mapping, string mappingName, string? defaultValue, IParsedValueWarningChecker? warnings) + { + var ok = mapping.Children.ContainsKey(mappingName); + if (!ok) return defaultValue; - warnings?.CheckParsedValue(file, mappingName, node, value); + var node = mapping.Children[mappingName] as YamlScalarNode; + var value = node?.Value ?? defaultValue; - return value; - } + warnings?.CheckParsedValue(file, mappingName, node, value); - protected string StringFromNode(string file, YamlNode node, IParsedValueWarningChecker? warnings) - { - var scalar = node as YamlScalarNode; - if (scalar != null && scalar.Value != null) - { - warnings?.CheckParsedValue(file, null, scalar, scalar.Value); - return scalar.Value; + return value; } - var mapping = node as YamlMappingNode; - if (mapping != null && mapping.Children.Count == 1) + protected string StringFromNode(string file, YamlNode node, IParsedValueWarningChecker? warnings) { - var child = mapping.Children[0]; - var name = (child.Key as YamlScalarNode)?.Value; - var value = (child.Value as YamlScalarNode)?.Value; - if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(value)) + var scalar = node as YamlScalarNode; + if (scalar != null && scalar.Value != null) { - return $"{name}: {value}"; + warnings?.CheckParsedValue(file, null, scalar, scalar.Value); + return scalar.Value; } - } - return string.Empty; - } + var mapping = node as YamlMappingNode; + if (mapping != null && mapping.Children.Count == 1) + { + var child = mapping.Children[0]; + var name = (child.Key as YamlScalarNode)?.Value; + var value = (child.Value as YamlScalarNode)?.Value; + if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(value)) + { + return $"{name}: {value}"; + } + } - protected string RequireScalarStringValueNotNullOrEmpty(string file, string key, YamlScalarNode scalar, IParsedValueWarningChecker? warnings) - { - var value = scalar.Value; - if (string.IsNullOrEmpty(value)) - { - throw ExpectedStringValueNotNullOrEmpty(file, key, scalar); + return string.Empty; } - warnings?.CheckParsedValue(file, key, scalar, value); - - return value; - } + protected string RequireScalarStringValueNotNullOrEmpty(string file, string key, YamlScalarNode scalar, IParsedValueWarningChecker? warnings) + { + var value = scalar.Value; + if (string.IsNullOrEmpty(value)) + { + throw ExpectedStringValueNotNullOrEmpty(file, key, scalar); + } - protected string? RequireMappingStringValueNotNullIfPresent(string file, string parent, YamlMappingNode mapping, string key, IParsedValueWarningChecker? warnings) - { - var ok = mapping.Children.ContainsKey(key); - if (!ok) return null; + warnings?.CheckParsedValue(file, key, scalar, value); - return RequireMappingStringValueNotNull(file, parent, mapping, key, warnings); - } - - protected string? RequireMappingStringValueNotNull(string file, string parent, YamlMappingNode mapping, string key, IParsedValueWarningChecker? warnings) - { - var value = GetScalarString(file, mapping, key, null, warnings); - if (value == null) - { - throw ExpectedMappingStringValueException(file, parent, mapping, key); + return value; } - return value; - } - protected string? RequireMappingStringValueNotNullOrEmptyIfPresent(string file, string parent, YamlMappingNode mapping, string key, IParsedValueWarningChecker? warnings) - { - var ok = mapping.Children.ContainsKey(key); - if (!ok) return null; + protected string? RequireMappingStringValueNotNullIfPresent(string file, string parent, YamlMappingNode mapping, string key, IParsedValueWarningChecker? warnings) + { + var ok = mapping.Children.ContainsKey(key); + if (!ok) return null; - return RequireMappingStringValueNotNullOrEmpty(file, parent, mapping, key, warnings); - } + return RequireMappingStringValueNotNull(file, parent, mapping, key, warnings); + } - protected string RequireMappingStringValueNotNullOrEmpty(string file, string parent, YamlMappingNode mapping, string key, IParsedValueWarningChecker? warnings) - { - var value = GetScalarString(file, mapping, key, null, warnings); - if (value == null) + protected string? RequireMappingStringValueNotNull(string file, string parent, YamlMappingNode mapping, string key, IParsedValueWarningChecker? warnings) { - throw ExpectedMappingStringValueException(file, parent, mapping, key); + var value = GetScalarString(file, mapping, key, null, warnings); + if (value == null) + { + throw ExpectedMappingStringValueException(file, parent, mapping, key); + } + return value; } - else if (string.IsNullOrEmpty(value)) + + protected string? RequireMappingStringValueNotNullOrEmptyIfPresent(string file, string parent, YamlMappingNode mapping, string key, IParsedValueWarningChecker? warnings) { - throw ExpectedMappingStringValueNotNullOrEmptyException(file, parent, mapping, key); + var ok = mapping.Children.ContainsKey(key); + if (!ok) return null; + + return RequireMappingStringValueNotNullOrEmpty(file, parent, mapping, key, warnings); } - return value; - } - protected IEnumerable RequireSequenceOfStringsNotNullOrEmpty(string file, string key, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) - { - var phrases = GetScalarStrings(file, sequence, warnings); - if (phrases == null || phrases.Count(item => string.IsNullOrEmpty(item)) > 0) + protected string RequireMappingStringValueNotNullOrEmpty(string file, string parent, YamlMappingNode mapping, string key, IParsedValueWarningChecker? warnings) { - throw ExpectedSequenceOfStringsNotNullOrEmptyException(file, key, sequence); + var value = GetScalarString(file, mapping, key, null, warnings); + if (value == null) + { + throw ExpectedMappingStringValueException(file, parent, mapping, key); + } + else if (string.IsNullOrEmpty(value)) + { + throw ExpectedMappingStringValueNotNullOrEmptyException(file, parent, mapping, key); + } + return value; } - return phrases; - } - - protected void RequireNoUnexpectedMappingKeys(string file, YamlMappingNode? mapping, string parent, string[] keys) - { - if (mapping == null) return; - - foreach (var child in mapping.Children) + protected IEnumerable RequireSequenceOfStringsNotNullOrEmpty(string file, string key, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings) { - var scalar = child.Key as YamlScalarNode; - var key = scalar?.Value; - if (key != null && key != parent && !keys.Contains(key)) + var phrases = GetScalarStrings(file, sequence, warnings); + if (phrases == null || phrases.Count(item => string.IsNullOrEmpty(item)) > 0) { - throw ExpectedMappingKey(file, mapping, parent, key, keys); + throw ExpectedSequenceOfStringsNotNullOrEmptyException(file, key, sequence); } + + return phrases; } - } - protected Exception ExpectedMappingKey(string file, YamlMappingNode mapping, string parent, string key, string[] expectedKeys) - { - var keys = expectedKeys.Select(x => $"`{x}`"); - var expected = keys.Count() > 0 - ? string.Join(", ", keys) - : $"`{parent}` with nothing else"; - var node = mapping.Children.ContainsKey(key) ? mapping.Children[key] : mapping; - return ErrorParsingYamlException(file, node.Start.Line, node.Start.Column, $"When parsing `{parent}`, unexpected mapping key `{key}`", $"EXPECTED: {expected}"); - } + protected void RequireNoUnexpectedMappingKeys(string file, YamlMappingNode? mapping, string parent, string[] keys) + { + if (mapping == null) return; - protected Exception ExpectedMappingStringValueException(string file, string parent, YamlMappingNode mapping, string key) - { - var expected = $"`{key}: (string)`"; - var node = mapping.Children.ContainsKey(key) ? mapping.Children[key] : mapping; - return ErrorParsingYamlException(file, node.Start.Line, node.Start.Column, $"When parsing `{parent}`, missing `{key}` value", $"EXPECTED: {expected}"); - } + foreach (var child in mapping.Children) + { + var scalar = child.Key as YamlScalarNode; + var key = scalar?.Value; + if (key != null && key != parent && !keys.Contains(key)) + { + throw ExpectedMappingKey(file, mapping, parent, key, keys); + } + } + } - protected Exception ExpectedMappingStringValueNotNullOrEmptyException(string file, string parent, YamlMappingNode mapping, string key) - { - var expected = $"`{key}` (string) value must not be empty"; - var node = mapping.Children.ContainsKey(key) ? mapping.Children[key] : mapping; - return ErrorParsingYamlException(file, node.Start.Line, node.Start.Column, $"When parsing `{parent}`, missing `{key}` value", $"EXPECTED: {expected}"); - } + protected Exception ExpectedMappingKey(string file, YamlMappingNode mapping, string parent, string key, string[] expectedKeys) + { + var keys = expectedKeys.Select(x => $"`{x}`"); + var expected = keys.Count() > 0 + ? string.Join(", ", keys) + : $"`{parent}` with nothing else"; + var node = mapping.Children.ContainsKey(key) ? mapping.Children[key] : mapping; + return ErrorParsingYamlException(file, node.Start.Line, node.Start.Column, $"When parsing `{parent}`, unexpected mapping key `{key}`", $"EXPECTED: {expected}"); + } - protected Exception ExpectedMappingOrStringValueException(string file, string key, YamlNode value) - { - var expected = $"`{key}: (mapping)` or `{key}: (string)`"; - return ErrorParsingYamlException(file, value.Start.Line, value.Start.Column, $"Unexpected `{key}` value", $"EXPECTED: {expected}"); - } + protected Exception ExpectedMappingStringValueException(string file, string parent, YamlMappingNode mapping, string key) + { + var expected = $"`{key}: (string)`"; + var node = mapping.Children.ContainsKey(key) ? mapping.Children[key] : mapping; + return ErrorParsingYamlException(file, node.Start.Line, node.Start.Column, $"When parsing `{parent}`, missing `{key}` value", $"EXPECTED: {expected}"); + } - protected Exception ExpectedSequenceOfStringsNotNullOrEmptyException(string file, string key, YamlSequenceNode sequence) - { - var expected = $"`{key}` (sequence of (string)) must not be empty or contain empty strings"; - return ErrorParsingYamlException(file, sequence.Start.Line, sequence.Start.Column, $"Unexpected `{key}` value", $"EXPECTED: {expected}"); - } + protected Exception ExpectedMappingStringValueNotNullOrEmptyException(string file, string parent, YamlMappingNode mapping, string key) + { + var expected = $"`{key}` (string) value must not be empty"; + var node = mapping.Children.ContainsKey(key) ? mapping.Children[key] : mapping; + return ErrorParsingYamlException(file, node.Start.Line, node.Start.Column, $"When parsing `{parent}`, missing `{key}` value", $"EXPECTED: {expected}"); + } - protected Exception ExpectedSequenceOrStringValueException(string file, string key, YamlNode value) - { - var expected = $"`{key}: (sequence)` or `{key}: (string)`"; - return ErrorParsingYamlException(file, value.Start.Line, value.Start.Column, $"Unexpected `{key}` value", $"EXPECTED: {expected}"); - } + protected Exception ExpectedMappingOrStringValueException(string file, string key, YamlNode value) + { + var expected = $"`{key}: (mapping)` or `{key}: (string)`"; + return ErrorParsingYamlException(file, value.Start.Line, value.Start.Column, $"Unexpected `{key}` value", $"EXPECTED: {expected}"); + } - protected Exception ExpectedStringValueNotNullOrEmpty(string file, string key, YamlScalarNode scalar) - { - var expected = $"`{key}` (string) value must not be empty"; - return ErrorParsingYamlException(file, scalar.Start.Line, scalar.Start.Column, $"Unexpected `{key}` value", $"EXPECTED: {expected}"); - } + protected Exception ExpectedSequenceOfStringsNotNullOrEmptyException(string file, string key, YamlSequenceNode sequence) + { + var expected = $"`{key}` (sequence of (string)) must not be empty or contain empty strings"; + return ErrorParsingYamlException(file, sequence.Start.Line, sequence.Start.Column, $"Unexpected `{key}` value", $"EXPECTED: {expected}"); + } - protected Exception ExpectedSequenceOrStringValue(string file, YamlNode value) - { - var expected = $"`(string)` or (sequence of (string))` expected"; - return ErrorParsingYamlException(file, value.Start.Line, value.Start.Column, $"Unexpected non-string/non-sequence of string", $"EXPECTED: {expected}"); - } - - protected Exception ExpectedStringValue(string file, YamlNode node) - { - var expected = "(string) value must not be empty"; - return ErrorParsingYamlException(file, node.Start.Line, node.Start.Column, $"Unexpected non-string value", $"EXPECTED: {expected}"); - } + protected Exception ExpectedSequenceOrStringValueException(string file, string key, YamlNode value) + { + var expected = $"`{key}: (sequence)` or `{key}: (string)`"; + return ErrorParsingYamlException(file, value.Start.Line, value.Start.Column, $"Unexpected `{key}` value", $"EXPECTED: {expected}"); + } - protected Exception ErrorTemplateContainsOneDocument(string file, YamlStream parsed) - { - var message = $"When parsing `template` `{file}, found {parsed.Documents.Count()} YAML document(s)"; - var expected = "EXPECTED: One (1) YAML document"; - return ErrorParsingYamlException(file, 1, 1, message, expected); - } + protected Exception ExpectedStringValueNotNullOrEmpty(string file, string key, YamlScalarNode scalar) + { + var expected = $"`{key}` (string) value must not be empty"; + return ErrorParsingYamlException(file, scalar.Start.Line, scalar.Start.Column, $"Unexpected `{key}` value", $"EXPECTED: {expected}"); + } - protected Exception ErrorInvalidTemplateSequenceNodeType(string file, YamlNode node, string kindOfSequence, string fromFile) - { - var message = $"When parsing `template` from `{fromFile}`, found invalid YamlNode type"; - var expected = $"EXPECTED: `{{{kindOfSequence} sequence}}"; - return ErrorParsingYamlException(file, node.Start.Line, node.Start.Column, message, expected); - } + protected Exception ExpectedSequenceOrStringValue(string file, YamlNode value) + { + var expected = $"`(string)` or (sequence of (string))` expected"; + return ErrorParsingYamlException(file, value.Start.Line, value.Start.Column, $"Unexpected non-string/non-sequence of string", $"EXPECTED: {expected}"); + } - protected Exception ErrorUnexpectedNode(string file, YamlNode node, string expected) - { - var message = "Unexpected node"; - return ErrorParsingYamlException(file, node.Start.Line, node.Start.Column, message, $"EXPECTED: {expected}"); - } + protected Exception ExpectedStringValue(string file, YamlNode node) + { + var expected = "(string) value must not be empty"; + return ErrorParsingYamlException(file, node.Start.Line, node.Start.Column, $"Unexpected non-string value", $"EXPECTED: {expected}"); + } - protected Exception ErrorParsingYamlException(string file, string message1, string? message2 = null) - { - return ErrorParsingYamlException(file, 0, 0, message1, message2); - } + protected Exception ErrorTemplateContainsOneDocument(string file, YamlStream parsed) + { + var message = $"When parsing `template` `{file}, found {parsed.Documents.Count()} YAML document(s)"; + var expected = "EXPECTED: One (1) YAML document"; + return ErrorParsingYamlException(file, 1, 1, message, expected); + } - protected Exception ErrorParsingYamlException(string file, int line, int column, string message1, string? message2 = null) - { - return ErrorException(file, line, column, "Parsing YAML", message1, message2); - } + protected Exception ErrorInvalidTemplateSequenceNodeType(string file, YamlNode node, string kindOfSequence, string fromFile) + { + var message = $"When parsing `template` from `{fromFile}`, found invalid YamlNode type"; + var expected = $"EXPECTED: `{{{kindOfSequence} sequence}}"; + return ErrorParsingYamlException(file, node.Start.Line, node.Start.Column, message, expected); + } - protected Exception ErrorException(string file, string message0, string? message1 = null, string? message2 = null) - { - return ErrorException(file, 0, 0, message0, message1, message2); - } + protected Exception ErrorUnexpectedNode(string file, YamlNode node, string expected) + { + var message = "Unexpected node"; + return ErrorParsingYamlException(file, node.Start.Line, node.Start.Column, message, $"EXPECTED: {expected}"); + } - protected Exception ErrorException(string file, int line, int column, string message0, string? message1 = null, string? message2 = null) - { - var message = !string.IsNullOrEmpty(message1) - ? $"{message0}: {message1}" - : message0; + protected Exception ErrorParsingYamlException(string file, string message1, string? message2 = null) + { + return ErrorParsingYamlException(file, 0, 0, message1, message2); + } - if (!string.IsNullOrEmpty(message2)) + protected Exception ErrorParsingYamlException(string file, int line, int column, string message1, string? message2 = null) { - message += $"\n\n {message2}"; + return ErrorException(file, line, column, "Parsing YAML", message1, message2); } - return new FileParseException(message, file, line, column); - } + protected Exception ErrorException(string file, string message0, string? message1 = null, string? message2 = null) + { + return ErrorException(file, 0, 0, message0, message1, message2); + } - private static string ReplaceTemplateParameters(YamlNode callerSpecifiedParameters, string yaml) - { - var mapping = callerSpecifiedParameters as YamlMappingNode; - if (mapping != null) + protected Exception ErrorException(string file, int line, int column, string message0, string? message1 = null, string? message2 = null) { - var replacements = new Dictionary(mapping.Children.Select(x => new KeyValuePair( - (x.Key as YamlScalarNode)?.Value ?? "", - (x.Value as YamlScalarNode)?.Value ?? ""))); + var message = !string.IsNullOrEmpty(message1) + ? $"{message0}: {message1}" + : message0; - foreach (var replacement in replacements) + if (!string.IsNullOrEmpty(message2)) { - yaml = yaml.Replace("{" + replacement.Key + "}", replacement.Value); + message += $"\n\n {message2}"; } + + return new FileParseException(message, file, line, column); } - return yaml; - } + private static string ReplaceTemplateParameters(YamlNode callerSpecifiedParameters, string yaml) + { + var mapping = callerSpecifiedParameters as YamlMappingNode; + if (mapping != null) + { + var replacements = new Dictionary(mapping.Children.Select(x => new KeyValuePair( + (x.Key as YamlScalarNode)?.Value ?? "", + (x.Value as YamlScalarNode)?.Value ?? ""))); + + foreach (var replacement in replacements) + { + yaml = yaml.Replace("{" + replacement.Key + "}", replacement.Value); + } + } + + return yaml; + } - private IResolutionContext _context; -} + private IResolutionContext _context; + } +} \ No newline at end of file diff --git a/src/cs/Helpers/input_interop.cs b/src/cs/Helpers/input_interop.cs index a7bab57e..55cd8816 100644 --- a/src/cs/Helpers/input_interop.cs +++ b/src/cs/Helpers/input_interop.cs @@ -5,282 +5,300 @@ // The default implementation of Send() is simply to call Press(); and Release(); + +/* Unmerged change from project 'macaroni_core (net6.0-windows)' +Before: using WORD = System.UInt16; -using DWORD = System.UInt32; -using System.Runtime.InteropServices; +After: +using System.Globalization; +using System.UInt16; +*/ + +/* Unmerged change from project 'macaroni_core (netstandard2.1)' +Before: +using WORD = System.UInt16; +After: using System.Globalization; +using System.UInt16; +*/ -namespace macaroni; +using System; +using System.Linq; +using System.Runtime.InteropServices; +using DWORD = System.UInt32; +using WORD = System.UInt16; -public class input_interop +namespace macaroni { - public const DWORD KEYEVENTF_EXTENDEDKEY = 0x0001; - public const DWORD KEYEVENTF_KEYUP = 0x0002; - public const DWORD KEYEVENTF_UNICODE = 0x0004; - public const DWORD KEYEVENTF_SCANCODE = 0x0008; + public class input_interop + { + public const DWORD KEYEVENTF_EXTENDEDKEY = 0x0001; + public const DWORD KEYEVENTF_KEYUP = 0x0002; + public const DWORD KEYEVENTF_UNICODE = 0x0004; + public const DWORD KEYEVENTF_SCANCODE = 0x0008; - // Constants for key types. OR with STATE_ON or STATE_OFF - public const DWORD STATE_CAPS = 1; - public const DWORD STATE_NUM = 2; - public const DWORD STATE_SCROLL = 3; + // Constants for key types. OR with STATE_ON or STATE_OFF + public const DWORD STATE_CAPS = 1; + public const DWORD STATE_NUM = 2; + public const DWORD STATE_SCROLL = 3; - public const DWORD STATE_ON = 0x80000000; - public const DWORD STATE_OFF = 0; + public const DWORD STATE_ON = 0x80000000; + public const DWORD STATE_OFF = 0; - // Pass this in as the flags parameter to use VK_xxx codes - public const DWORD VIRTUAL_KEY = 0; + // Pass this in as the flags parameter to use VK_xxx codes + public const DWORD VIRTUAL_KEY = 0; - public enum VirtualKeyStates : int - { - VK_LBUTTON = 0x01, - VK_RBUTTON = 0x02, - VK_CANCEL = 0x03, - VK_MBUTTON = 0x04, - // - VK_XBUTTON1 = 0x05, - VK_XBUTTON2 = 0x06, - // - VK_BACK = 0x08, - VK_TAB = 0x09, - // - VK_CLEAR = 0x0C, - VK_RETURN = 0x0D, - // - VK_SHIFT = 0x10, - VK_CONTROL = 0x11, - VK_MENU = 0x12, - VK_PAUSE = 0x13, - VK_CAPITAL = 0x14, - // - VK_KANA = 0x15, - VK_HANGEUL = 0x15, /* old name - should be here for compatibility */ - VK_HANGUL = 0x15, - VK_JUNJA = 0x17, - VK_FINAL = 0x18, - VK_HANJA = 0x19, - VK_KANJI = 0x19, - // - VK_ESCAPE = 0x1B, - // - VK_CONVERT = 0x1C, - VK_NONCONVERT = 0x1D, - VK_ACCEPT = 0x1E, - VK_MODECHANGE = 0x1F, - // - VK_SPACE = 0x20, - VK_PRIOR = 0x21, - VK_NEXT = 0x22, - VK_END = 0x23, - VK_HOME = 0x24, - VK_LEFT = 0x25, - VK_UP = 0x26, - VK_RIGHT = 0x27, - VK_DOWN = 0x28, - VK_SELECT = 0x29, - VK_PRINT = 0x2A, - VK_EXECUTE = 0x2B, - VK_SNAPSHOT = 0x2C, - VK_INSERT = 0x2D, - VK_DELETE = 0x2E, - VK_HELP = 0x2F, - // - VK_LWIN = 0x5B, - VK_RWIN = 0x5C, - VK_APPS = 0x5D, - // - VK_SLEEP = 0x5F, - // - VK_NUMPAD0 = 0x60, - VK_NUMPAD1 = 0x61, - VK_NUMPAD2 = 0x62, - VK_NUMPAD3 = 0x63, - VK_NUMPAD4 = 0x64, - VK_NUMPAD5 = 0x65, - VK_NUMPAD6 = 0x66, - VK_NUMPAD7 = 0x67, - VK_NUMPAD8 = 0x68, - VK_NUMPAD9 = 0x69, - VK_MULTIPLY = 0x6A, - VK_ADD = 0x6B, - VK_SEPARATOR = 0x6C, - VK_SUBTRACT = 0x6D, - VK_DECIMAL = 0x6E, - VK_DIVIDE = 0x6F, - VK_F1 = 0x70, - VK_F2 = 0x71, - VK_F3 = 0x72, - VK_F4 = 0x73, - VK_F5 = 0x74, - VK_F6 = 0x75, - VK_F7 = 0x76, - VK_F8 = 0x77, - VK_F9 = 0x78, - VK_F10 = 0x79, - VK_F11 = 0x7A, - VK_F12 = 0x7B, - VK_F13 = 0x7C, - VK_F14 = 0x7D, - VK_F15 = 0x7E, - VK_F16 = 0x7F, - VK_F17 = 0x80, - VK_F18 = 0x81, - VK_F19 = 0x82, - VK_F20 = 0x83, - VK_F21 = 0x84, - VK_F22 = 0x85, - VK_F23 = 0x86, - VK_F24 = 0x87, - // - VK_NUMLOCK = 0x90, - VK_SCROLL = 0x91, - // - VK_OEM_NEC_EQUAL = 0x92, // '=' key on numpad - // - VK_OEM_FJ_JISHO = 0x92, // 'Dictionary' key - VK_OEM_FJ_MASSHOU= 0x93, // 'Unregister word' key - VK_OEM_FJ_TOUROKU= 0x94, // 'Register word' key - VK_OEM_FJ_LOYA = 0x95, // 'Left OYAYUBI' key - VK_OEM_FJ_ROYA = 0x96, // 'Right OYAYUBI' key - // - VK_LSHIFT = 0xA0, - VK_RSHIFT = 0xA1, - VK_LCONTROL = 0xA2, - VK_RCONTROL = 0xA3, - VK_LMENU = 0xA4, - VK_RMENU = 0xA5, - // - VK_BROWSER_BACK = 0xA6, - VK_BROWSER_FORWARD = 0xA7, - VK_BROWSER_REFRESH = 0xA8, - VK_BROWSER_STOP = 0xA9, - VK_BROWSER_SEARCH = 0xAA, - VK_BROWSER_FAVORITES = 0xAB, - VK_BROWSER_HOME = 0xAC, - // - VK_VOLUME_MUTE = 0xAD, - VK_VOLUME_DOWN = 0xAE, - VK_VOLUME_UP = 0xAF, - VK_MEDIA_NEXT_TRACK = 0xB0, - VK_MEDIA_PREV_TRACK = 0xB1, - VK_MEDIA_STOP = 0xB2, - VK_MEDIA_PLAY_PAUSE = 0xB3, - VK_LAUNCH_MAIL = 0xB4, - VK_LAUNCH_MEDIA_SELECT= 0xB5, - VK_LAUNCH_APP1 = 0xB6, - VK_LAUNCH_APP2 = 0xB7, - // - VK_OEM_1 = 0xBA, // ';:' for US - VK_OEM_PLUS = 0xBB, // '+' any country - VK_OEM_COMMA = 0xBC, // ',' any country - VK_OEM_MINUS = 0xBD, // '-' any country - VK_OEM_PERIOD = 0xBE, // '.' any country - VK_OEM_2 = 0xBF, // '/?' for US - VK_OEM_3 = 0xC0, // '`~' for US - // - VK_OEM_4 = 0xDB, // '[{' for US - VK_OEM_5 = 0xDC, // '\|' for US - VK_OEM_6 = 0xDD, // ']}' for US - VK_OEM_7 = 0xDE, // ''"' for US - VK_OEM_8 = 0xDF, - // - VK_OEM_AX = 0xE1, // 'AX' key on Japanese AX kbd - VK_OEM_102 = 0xE2, // "<>" or "\|" on RT 102-key kbd. - VK_ICO_HELP = 0xE3, // Help key on ICO - VK_ICO_00 = 0xE4, // 00 key on ICO - // - VK_PROCESSKEY = 0xE5, - // - VK_ICO_CLEAR = 0xE6, - // - VK_PACKET = 0xE7, - // - VK_OEM_RESET = 0xE9, - VK_OEM_JUMP = 0xEA, - VK_OEM_PA1 = 0xEB, - VK_OEM_PA2 = 0xEC, - VK_OEM_PA3 = 0xED, - VK_OEM_WSCTRL = 0xEE, - VK_OEM_CUSEL = 0xEF, - VK_OEM_ATTN = 0xF0, - VK_OEM_FINISH = 0xF1, - VK_OEM_COPY = 0xF2, - VK_OEM_AUTO = 0xF3, - VK_OEM_ENLW = 0xF4, - VK_OEM_BACKTAB = 0xF5, - // - VK_ATTN = 0xF6, - VK_CRSEL = 0xF7, - VK_EXSEL = 0xF8, - VK_EREOF = 0xF9, - VK_PLAY = 0xFA, - VK_ZOOM = 0xFB, - VK_NONAME = 0xFC, - VK_PA1 = 0xFD, - VK_OEM_CLEAR = 0xFE - } + public enum VirtualKeyStates : int + { + VK_LBUTTON = 0x01, + VK_RBUTTON = 0x02, + VK_CANCEL = 0x03, + VK_MBUTTON = 0x04, + // + VK_XBUTTON1 = 0x05, + VK_XBUTTON2 = 0x06, + // + VK_BACK = 0x08, + VK_TAB = 0x09, + // + VK_CLEAR = 0x0C, + VK_RETURN = 0x0D, + // + VK_SHIFT = 0x10, + VK_CONTROL = 0x11, + VK_MENU = 0x12, + VK_PAUSE = 0x13, + VK_CAPITAL = 0x14, + // + VK_KANA = 0x15, + VK_HANGEUL = 0x15, /* old name - should be here for compatibility */ + VK_HANGUL = 0x15, + VK_JUNJA = 0x17, + VK_FINAL = 0x18, + VK_HANJA = 0x19, + VK_KANJI = 0x19, + // + VK_ESCAPE = 0x1B, + // + VK_CONVERT = 0x1C, + VK_NONCONVERT = 0x1D, + VK_ACCEPT = 0x1E, + VK_MODECHANGE = 0x1F, + // + VK_SPACE = 0x20, + VK_PRIOR = 0x21, + VK_NEXT = 0x22, + VK_END = 0x23, + VK_HOME = 0x24, + VK_LEFT = 0x25, + VK_UP = 0x26, + VK_RIGHT = 0x27, + VK_DOWN = 0x28, + VK_SELECT = 0x29, + VK_PRINT = 0x2A, + VK_EXECUTE = 0x2B, + VK_SNAPSHOT = 0x2C, + VK_INSERT = 0x2D, + VK_DELETE = 0x2E, + VK_HELP = 0x2F, + // + VK_LWIN = 0x5B, + VK_RWIN = 0x5C, + VK_APPS = 0x5D, + // + VK_SLEEP = 0x5F, + // + VK_NUMPAD0 = 0x60, + VK_NUMPAD1 = 0x61, + VK_NUMPAD2 = 0x62, + VK_NUMPAD3 = 0x63, + VK_NUMPAD4 = 0x64, + VK_NUMPAD5 = 0x65, + VK_NUMPAD6 = 0x66, + VK_NUMPAD7 = 0x67, + VK_NUMPAD8 = 0x68, + VK_NUMPAD9 = 0x69, + VK_MULTIPLY = 0x6A, + VK_ADD = 0x6B, + VK_SEPARATOR = 0x6C, + VK_SUBTRACT = 0x6D, + VK_DECIMAL = 0x6E, + VK_DIVIDE = 0x6F, + VK_F1 = 0x70, + VK_F2 = 0x71, + VK_F3 = 0x72, + VK_F4 = 0x73, + VK_F5 = 0x74, + VK_F6 = 0x75, + VK_F7 = 0x76, + VK_F8 = 0x77, + VK_F9 = 0x78, + VK_F10 = 0x79, + VK_F11 = 0x7A, + VK_F12 = 0x7B, + VK_F13 = 0x7C, + VK_F14 = 0x7D, + VK_F15 = 0x7E, + VK_F16 = 0x7F, + VK_F17 = 0x80, + VK_F18 = 0x81, + VK_F19 = 0x82, + VK_F20 = 0x83, + VK_F21 = 0x84, + VK_F22 = 0x85, + VK_F23 = 0x86, + VK_F24 = 0x87, + // + VK_NUMLOCK = 0x90, + VK_SCROLL = 0x91, + // + VK_OEM_NEC_EQUAL = 0x92, // '=' key on numpad + // + VK_OEM_FJ_JISHO = 0x92, // 'Dictionary' key + VK_OEM_FJ_MASSHOU = 0x93, // 'Unregister word' key + VK_OEM_FJ_TOUROKU = 0x94, // 'Register word' key + VK_OEM_FJ_LOYA = 0x95, // 'Left OYAYUBI' key + VK_OEM_FJ_ROYA = 0x96, // 'Right OYAYUBI' key + // + VK_LSHIFT = 0xA0, + VK_RSHIFT = 0xA1, + VK_LCONTROL = 0xA2, + VK_RCONTROL = 0xA3, + VK_LMENU = 0xA4, + VK_RMENU = 0xA5, + // + VK_BROWSER_BACK = 0xA6, + VK_BROWSER_FORWARD = 0xA7, + VK_BROWSER_REFRESH = 0xA8, + VK_BROWSER_STOP = 0xA9, + VK_BROWSER_SEARCH = 0xAA, + VK_BROWSER_FAVORITES = 0xAB, + VK_BROWSER_HOME = 0xAC, + // + VK_VOLUME_MUTE = 0xAD, + VK_VOLUME_DOWN = 0xAE, + VK_VOLUME_UP = 0xAF, + VK_MEDIA_NEXT_TRACK = 0xB0, + VK_MEDIA_PREV_TRACK = 0xB1, + VK_MEDIA_STOP = 0xB2, + VK_MEDIA_PLAY_PAUSE = 0xB3, + VK_LAUNCH_MAIL = 0xB4, + VK_LAUNCH_MEDIA_SELECT = 0xB5, + VK_LAUNCH_APP1 = 0xB6, + VK_LAUNCH_APP2 = 0xB7, + // + VK_OEM_1 = 0xBA, // ';:' for US + VK_OEM_PLUS = 0xBB, // '+' any country + VK_OEM_COMMA = 0xBC, // ',' any country + VK_OEM_MINUS = 0xBD, // '-' any country + VK_OEM_PERIOD = 0xBE, // '.' any country + VK_OEM_2 = 0xBF, // '/?' for US + VK_OEM_3 = 0xC0, // '`~' for US + // + VK_OEM_4 = 0xDB, // '[{' for US + VK_OEM_5 = 0xDC, // '\|' for US + VK_OEM_6 = 0xDD, // ']}' for US + VK_OEM_7 = 0xDE, // ''"' for US + VK_OEM_8 = 0xDF, + // + VK_OEM_AX = 0xE1, // 'AX' key on Japanese AX kbd + VK_OEM_102 = 0xE2, // "<>" or "\|" on RT 102-key kbd. + VK_ICO_HELP = 0xE3, // Help key on ICO + VK_ICO_00 = 0xE4, // 00 key on ICO + // + VK_PROCESSKEY = 0xE5, + // + VK_ICO_CLEAR = 0xE6, + // + VK_PACKET = 0xE7, + // + VK_OEM_RESET = 0xE9, + VK_OEM_JUMP = 0xEA, + VK_OEM_PA1 = 0xEB, + VK_OEM_PA2 = 0xEC, + VK_OEM_PA3 = 0xED, + VK_OEM_WSCTRL = 0xEE, + VK_OEM_CUSEL = 0xEF, + VK_OEM_ATTN = 0xF0, + VK_OEM_FINISH = 0xF1, + VK_OEM_COPY = 0xF2, + VK_OEM_AUTO = 0xF3, + VK_OEM_ENLW = 0xF4, + VK_OEM_BACKTAB = 0xF5, + // + VK_ATTN = 0xF6, + VK_CRSEL = 0xF7, + VK_EXSEL = 0xF8, + VK_EREOF = 0xF9, + VK_PLAY = 0xFA, + VK_ZOOM = 0xFB, + VK_NONAME = 0xFC, + VK_PA1 = 0xFD, + VK_OEM_CLEAR = 0xFE + } - public enum MapVirtualKeyType : uint - { - MAPVK_VK_TO_VSC = 0, - MAPVK_VSC_TO_VK = 1, - MAPVK_VK_TO_CHAR = 2, - MAPVK_VSC_TO_VK_EX = 3, - MAPVK_VK_TO_VSC_EX = 4 - } + public enum MapVirtualKeyType : uint + { + MAPVK_VK_TO_VSC = 0, + MAPVK_VSC_TO_VK = 1, + MAPVK_VK_TO_CHAR = 2, + MAPVK_VSC_TO_VK_EX = 3, + MAPVK_VK_TO_VSC_EX = 4 + } - [DllImport("user32.dll", SetLastError = true)] - public static extern uint MapVirtualKey(uint uCode, MapVirtualKeyType uMapType); + [DllImport("user32.dll", SetLastError = true)] + public static extern uint MapVirtualKey(uint uCode, MapVirtualKeyType uMapType); - [DllImport("user32.dll", SetLastError = true)] - public static extern uint MapVirtualKeyEx(uint uCode, MapVirtualKeyType uMapType, IntPtr dwhkl); + [DllImport("user32.dll", SetLastError = true)] + public static extern uint MapVirtualKeyEx(uint uCode, MapVirtualKeyType uMapType, IntPtr dwhkl); - [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern short VkKeyScan(char ch); + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern short VkKeyScan(char ch); - [DllImport("user32.dll", CharSet = CharSet.Unicode)] - public static extern short VkKeyScanEx(char ch, IntPtr dwhkl); + [DllImport("user32.dll", CharSet = CharSet.Unicode)] + public static extern short VkKeyScanEx(char ch, IntPtr dwhkl); - [DllImport("user32.dll", SetLastError = true)] - public static extern bool UnloadKeyboardLayout(IntPtr hkl); + [DllImport("user32.dll", SetLastError = true)] + public static extern bool UnloadKeyboardLayout(IntPtr hkl); - [DllImport("user32.dll", SetLastError = true)] - public static extern IntPtr LoadKeyboardLayout(string pwszKLID, uint Flags); + [DllImport("user32.dll", SetLastError = true)] + public static extern IntPtr LoadKeyboardLayout(string pwszKLID, uint Flags); - public struct KeyMap - { - public KeyMap(string word, WORD code) + public struct KeyMap { - Word = word; - Code = code; + public KeyMap(string word, WORD code) + { + Word = word; + Code = code; + } + + public string Word; + public WORD Code; } - public string Word; - public WORD Code; - } - - // These are keys that have a special meaning, but can be - // escaped within curly braces. - public static char[] BraceEscapeRequiredChars = "^%+{}()~".ToArray(); + // These are keys that have a special meaning, but can be + // escaped within curly braces. + public static char[] BraceEscapeRequiredChars = "^%+{}()~".ToArray(); - // // Special-case keys. These keys don't follow normal key behavior. - public const WORD SCANCODE_SPECIAL = 0xFF00; - public static bool IS_SPECIAL_SCANCODE(WORD x) { return ((x & SCANCODE_SPECIAL) == SCANCODE_SPECIAL); } + // // Special-case keys. These keys don't follow normal key behavior. + public const WORD SCANCODE_SPECIAL = 0xFF00; + public static bool IS_SPECIAL_SCANCODE(WORD x) { return ((x & SCANCODE_SPECIAL) == SCANCODE_SPECIAL); } - public const WORD SCANCODE_SPECIAL_BREAK = (SCANCODE_SPECIAL | 0x01); - public const WORD SCANCODE_SPECIAL_PRTSC = (SCANCODE_SPECIAL | 0x02); - public const WORD SCANCODE_SPECIAL_SLEEP = (SCANCODE_SPECIAL | 0x03); - public const WORD SCANCODE_SPECIAL_CAPSON = (SCANCODE_SPECIAL | 0x04); - public const WORD SCANCODE_SPECIAL_CAPSOFF = (SCANCODE_SPECIAL | 0x05); - public const WORD SCANCODE_SPECIAL_NUMON = (SCANCODE_SPECIAL | 0x06); - public const WORD SCANCODE_SPECIAL_NUMOFF = (SCANCODE_SPECIAL | 0x07); - public const WORD SCANCODE_SPECIAL_SCRON = (SCANCODE_SPECIAL | 0x08); - public const WORD SCANCODE_SPECIAL_SCROFF = (SCANCODE_SPECIAL | 0x09); + public const WORD SCANCODE_SPECIAL_BREAK = (SCANCODE_SPECIAL | 0x01); + public const WORD SCANCODE_SPECIAL_PRTSC = (SCANCODE_SPECIAL | 0x02); + public const WORD SCANCODE_SPECIAL_SLEEP = (SCANCODE_SPECIAL | 0x03); + public const WORD SCANCODE_SPECIAL_CAPSON = (SCANCODE_SPECIAL | 0x04); + public const WORD SCANCODE_SPECIAL_CAPSOFF = (SCANCODE_SPECIAL | 0x05); + public const WORD SCANCODE_SPECIAL_NUMON = (SCANCODE_SPECIAL | 0x06); + public const WORD SCANCODE_SPECIAL_NUMOFF = (SCANCODE_SPECIAL | 0x07); + public const WORD SCANCODE_SPECIAL_SCRON = (SCANCODE_SPECIAL | 0x08); + public const WORD SCANCODE_SPECIAL_SCROFF = (SCANCODE_SPECIAL | 0x09); - // These key strings are contained in {} braces. - static public KeyMap[] ScanCodeKeyMap = new[] - { + // These key strings are contained in {} braces. + static public KeyMap[] ScanCodeKeyMap = new[] + { new KeyMap("BACKSPACE", 0x000e ), new KeyMap("BS", 0x000e), new KeyMap("BKSP", 0x000e), @@ -302,18 +320,18 @@ public KeyMap(string word, WORD code) new KeyMap("SCROLLLOCK", 0x0046), new KeyMap("TAB", 0x000f), new KeyMap("UP", 0xe048), - new KeyMap("F1", 0x003b), - new KeyMap("F2", 0x003c), - new KeyMap("F3", 0x003d), - new KeyMap("F4", 0x003e), - new KeyMap("F5", 0x003f), - new KeyMap("F6", 0x0040), - new KeyMap("F7", 0x0041), - new KeyMap("F8", 0x0042), - new KeyMap("F9", 0x0043), - new KeyMap("F10", 0x0044), - new KeyMap("F11", 0x0057), - new KeyMap("F12", 0x0058), + new KeyMap("F1", 0x003b), + new KeyMap("F2", 0x003c), + new KeyMap("F3", 0x003d), + new KeyMap("F4", 0x003e), + new KeyMap("F5", 0x003f), + new KeyMap("F6", 0x0040), + new KeyMap("F7", 0x0041), + new KeyMap("F8", 0x0042), + new KeyMap("F9", 0x0043), + new KeyMap("F10", 0x0044), + new KeyMap("F11", 0x0057), + new KeyMap("F12", 0x0058), new KeyMap("NUM0", 0x0052), new KeyMap("NUM1", 0x004f), new KeyMap("NUM2", 0x0050), @@ -357,91 +375,92 @@ public KeyMap(string word, WORD code) new KeyMap("SCROLLLOCK-", SCANCODE_SPECIAL_SCROFF), }; - [DllImport("USER32.dll")] - static public extern WORD GetKeyState(VirtualKeyStates nVirtKey); + [DllImport("USER32.dll")] + static public extern WORD GetKeyState(VirtualKeyStates nVirtKey); - static public DWORD KEY_VALUE(DWORD x) { return (x & (~STATE_ON)); } - static public DWORD KEY_STATE(DWORD x) { return (x & STATE_ON); } + static public DWORD KEY_VALUE(DWORD x) { return (x & (~STATE_ON)); } + static public DWORD KEY_STATE(DWORD x) { return (x & STATE_ON); } - [StructLayout(LayoutKind.Sequential)] - public struct INPUT - { - public InputType type; - public InputUnion U; - public static int Size + [StructLayout(LayoutKind.Sequential)] + public struct INPUT { - get { return Marshal.SizeOf(typeof(INPUT)); } + public InputType type; + public InputUnion U; + public static int Size + { + get { return Marshal.SizeOf(typeof(INPUT)); } + } } - } - public enum InputType : uint - { - INPUT_MOUSE, - INPUT_KEYBOARD, - INPUT_HARDWARE - } + public enum InputType : uint + { + INPUT_MOUSE, + INPUT_KEYBOARD, + INPUT_HARDWARE + } - [StructLayout(LayoutKind.Explicit)] - public struct InputUnion - { - [FieldOffset(0)] - public MOUSEINPUT mi; - [FieldOffset(0)] - public KEYBDINPUT ki; - [FieldOffset(0)] - public HARDWAREINPUT hi; - } + [StructLayout(LayoutKind.Explicit)] + public struct InputUnion + { + [FieldOffset(0)] + public MOUSEINPUT mi; + [FieldOffset(0)] + public KEYBDINPUT ki; + [FieldOffset(0)] + public HARDWAREINPUT hi; + } - [StructLayout(LayoutKind.Sequential)] - public struct MOUSEINPUT - { - public int dx; - public int dy; - public int mouseData; - public DWORD dwFlags; - public uint time; - public UIntPtr dwExtraInfo; - } + [StructLayout(LayoutKind.Sequential)] + public struct MOUSEINPUT + { + public int dx; + public int dy; + public int mouseData; + public DWORD dwFlags; + public uint time; + public UIntPtr dwExtraInfo; + } - [StructLayout(LayoutKind.Sequential)] - public struct KEYBDINPUT - { - public WORD wVk; - public WORD wScan; - public DWORD dwFlags; - public int time; - public UIntPtr dwExtraInfo; - } - - [StructLayout(LayoutKind.Sequential)] - public struct HARDWAREINPUT - { - public int uMsg; - public short wParamL; - public short wParamH; - } + [StructLayout(LayoutKind.Sequential)] + public struct KEYBDINPUT + { + public WORD wVk; + public WORD wScan; + public DWORD dwFlags; + public int time; + public UIntPtr dwExtraInfo; + } - [DllImport("user32.dll")] - public static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize); + [StructLayout(LayoutKind.Sequential)] + public struct HARDWAREINPUT + { + public int uMsg; + public short wParamL; + public short wParamH; + } - public const DWORD WM_HOTKEY = 0x0312; + [DllImport("user32.dll")] + public static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize); - public const WORD MOD_ALT = 0x0001; - public const WORD MOD_CONTROL = 0x0002; - public const WORD MOD_SHIFT = 0x0004; - public const WORD MOD_WIN = 0x0008; + public const DWORD WM_HOTKEY = 0x0312; - public const WORD VK_SHIFT = 0x10; - public const WORD VK_CONTROL = 0x11; - public const WORD VK_MENU = 0x12; + public const WORD MOD_ALT = 0x0001; + public const WORD MOD_CONTROL = 0x0002; + public const WORD MOD_SHIFT = 0x0004; + public const WORD MOD_WIN = 0x0008; - public const WORD VK_LSHIFT = 0xA0; - public const WORD VK_RSHIFT = 0xA1; - public const WORD VK_LCONTROL = 0xA2; - public const WORD VK_RCONTROL = 0xA3; - public const WORD VK_LMENU = 0xA4; - public const WORD VK_RMENU = 0xA5; + public const WORD VK_SHIFT = 0x10; + public const WORD VK_CONTROL = 0x11; + public const WORD VK_MENU = 0x12; - public const WORD VK_LWIN = 0x5B; - public const WORD VK_RWIN = 0x5C; -} + public const WORD VK_LSHIFT = 0xA0; + public const WORD VK_RSHIFT = 0xA1; + public const WORD VK_LCONTROL = 0xA2; + public const WORD VK_RCONTROL = 0xA3; + public const WORD VK_LMENU = 0xA4; + public const WORD VK_RMENU = 0xA5; + + public const WORD VK_LWIN = 0x5B; + public const WORD VK_RWIN = 0x5C; + } +} \ No newline at end of file diff --git a/src/cs/Helpers/window_interop.cs b/src/cs/Helpers/window_interop.cs index 8b25c96c..dcf71038 100644 --- a/src/cs/Helpers/window_interop.cs +++ b/src/cs/Helpers/window_interop.cs @@ -1,51 +1,53 @@ +using System; using System.Runtime.InteropServices; using System.Text; -namespace macaroni; - -public static class window_interop +namespace macaroni { - public delegate bool EnumWindowsProc(IntPtr hWnd, int lParam); + public static class window_interop + { + public delegate bool EnumWindowsProc(IntPtr hWnd, int lParam); - [DllImport("USER32.DLL")] - public static extern bool EnumWindows(EnumWindowsProc enumFunc, int lParam); + [DllImport("USER32.DLL")] + public static extern bool EnumWindows(EnumWindowsProc enumFunc, int lParam); - [DllImport("USER32.DLL")] - public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); + [DllImport("USER32.DLL")] + public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); - [DllImport("USER32.DLL")] - public static extern int GetWindowTextLength(IntPtr hWnd); + [DllImport("USER32.DLL")] + public static extern int GetWindowTextLength(IntPtr hWnd); - [DllImport("USER32.DLL")] - public static extern bool IsWindowVisible(IntPtr hWnd); + [DllImport("USER32.DLL")] + public static extern bool IsWindowVisible(IntPtr hWnd); - [DllImport("USER32.DLL")] - public static extern IntPtr GetShellWindow(); + [DllImport("USER32.DLL")] + public static extern IntPtr GetShellWindow(); - [DllImport("user32.dll")] - public static extern IntPtr GetForegroundWindow(); + [DllImport("user32.dll")] + public static extern IntPtr GetForegroundWindow(); - //WARN: Only for "Any CPU": - [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] - public static extern int GetWindowThreadProcessId(IntPtr handle, out uint processId); + //WARN: Only for "Any CPU": + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern int GetWindowThreadProcessId(IntPtr handle, out uint processId); - public const uint PROCESS_QUERY_INFORMATION = (0x0400); + public const uint PROCESS_QUERY_INFORMATION = (0x0400); - [DllImport("kernel32.dll", SetLastError = true)] - public static extern IntPtr OpenProcess( - uint processAccess, - bool bInheritHandle, - uint processId - ); + [DllImport("kernel32.dll", SetLastError = true)] + public static extern IntPtr OpenProcess( + uint processAccess, + bool bInheritHandle, + uint processId + ); - [DllImport("kernel32.dll", SetLastError=true)] - public static extern bool CloseHandle(IntPtr hHandle); + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool CloseHandle(IntPtr hHandle); - [DllImport("psapi.dll")] - public static extern uint GetProcessImageFileName( - IntPtr hProcess, - [Out] StringBuilder lpImageFileName, - [In] [MarshalAs(UnmanagedType.U4)] int nSize - ); + [DllImport("psapi.dll")] + public static extern uint GetProcessImageFileName( + IntPtr hProcess, + [Out] StringBuilder lpImageFileName, + [In][MarshalAs(UnmanagedType.U4)] int nSize + ); -} + } +} \ No newline at end of file diff --git a/src/cs/IntentRecognition/CLURecognizerService.cs b/src/cs/IntentRecognition/CLURecognizerService.cs index 605968be..66c1c00d 100644 --- a/src/cs/IntentRecognition/CLURecognizerService.cs +++ b/src/cs/IntentRecognition/CLURecognizerService.cs @@ -1,130 +1,136 @@ -using Azure; +using System; +using System.Collections.Generic; +using Azure; using Azure.AI.Language.Conversations; using Azure.Core; using Microsoft.Extensions.DependencyInjection; using System.Diagnostics; +using System.IO; +using System.Linq; using System.Text.Json; +using System.Threading.Tasks; -namespace macaroni; - -internal class CLURecognizerService : ICLURecognizerService +namespace macaroni { - public CLURecognizerService(IServiceProvider services) + internal class CLURecognizerService : ICLURecognizerService { - _serviceProvider = services; - } + public CLURecognizerService(IServiceProvider services) + { + _serviceProvider = services; + } - private ConversationAnalysisClient GetConversationAnalysisClient() - { - var service = _serviceProvider.GetRequiredService(); - return service.GetConversationAnalysisClient(); - } + private ConversationAnalysisClient GetConversationAnalysisClient() + { + var service = _serviceProvider.GetRequiredService(); + return service.GetConversationAnalysisClient(); + } - public Task<(string intentId, Dictionary entities, Dictionary entitiesJson)> CheckCLUAsync(string text) - { - return Task<(string intentId, Dictionary entities)>.Run(() => + public Task<(string intentId, Dictionary entities, Dictionary entitiesJson)> CheckCLUAsync(string text) { - var timer = new Stopwatch(); - var client = GetConversationAnalysisClient(); + return Task<(string intentId, Dictionary entities)>.Run(() => + { + var timer = new Stopwatch(); + var client = GetConversationAnalysisClient(); - var settings = _serviceProvider.GetRequiredService(); - var projectName = settings.Get("CLU_PROJECT_NAME")?.Trim(); - var deploymentName = settings.Get("CLU_DEPLOYMENT_NAME")?.Trim(); + var settings = _serviceProvider.GetRequiredService(); + var projectName = settings.Get("CLU_PROJECT_NAME")?.Trim(); + var deploymentName = settings.Get("CLU_DEPLOYMENT_NAME")?.Trim(); - var data = new - { - analysisInput = new + var data = new { - conversationItem = new + analysisInput = new { - text = text, - id = "1", - participantId = "1", - } - }, - parameters = new - { - projectName, - deploymentName, - - // Use Utf16CodeUnit for strings in .NET. - stringIndexType = "Utf16CodeUnit", - }, - kind = "Conversation", - }; - //using AzureEventSourceListener listener = AzureEventSourceListener.CreateConsoleLogger(); - - timer.Start(); - Response? response = client.AnalyzeConversation(RequestContent.Create(data)); - timer.Stop(); - MR.TRACE_VERBOSE($"CLU latency: {timer.ElapsedMilliseconds.ToString()}ms\n"); - - ParseCLUJsonResponseStream(response.ContentStream!, out var intentId, out var entities, out var entitiesJson); - return (intentId, entities, entitiesJson); - }); - } - - public void ParseCLUJsonResponseStream(Stream stream, out string intentId, out Dictionary entities, out Dictionary entitiesJson) - { - intentId = ""; - entities = new Dictionary(); - entitiesJson = new Dictionary(); - - JsonDocument jsonResult = JsonDocument.Parse(stream); - JsonElement responseTaskResult = jsonResult.RootElement; - JsonElement prediction = responseTaskResult.GetProperty("result").GetProperty("prediction"); - JsonElement projectKind = prediction.GetProperty("projectKind"); + conversationItem = new + { + text = text, + id = "1", + participantId = "1", + } + }, + parameters = new + { + projectName, + deploymentName, + + // Use Utf16CodeUnit for strings in .NET. + stringIndexType = "Utf16CodeUnit", + }, + kind = "Conversation", + }; + //using AzureEventSourceListener listener = AzureEventSourceListener.CreateConsoleLogger(); + + timer.Start(); + Response? response = client.AnalyzeConversation(RequestContent.Create(data)); + timer.Stop(); + MR.TRACE_VERBOSE($"CLU latency: {timer.ElapsedMilliseconds.ToString()}ms\n"); + + ParseCLUJsonResponseStream(response.ContentStream!, out var intentId, out var entities, out var entitiesJson); + return (intentId, entities, entitiesJson); + }); + } - if (projectKind.GetString() == "Orchestration") + public void ParseCLUJsonResponseStream(Stream stream, out string intentId, out Dictionary entities, out Dictionary entitiesJson) { - var respondingProjectName = prediction.GetProperty("topIntent").GetString(); - var isComplexResult = prediction.GetProperty("intents").GetProperty(respondingProjectName!).TryGetProperty("result", out var targetIntentResult); + intentId = ""; + entities = new Dictionary(); + entitiesJson = new Dictionary(); + + JsonDocument jsonResult = JsonDocument.Parse(stream); + JsonElement responseTaskResult = jsonResult.RootElement; + JsonElement prediction = responseTaskResult.GetProperty("result").GetProperty("prediction"); + JsonElement projectKind = prediction.GetProperty("projectKind"); - if (isComplexResult) + if (projectKind.GetString() == "Orchestration") { - prediction = targetIntentResult.GetProperty("prediction"); + var respondingProjectName = prediction.GetProperty("topIntent").GetString(); + var isComplexResult = prediction.GetProperty("intents").GetProperty(respondingProjectName!).TryGetProperty("result", out var targetIntentResult); + + if (isComplexResult) + { + prediction = targetIntentResult.GetProperty("prediction"); + } + else + { + intentId = respondingProjectName ?? ""; + } } - else + else if (projectKind.GetString() == "Conversation") { - intentId = respondingProjectName ?? ""; + var targetIntentResult = responseTaskResult.GetProperty("result"); + prediction = targetIntentResult.GetProperty("prediction"); } - } - else if (projectKind.GetString() == "Conversation") - { - var targetIntentResult = responseTaskResult.GetProperty("result"); - prediction = targetIntentResult.GetProperty("prediction"); - } - if (prediction.GetProperty("projectKind").GetString() == "Conversation") - { - intentId = prediction.GetProperty("topIntent").GetString() ?? ""; - - var trackEntityByNameCount = new Dictionary(); - var array = prediction.GetProperty("entities").EnumerateArray(); - foreach (JsonElement entity in prediction.GetProperty("entities").EnumerateArray()) + if (prediction.GetProperty("projectKind").GetString() == "Conversation") { - var entityName = entity.GetProperty("category").GetString(); - var entityValue = entity.GetProperty("text").GetString(); - var entityJsonValue = entity.ToString(); - - entities[entityName!] = entityValue!; - entitiesJson[entityName!] = entityJsonValue; + intentId = prediction.GetProperty("topIntent").GetString() ?? ""; - // if the entity class appears multiple times in the array - if (array.Count(x => x.GetProperty("category").GetString() == entityName) >= 2) + var trackEntityByNameCount = new Dictionary(); + var array = prediction.GetProperty("entities").EnumerateArray(); + foreach (JsonElement entity in prediction.GetProperty("entities").EnumerateArray()) { - // also store each one as {entityName][i] - var index = trackEntityByNameCount.ContainsKey(entityName!) - ? trackEntityByNameCount[entityName!] - : 0; - entities[$"{entityName}[{index}]"] = entityValue!; - entitiesJson[$"{entityName}[{index}]"] = entityJsonValue; - trackEntityByNameCount[entityName!] = index + 1; + var entityName = entity.GetProperty("category").GetString(); + var entityValue = entity.GetProperty("text").GetString(); + var entityJsonValue = entity.ToString(); + + entities[entityName!] = entityValue!; + entitiesJson[entityName!] = entityJsonValue; + + // if the entity class appears multiple times in the array + if (array.Count(x => x.GetProperty("category").GetString() == entityName) >= 2) + { + // also store each one as {entityName][i] + var index = trackEntityByNameCount.ContainsKey(entityName!) + ? trackEntityByNameCount[entityName!] + : 0; + entities[$"{entityName}[{index}]"] = entityValue!; + entitiesJson[$"{entityName}[{index}]"] = entityJsonValue; + trackEntityByNameCount[entityName!] = index + 1; + } } } } - } - private readonly IServiceProvider _serviceProvider; - private Dictionary> _callbacks = new(); -} + private readonly IServiceProvider _serviceProvider; + private Dictionary> _callbacks = new Dictionary>(); + } +} \ No newline at end of file diff --git a/src/cs/IntentRecognition/IntentRecognizerService.cs b/src/cs/IntentRecognition/IntentRecognizerService.cs index db140b47..c488a86a 100644 --- a/src/cs/IntentRecognition/IntentRecognizerService.cs +++ b/src/cs/IntentRecognition/IntentRecognizerService.cs @@ -5,960 +5,967 @@ using Microsoft.CognitiveServices.Speech.Intent; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; +using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; +using System.Linq; using System.Net; using System.Text; +using System.Threading.Tasks; using static Microsoft.Extensions.Logging.EventSource.LoggingEventSource; -namespace macaroni; - -internal class IntentRecognizerService : IIntentRecognizerService +namespace macaroni { - public IntentRecognizerService(IServiceProvider services, IBroadcastMessageService broadcastMessageService, IOnScreenDisplayService osd, IGlobalNamedStateService namedStateService) - { - _serviceProvider = services; - _broadcastMessageService = broadcastMessageService; - _osd = osd; - - var value = namedStateService.GetNamedState("__macaroni.defaultListeningState"); - if (value == null || !ListeningStateHelpers.TryParse(value, out _defaultListeningState)) - { - _defaultListeningState = ListeningState.Off; - } - - value = namedStateService.GetNamedState("__macaroni.allowPushToTalk"); - if (value == null || !bool.TryParse(value, out _allowPushToTalk)) - { - _allowPushToTalk = false; - } - - value = namedStateService.GetNamedState("__macaroni.useNuggets"); - if (value == null || !bool.TryParse(value, out _useNuggets)) - { - _useNuggets = false; - } - - value = namedStateService.GetNamedState("__macaroni.useCLU"); - if (value == null || !bool.TryParse(value, out _useCLU)) - { - _useCLU = false; - } - - value = namedStateService.GetNamedState("__macaroni.keyword"); - if (!string.IsNullOrEmpty(value)) - { - _keyword = value; - } - - value = namedStateService.GetNamedState("__macaroni.keywordModelFile"); - if (!string.IsNullOrEmpty(value)) - { - _keywordModelFile = value; - } - } - public Task StartAsync() + internal class IntentRecognizerService : IIntentRecognizerService { - if (IsEditorDesignMode()) + public IntentRecognizerService(IServiceProvider services, IBroadcastMessageService broadcastMessageService, IOnScreenDisplayService osd, IGlobalNamedStateService namedStateService) { - MR.DBG_TRACE_VERBOSE("IntentRecognizerService.StartAsync ... (in EditorDesignMode) ... Done!"); - return Task.CompletedTask; - } + _serviceProvider = services; + _broadcastMessageService = broadcastMessageService; + _osd = osd; - return Task.Run(() => - { - CheckInitCLU(); - - MR.DBG_TRACE_VERBOSE("IntentRecognizerService.StartAsync ..."); - SetState(_defaultListeningState); - HandleStarted(); - MR.DBG_TRACE_VERBOSE("IntentRecognizerService.StartAsync ... Done!"); - }); - } + var value = namedStateService.GetNamedState("__macaroni.defaultListeningState"); + if (value == null || !ListeningStateHelpers.TryParse(value, out _defaultListeningState)) + { + _defaultListeningState = ListeningState.Off; + } - public Task StopAsync() - { - return Task.Run(() => - { - MR.DBG_TRACE_VERBOSE("IntentRecognizerService.StopAsync ..."); - SetState(ListeningState.Off); - MR.DBG_TRACE_VERBOSE("IntentRecognizerService.StopAsync ... Done"); - }); - } + value = namedStateService.GetNamedState("__macaroni.allowPushToTalk"); + if (value == null || !bool.TryParse(value, out _allowPushToTalk)) + { + _allowPushToTalk = false; + } - public UInt64 SetState(ListeningState state) - { - lock (this) - { - var oldState = _state; - if (state == GetListeningState(oldState)) + value = namedStateService.GetNamedState("__macaroni.useNuggets"); + if (value == null || !bool.TryParse(value, out _useNuggets)) { - // don't need to do anything, unless we're restarting Once - MR.DBG_TRACE_INFO($"\n\n**** currentListeningState={state}, {_state}"); - if (state == ListeningState.Once) - { - ResetRecognizer(ref _recognizerOnce); - WaitForever(StartRecognizeOnceAsync()); - } + _useNuggets = false; } - else if (state == ListeningState.Off) + + value = namedStateService.GetNamedState("__macaroni.useCLU"); + if (value == null || !bool.TryParse(value, out _useCLU)) { - UpdateState32(ref _state, state); - ResetRecognizer(ref _recognizerOnce); - ResetRecognizer(ref _recognizerContinuous); - BroadcastRecognizerStateChanged(state); + _useCLU = false; } - else if (state == ListeningState.On) + + value = namedStateService.GetNamedState("__macaroni.keyword"); + if (!string.IsNullOrEmpty(value)) { - UpdateState32(ref _state, state); - WaitForever(StartRecognitionAsync()); - BroadcastRecognizerStateChanged(state); + _keyword = value; } - else if (state == ListeningState.Once) + + value = namedStateService.GetNamedState("__macaroni.keywordModelFile"); + if (!string.IsNullOrEmpty(value)) { - UpdateState32(ref _state, state); - WaitForever(StartRecognizeOnceAsync()); - BroadcastRecognizerStateChanged(state); + _keywordModelFile = value; } - else if (state == ListeningState.Sleep) + } + + public Task StartAsync() + { + if (IsEditorDesignMode()) { - UpdateState32(ref _state, state); - WaitForever(StartKeywordRecognitionAsync()); - BroadcastRecognizerStateChanged(state); + MR.DBG_TRACE_VERBOSE("IntentRecognizerService.StartAsync ... (in EditorDesignMode) ... Done!"); + return Task.CompletedTask; } - return GetStashState64(oldState, _state); + + return Task.Run(() => + { + CheckInitCLU(); + + MR.DBG_TRACE_VERBOSE("IntentRecognizerService.StartAsync ..."); + SetState(_defaultListeningState); + HandleStarted(); + MR.DBG_TRACE_VERBOSE("IntentRecognizerService.StartAsync ... Done!"); + }); } - } - public UInt64 RestoreState(UInt64 state) - { - lock (this) + public Task StopAsync() { - UnpackStashState64(state, out var state0, out var state1); - if (_state == state1) + return Task.Run(() => { - var restoring0 = GetListeningState(state0); + MR.DBG_TRACE_VERBOSE("IntentRecognizerService.StopAsync ..."); + SetState(ListeningState.Off); + MR.DBG_TRACE_VERBOSE("IntentRecognizerService.StopAsync ... Done"); + }); + } - if (restoring0 == GetListeningState(_state)) + public UInt64 SetState(ListeningState state) + { + lock (this) + { + var oldState = _state; + if (state == GetListeningState(oldState)) { // don't need to do anything, unless we're restarting Once - MR.DBG_TRACE_INFO($"\n\n**** currentListeningState={restoring0}, {_state}"); - if (restoring0 == ListeningState.Once) + MR.DBG_TRACE_INFO($"\n\n**** currentListeningState={state}, {_state}"); + if (state == ListeningState.Once) { ResetRecognizer(ref _recognizerOnce); WaitForever(StartRecognizeOnceAsync()); } } - else if (restoring0 == ListeningState.Off) + else if (state == ListeningState.Off) { - UpdateState32(ref _state, state0); + UpdateState32(ref _state, state); ResetRecognizer(ref _recognizerOnce); ResetRecognizer(ref _recognizerContinuous); - BroadcastRecognizerStateChanged(restoring0); + BroadcastRecognizerStateChanged(state); } - else if (restoring0 == ListeningState.On) + else if (state == ListeningState.On) { - UpdateState32(ref _state, state0); + UpdateState32(ref _state, state); WaitForever(StartRecognitionAsync()); - BroadcastRecognizerStateChanged(restoring0); + BroadcastRecognizerStateChanged(state); } - else if (restoring0 == ListeningState.Once) + else if (state == ListeningState.Once) { - UpdateState32(ref _state, state0); + UpdateState32(ref _state, state); WaitForever(StartRecognizeOnceAsync()); - BroadcastRecognizerStateChanged(restoring0); + BroadcastRecognizerStateChanged(state); } - else if (restoring0 == ListeningState.Sleep) + else if (state == ListeningState.Sleep) { - UpdateState32(ref _state, state0); + UpdateState32(ref _state, state); WaitForever(StartKeywordRecognitionAsync()); - BroadcastRecognizerStateChanged(restoring0); + BroadcastRecognizerStateChanged(state); } - return GetStashState64(state1, _state); + return GetStashState64(oldState, _state); } - return GetStashState64(_state, _state); } - } - public ListeningState GetState() - { - return GetListeningState(_state); - } + public UInt64 RestoreState(UInt64 state) + { + lock (this) + { + UnpackStashState64(state, out var state0, out var state1); + if (_state == state1) + { + var restoring0 = GetListeningState(state0); - public ListeningState GetDefaultState() - { - return _defaultListeningState; - } + if (restoring0 == GetListeningState(_state)) + { + // don't need to do anything, unless we're restarting Once + MR.DBG_TRACE_INFO($"\n\n**** currentListeningState={restoring0}, {_state}"); + if (restoring0 == ListeningState.Once) + { + ResetRecognizer(ref _recognizerOnce); + WaitForever(StartRecognizeOnceAsync()); + } + } + else if (restoring0 == ListeningState.Off) + { + UpdateState32(ref _state, state0); + ResetRecognizer(ref _recognizerOnce); + ResetRecognizer(ref _recognizerContinuous); + BroadcastRecognizerStateChanged(restoring0); + } + else if (restoring0 == ListeningState.On) + { + UpdateState32(ref _state, state0); + WaitForever(StartRecognitionAsync()); + BroadcastRecognizerStateChanged(restoring0); + } + else if (restoring0 == ListeningState.Once) + { + UpdateState32(ref _state, state0); + WaitForever(StartRecognizeOnceAsync()); + BroadcastRecognizerStateChanged(restoring0); + } + else if (restoring0 == ListeningState.Sleep) + { + UpdateState32(ref _state, state0); + WaitForever(StartKeywordRecognitionAsync()); + BroadcastRecognizerStateChanged(restoring0); + } + return GetStashState64(state1, _state); + } + return GetStashState64(_state, _state); + } + } - public void Emulate(string text) - { - var recognizer = CreateRecognizer(); - WaitForever(recognizer.RecognizeOnceAsync(text)); - } + public ListeningState GetState() + { + return GetListeningState(_state); + } - public void RegisterIntentCallback(string intentId, string? entityId, string groupId, Action callback) - { - lock (_callbacks) + public ListeningState GetDefaultState() { - var hasEntity = !string.IsNullOrEmpty(entityId); + return _defaultListeningState; + } - var needToCreate = !_callbacks.ContainsKey(intentId); - if (needToCreate) - { - _callbacks[intentId] = hasEntity - ? new IntentCallback(groupId, entityId!, callback) - : new IntentCallback(groupId, callback); - } - else if (hasEntity) - { - _callbacks[intentId].EntityCallbacks[entityId!] = callback; - } - else - { - _callbacks[intentId].Callback = callback; - } + public void Emulate(string text) + { + var recognizer = CreateRecognizer(); + WaitForever(recognizer.RecognizeOnceAsync(text)); } - } - public void RemoveIntentCallbackGroup(string groupId) - { - lock (_callbacks) + public void RegisterIntentCallback(string intentId, string? entityId, string groupId, Action callback) { - var copy = _callbacks.ToList(); - foreach (var callback in copy) + lock (_callbacks) { - if (callback.Value.GroupId == groupId) + var hasEntity = !string.IsNullOrEmpty(entityId); + + var needToCreate = !_callbacks.ContainsKey(intentId); + if (needToCreate) + { + _callbacks[intentId] = hasEntity + ? new IntentCallback(groupId, entityId!, callback) + : new IntentCallback(groupId, callback); + } + else if (hasEntity) { - _callbacks?.Remove(callback.Key); + _callbacks[intentId].EntityCallbacks[entityId!] = callback; + } + else + { + _callbacks[intentId].Callback = callback; } } } - } - public void LoadPatternMatchingModel(PatternMatchingModel model, Action matchedCallback) - { - MR.DBG_TRACE_INFO($"LoadPatternMatchingModel: {model.ModelId}"); - - lock (this) + public void RemoveIntentCallbackGroup(string groupId) { - _models?.Remove(model.ModelId); - _models?.Add(model); - - _recognizerOnce?.ApplyLanguageModels(_models); - _recognizerContinuous?.ApplyLanguageModels(_models); + lock (_callbacks) + { + var copy = _callbacks.ToList(); + foreach (var callback in copy) + { + if (callback.Value.GroupId == groupId) + { + _callbacks?.Remove(callback.Key); + } + } + } } - lock (_callbacks) + public void LoadPatternMatchingModel(PatternMatchingModel model, Action matchedCallback) { - _callbacks.Remove(model.ModelId); - _callbacks.Add(model.ModelId, new IntentCallback(model.ModelId, matchedCallback)); - foreach (var intent in model.Intents) + MR.DBG_TRACE_INFO($"LoadPatternMatchingModel: {model.ModelId}"); + + lock (this) { - _callbacks.Remove(intent.IntentId); - _callbacks.Add(intent.IntentId, new IntentCallback(model.ModelId, matchedCallback)); - } - } + _models?.Remove(model.ModelId); + _models?.Add(model); - MR.DBG_TRACE_VERBOSE($"LoadPatternMatchingModel: {model.ModelId} ... Done! ==> {_models?.Count()} model(s), {_callbacks.Count()}"); - } + _recognizerOnce?.ApplyLanguageModels(_models); + _recognizerContinuous?.ApplyLanguageModels(_models); + } - public void UnloadPatternMatchingModel(PatternMatchingModel model) - { - MR.DBG_TRACE_INFO($"UnloadPatternMatchingModel: {model.ModelId}"); + lock (_callbacks) + { + _callbacks.Remove(model.ModelId); + _callbacks.Add(model.ModelId, new IntentCallback(model.ModelId, matchedCallback)); + foreach (var intent in model.Intents) + { + _callbacks.Remove(intent.IntentId); + _callbacks.Add(intent.IntentId, new IntentCallback(model.ModelId, matchedCallback)); + } + } - lock (this) - { - _models.Remove(model.ModelId); + MR.DBG_TRACE_VERBOSE($"LoadPatternMatchingModel: {model.ModelId} ... Done! ==> {_models?.Count()} model(s), {_callbacks.Count()}"); } - lock (_callbacks) + public void UnloadPatternMatchingModel(PatternMatchingModel model) { - _callbacks.Remove(model.ModelId); - foreach (var item in model.Intents) + MR.DBG_TRACE_INFO($"UnloadPatternMatchingModel: {model.ModelId}"); + + lock (this) { - _callbacks.Remove(item.IntentId); + _models.Remove(model.ModelId); } - } - MR.DBG_TRACE_INFO($"UnloadPatternMatchingModel: {model.ModelId} ... Done! ==> {_models.Count()} model(s), {_callbacks.Count()}"); - } + lock (_callbacks) + { + _callbacks.Remove(model.ModelId); + foreach (var item in model.Intents) + { + _callbacks.Remove(item.IntentId); + } + } - private bool IsEditorDesignMode() - { - var resolve = _serviceProvider.GetRequiredService(); - var value = resolve.Get("IsEditorDesignMode", null); - return value != null && value is string && value as string == "true"; - } + MR.DBG_TRACE_INFO($"UnloadPatternMatchingModel: {model.ModelId} ... Done! ==> {_models.Count()} model(s), {_callbacks.Count()}"); + } - private void CheckInitCLU() - { - if (_useCLU) + private bool IsEditorDesignMode() { - InitCLU(); + var resolve = _serviceProvider.GetRequiredService(); + var value = resolve.Get("IsEditorDesignMode", null); + return value != null && value is string && value as string == "true"; } - } - - private void InitCLU() - { - //TODO: this should come from some extension that handles declarations of CLU models. Also should we - // support multiple CLU projects? - var settings = _serviceProvider.GetRequiredService(); - var key = settings.Get("CLU_KEY")?.Trim(); - var endpoint = settings.Get("CLU_ENDPOINT")?.Trim(); - var project = settings.Get("CLU_PROJECT_NAME")?.Trim(); - var deployment = settings.Get("CLU_DEPLOYMENT_NAME")?.Trim(); - // only create the model if we have everything - if ((key ?? endpoint ?? project ?? deployment) != null) + private void CheckInitCLU() { - var cluMode = new ConversationalLanguageUnderstandingModel(key, endpoint, project, deployment); - _models.Add(new ConversationalLanguageUnderstandingModel(key, endpoint, project, deployment)); + if (_useCLU) + { + InitCLU(); + } } - // end TODO - } - private void ResetRecognizer(ref IntentRecognizer? recognizer) - { - lock (this) + private void InitCLU() { - if (recognizer != null) + //TODO: this should come from some extension that handles declarations of CLU models. Also should we + // support multiple CLU projects? + var settings = _serviceProvider.GetRequiredService(); + var key = settings.Get("CLU_KEY")?.Trim(); + var endpoint = settings.Get("CLU_ENDPOINT")?.Trim(); + var project = settings.Get("CLU_PROJECT_NAME")?.Trim(); + var deployment = settings.Get("CLU_DEPLOYMENT_NAME")?.Trim(); + + // only create the model if we have everything + if ((key ?? endpoint ?? project ?? deployment) != null) { - _ = DisposeAsync(recognizer); - recognizer = null; + var cluMode = new ConversationalLanguageUnderstandingModel(key, endpoint, project, deployment); + _models.Add(new ConversationalLanguageUnderstandingModel(key, endpoint, project, deployment)); } + // end TODO } - } - private IntentRecognizer EnsureRecognizer(ref IntentRecognizer? recognizer) - { - lock (this) + private void ResetRecognizer(ref IntentRecognizer? recognizer) { - if (recognizer == null) + lock (this) { - recognizer = CreateRecognizer(); + if (recognizer != null) + { + _ = DisposeAsync(recognizer); + recognizer = null; + } } - return recognizer; } - } - - private IntentRecognizer CreateRecognizer(bool applyLanguageModels = true) - { - MR.DBG_TRACE_VERBOSE("New IntentRecognizer ..."); - var recognizer = CreateIntentRecognizer(); - _createdRecognizerTime = DateTime.Now; - recognizer.SessionStarted += (s, e) => HandleStarted(); - recognizer.SessionStopped += (s, e) => HandleStopped(); - recognizer.Canceled += (s, e) => HandleCanceled(s, e); - recognizer.Recognizing += (s, e) => HandleRecognizing(s, e.Result); - recognizer.Recognized += (s, e) => HandleRecognized(s, e.Result); - MR.DBG_TRACE_VERBOSE("New IntentRecognizer ... Part1 Done!"); - - lock (this) + private IntentRecognizer EnsureRecognizer(ref IntentRecognizer? recognizer) { - if (applyLanguageModels && _models.Count > 0) recognizer.ApplyLanguageModels(_models); - - if (_keywordModel == null && _keywordModelFile != null) + lock (this) { - _keywordModel = LoadKeywordModelFromFile(_keywordModelFile); + if (recognizer == null) + { + recognizer = CreateRecognizer(); + } + return recognizer; } } - MR.DBG_TRACE_VERBOSE("New IntentRecognizer ... All Done!"); - return recognizer; - } + private IntentRecognizer CreateRecognizer(bool applyLanguageModels = true) + { + MR.DBG_TRACE_VERBOSE("New IntentRecognizer ..."); + var recognizer = CreateIntentRecognizer(); + _createdRecognizerTime = DateTime.Now; - private IntentRecognizer CreateIntentRecognizer() - { - var audio = GetAudioConfig(); + recognizer.SessionStarted += (s, e) => HandleStarted(); + recognizer.SessionStopped += (s, e) => HandleStopped(); + recognizer.Canceled += (s, e) => HandleCanceled(s, e); + recognizer.Recognizing += (s, e) => HandleRecognizing(s, e.Result); + recognizer.Recognized += (s, e) => HandleRecognized(s, e.Result); + MR.DBG_TRACE_VERBOSE("New IntentRecognizer ... Part1 Done!"); - var embeddedConfig = GetEmbeddedSpeechConfig(); - if (embeddedConfig != null) - { - try - { - return new IntentRecognizer(embeddedConfig, audio); - } - catch (Exception) + lock (this) { - MR.DBG_TRACE_ERROR("Failed to create embedded IntentRecognizer"); + if (applyLanguageModels && _models.Count > 0) recognizer.ApplyLanguageModels(_models); + + if (_keywordModel == null && _keywordModelFile != null) + { + _keywordModel = LoadKeywordModelFromFile(_keywordModelFile); + } } - } - return new IntentRecognizer(GetSpeechConfig(), audio); - } + MR.DBG_TRACE_VERBOSE("New IntentRecognizer ... All Done!"); + return recognizer; + } - private KeywordRecognitionModel? LoadKeywordModelFromFile(string? keywordModelFile) - { - var exists = File.Exists(keywordModelFile!); - if (!exists) + private IntentRecognizer CreateIntentRecognizer() { - var folder = GetMacrosFolder(); - var check = Path.Combine(folder, keywordModelFile!); + var audio = GetAudioConfig(); - exists = File.Exists(check); - if (!exists) + var embeddedConfig = GetEmbeddedSpeechConfig(); + if (embeddedConfig != null) { - check = Path.Combine(folder, "keywords", keywordModelFile!); - exists = File.Exists(check); + try + { + return new IntentRecognizer(embeddedConfig, audio); + } + catch (Exception) + { + MR.DBG_TRACE_ERROR("Failed to create embedded IntentRecognizer"); + } } - } - if (exists) - { - MR.DBG_TRACE_INFO($"Loading keyword model from {keywordModelFile!} ..."); - return KeywordRecognitionModel.FromFile(keywordModelFile!); + return new IntentRecognizer(GetSpeechConfig(), audio); } - return null; - } + private KeywordRecognitionModel? LoadKeywordModelFromFile(string? keywordModelFile) + { + var exists = File.Exists(keywordModelFile!); + if (!exists) + { + var folder = GetMacrosFolder(); + var check = Path.Combine(folder, keywordModelFile!); - private SpeechConfig GetSpeechConfig() - { - var service = _serviceProvider.GetRequiredService(); - var config = service.GetSpeechConfig(SpeechConfigKind.SpeechRecognition); - config.SetProperty("KeywordConfig_EnableKeywordVerification", "true"); - return config; - } + exists = File.Exists(check); + if (!exists) + { + check = Path.Combine(folder, "keywords", keywordModelFile!); + exists = File.Exists(check); + } + } - private EmbeddedSpeechConfig? GetEmbeddedSpeechConfig() - { - var service = _serviceProvider.GetRequiredService(); - return service.GetEmbeddedSpeechConfig(); - } + if (exists) + { + MR.DBG_TRACE_INFO($"Loading keyword model from {keywordModelFile!} ..."); + return KeywordRecognitionModel.FromFile(keywordModelFile!); + } - private AudioConfig GetAudioConfig() - { - return _serviceProvider.GetRequiredService().GetAudioConfig(); - } + return null; + } - private Task StartRecognitionAsync() - { - EnsureStopSpeaking(); - lock (this) + private SpeechConfig GetSpeechConfig() { - ResetRecognizer(ref _recognizerOnce); - EnsureRecognizer(ref _recognizerContinuous); - return _recognizerContinuous!.StartContinuousRecognitionAsync(); + var service = _serviceProvider.GetRequiredService(); + var config = service.GetSpeechConfig(SpeechConfigKind.SpeechRecognition); + config.SetProperty("KeywordConfig_EnableKeywordVerification", "true"); + return config; } - } - private Task StartRecognizeOnceAsync() - { - EnsureStopSpeaking(); - lock (this) + private EmbeddedSpeechConfig? GetEmbeddedSpeechConfig() { - ResetRecognizer(ref _recognizerContinuous); - EnsureRecognizer(ref _recognizerOnce); - _ = _recognizerOnce!.RecognizeOnceAsync(); - return Task.CompletedTask; // No task in Carbon corresponding to "started" RecognizeOnceAsync + var service = _serviceProvider.GetRequiredService(); + return service.GetEmbeddedSpeechConfig(); } - } - private Task StartKeywordRecognitionAsync() - { - EnsureStopSpeaking(); - lock (this) + private AudioConfig GetAudioConfig() { - ResetRecognizer(ref _recognizerOnce); - ResetRecognizer(ref _recognizerContinuous); - EnsureRecognizer(ref _recognizerOnce); - - if (_keywordModel == null) - { - MR.DBG_TRACE_ERROR("Keyword model not loaded"); - return Task.CompletedTask; - } - - return _recognizerOnce!.StartKeywordRecognitionAsync(_keywordModel); + return _serviceProvider.GetRequiredService().GetAudioConfig(); } - } - private void EnsureStopSpeaking(int waitForStopInMs = 500) - { - lock (this) + private Task StartRecognitionAsync() { - if (_synthesizer == null) + EnsureStopSpeaking(); + lock (this) { - _synthesizer = _serviceProvider.GetRequiredService(); + ResetRecognizer(ref _recognizerOnce); + EnsureRecognizer(ref _recognizerContinuous); + return _recognizerContinuous!.StartContinuousRecognitionAsync(); } } - _synthesizer.StopSpeaking().Wait(waitForStopInMs); - } - - private void HandleStarted() - { - // display "Started!" the very first time we start... - _started += 1; - if (_started == 1) + private Task StartRecognizeOnceAsync() { - _osd.DisplayText("Started!!", "SYSTEM", false); + EnsureStopSpeaking(); + lock (this) + { + ResetRecognizer(ref _recognizerContinuous); + EnsureRecognizer(ref _recognizerOnce); + _ = _recognizerOnce!.RecognizeOnceAsync(); + return Task.CompletedTask; // No task in Carbon corresponding to "started" RecognizeOnceAsync + } } - MR.DBG_TRACE_VERBOSE("SESSION STARTED"); - EnsureStopSpeaking(0); - } - - private void HandleStopped() - { - // _osd.UpdateText("Stopped!!"); - MR.DBG_TRACE_VERBOSE("SESSION STOPPED"); - } - - private void HandleCanceled(object? sender, IntentRecognitionCanceledEventArgs e) - { - if (sender != _recognizerOnce && sender != _recognizerContinuous) return; - - MR.DBG_TRACE_WARNING($"Canceled \n Reason:{e.Reason.ToString()}\n Details:{e.ErrorDetails} "); - if (e.Reason == CancellationReason.Error) + private Task StartKeywordRecognitionAsync() { - var details = CancellationDetails.FromResult(e.Result); - var asJson = JsonConvert.SerializeObject(details); + EnsureStopSpeaking(); + lock (this) + { + ResetRecognizer(ref _recognizerOnce); + ResetRecognizer(ref _recognizerContinuous); + EnsureRecognizer(ref _recognizerOnce); - var stateOffAsync = Task.Run(() => { - lock (this) + if (_keywordModel == null) { - ResetRecognizer(ref _recognizerOnce); - ResetRecognizer(ref _recognizerContinuous); - SetState(ListeningState.Off); + MR.DBG_TRACE_ERROR("Keyword model not loaded"); + return Task.CompletedTask; } - }); - MR.DBG_TRACE_ERROR($"HandleCanceled: full details={asJson}"); - BroadcastRecognitionError(asJson); - - stateOffAsync.Wait(1000); + return _recognizerOnce!.StartKeywordRecognitionAsync(_keywordModel); + } } - } - private void HandleRecognizing(object? sender, IntentRecognitionResult result) - { - if (IsValidResult(sender, result)) + private void EnsureStopSpeaking(int waitForStopInMs = 500) { - EnsureStopSpeaking(0); + lock (this) + { + if (_synthesizer == null) + { + _synthesizer = _serviceProvider.GetRequiredService(); + } + } - _osd.DisplayText(result.Text, "USER", true); - MR.DBG_TRACE_VERBOSE($"RECOGNIZING: {result.IntentId}: {result.Text}"); + _synthesizer.StopSpeaking().Wait(waitForStopInMs); } - } - - private void HandleRecognized(object? sender, IntentRecognitionResult result) - { - var isValidResult = IsValidResult(sender, result); // check before we potentially reset the recognizer - CheckSetListeningStateAfterOnceReco(sender, result); - if (isValidResult) + private void HandleStarted() { - _osd.DisplayText(result.Text, "USER", false); - MR.DBG_TRACE_VERBOSE($"RECOGNIZED: {result.IntentId}: {result.Text} ({result.ResultId})\n"); - - NotifyNuggetUserText(result.Text); - - if (result.Reason == ResultReason.RecognizedIntent) - { - HandleRecognizedIntentCallback(result, () => - HandleRecognizedSpeechCallback(result)); - } - else + // display "Started!" the very first time we start... + _started += 1; + if (_started == 1) { - HandleRecognizedSpeechCallback(result); + _osd.DisplayText("Started!!", "SYSTEM", false); } + + MR.DBG_TRACE_VERBOSE("SESSION STARTED"); + EnsureStopSpeaking(0); } - } - private bool IsValidResult(object? sender, IntentRecognitionResult result) - { - if (string.IsNullOrEmpty(result.Text)) + private void HandleStopped() { - MR.DBG_TRACE_VERBOSE($"IGNORING result: '(empty)'"); - return false; + // _osd.UpdateText("Stopped!!"); + MR.DBG_TRACE_VERBOSE("SESSION STOPPED"); } - if (!_allowPushToTalk && !IsEmulatedResult(result) && !IsValidRecognizer(sender as IntentRecognizer)) + private void HandleCanceled(object? sender, IntentRecognitionCanceledEventArgs e) { - MR.DBG_TRACE_VERBOSE($"IGNORING result: '{result.Text}' (invalid recognizer)"); - return false; - } + if (sender != _recognizerOnce && sender != _recognizerContinuous) return; - return true; - } + MR.DBG_TRACE_WARNING($"Canceled \n Reason:{e.Reason.ToString()}\n Details:{e.ErrorDetails} "); + if (e.Reason == CancellationReason.Error) + { + var details = CancellationDetails.FromResult(e.Result); + var asJson = JsonConvert.SerializeObject(details); - private static bool IsEmulatedResult(IntentRecognitionResult result) - { - return result.OffsetInTicks == 0 && result.Duration == TimeSpan.Zero; - } + var stateOffAsync = Task.Run(() => + { + lock (this) + { + ResetRecognizer(ref _recognizerOnce); + ResetRecognizer(ref _recognizerContinuous); + SetState(ListeningState.Off); + } + }); - private bool IsValidRecognizer(IntentRecognizer? recognizer) - { - lock (this) - { - return recognizer != null && (recognizer == _recognizerOnce || recognizer == _recognizerContinuous); - } - } + MR.DBG_TRACE_ERROR($"HandleCanceled: full details={asJson}"); + BroadcastRecognitionError(asJson); - private void CheckSetListeningStateAfterOnceReco(object? sender, IntentRecognitionResult result) - { - lock (this) - { - if (GetState() == ListeningState.Once && sender == _recognizerOnce) - { - MR.DBG_TRACE_VERBOSE($"SETTING OFF/SLEEP BECAUSE once completed ({_defaultListeningState})"); - SetState(_defaultListeningState); + stateOffAsync.Wait(1000); } } - } - private void HandleRecognizedIntentCallback(IntentRecognitionResult result, Action notHandled) - { - var handled = false; - - MR.DBG_TRACE_INFO($"RESULT: intentId={result.IntentId}"); - foreach (var e in result.Entities) + private void HandleRecognizing(object? sender, IntentRecognitionResult result) { - MR.DBG_TRACE_INFO($"RESULT: entity: {e.Key}={e.Value}"); + if (IsValidResult(sender, result)) + { + EnsureStopSpeaking(0); + + _osd.DisplayText(result.Text, "USER", true); + MR.DBG_TRACE_VERBOSE($"RECOGNIZING: {result.IntentId}: {result.Text}"); + } } - if (_callbacks.TryGetValue(result.IntentId, out var intentCallback)) + private void HandleRecognized(object? sender, IntentRecognitionResult result) { - MR.DBG_TRACE_INFO($"RESULT: intentId={result.IntentId} (found one or more callbacks by intentId)"); - var matches = intentCallback.EntityCallbacks.Keys.Where(x => result.Entities.ContainsKey(x)); + CheckSetListeningStateAfterOnceReco(sender, result); - var matchFound = matches.Count() > 0; - if (matchFound) + if (IsValidResult(sender, result)) { - MR.DBG_TRACE_INFO($"RESULT: intentId={result.IntentId} (found callback by entityId; entity={matches.Last()})"); - } + _osd.DisplayText(result.Text, "USER", false); + MR.DBG_TRACE_VERBOSE($"RECOGNIZED: {result.IntentId}: {result.Text} ({result.ResultId})\n"); - var actualCallback = matchFound - ? intentCallback.EntityCallbacks[matches.Last()] - : intentCallback.Callback; + NotifyNuggetUserText(result.Text); - if (actualCallback != null) - { - var resultJson = result.Properties.GetProperty(PropertyId.LanguageUnderstandingServiceResponse_JsonResult); - if (string.IsNullOrEmpty(resultJson)) + if (result.Reason == ResultReason.RecognizedIntent) { - MR.DBG_TRACE_INFO($"RESULT: intentId={result.IntentId} (calling callback w/ result IntentId and Entities)"); - actualCallback(new IntentResult(result, result.IntentId, result.Entities)); + HandleRecognizedIntentCallback(result, () => + HandleRecognizedSpeechCallback(result)); } else { - MR.DBG_TRACE_INFO($"RESULT: intentId={result.IntentId} (calling callback w/ json parsed intentId and entities)"); - var cluService = _serviceProvider.GetRequiredService(); - var stream = new MemoryStream(Encoding.UTF8.GetBytes(resultJson)); - cluService.ParseCLUJsonResponseStream(stream, out var intentId, out var entities, out var entitiesJson); - - actualCallback(new IntentResult(result, result.IntentId, entities, entitiesJson)); + HandleRecognizedSpeechCallback(result); } - handled = true; } } - if (!handled) + private bool IsValidResult(object? sender, IntentRecognitionResult result) { - MR.DBG_TRACE_INFO($"RESULT: intentId={result.IntentId} (no matching callback found); {_callbacks.Count()} callback(s) registered"); - notHandled(); - } - } + if (string.IsNullOrEmpty(result.Text)) + { + MR.DBG_TRACE_VERBOSE($"IGNORING result: '(empty)'"); + return false; + } - private void HandleRecognizedSpeechCallback(IntentRecognitionResult result) - { - if (!string.IsNullOrEmpty(_keyword) && result.Text.StartsWith(_keyword)) - { - HandleKeywordStripAndRetryViaEmulation(result); - } - else if (result.Reason == ResultReason.RecognizedSpeech) - { - HandleCluDirect(result, () => - HandleNuggetExecution(result, () => - HandledUnexpectedPhrase(result)) - ); - } - else if (result.Reason == ResultReason.RecognizedIntent) - { - HandleNuggetExecution(result, () => - HandledUnexpectedPhrase(result) - ); + if (!_allowPushToTalk && !IsEmulatedResult(result) && !IsValidRecognizer(sender as IntentRecognizer)) + { + MR.DBG_TRACE_VERBOSE($"IGNORING result: '{result.Text}' (invalid recognizer)"); + return false; + } + + return true; } - else + + private static bool IsEmulatedResult(IntentRecognitionResult result) { - HandledUnexpectedPhrase(result); + return result.OffsetInTicks == 0 && result.Duration == TimeSpan.Zero; } - } - - private void HandleKeywordStripAndRetryViaEmulation(IntentRecognitionResult result) - { - var emulate = result.Text.Remove(0, _keyword!.Length).Trim(',', '.', ' '); - - EnsureRecognizer(ref _recognizerOnce); - _ = _recognizerOnce?.RecognizeOnceAsync(emulate); - } - private async void HandleCluDirect(IntentRecognitionResult result, Action notHandled) - { - var handled = false; - try + private bool IsValidRecognizer(IntentRecognizer? recognizer) { - if (_useCLU) + lock (this) { - handled = await TryHandleCluDirect(result); + return recognizer != null && (recognizer == _recognizerOnce || recognizer == _recognizerContinuous); } } - catch (Exception ex) + + private void CheckSetListeningStateAfterOnceReco(object? sender, IntentRecognitionResult result) { - BroadcastRuntimeException(ex); + lock (this) + { + if (GetState() == ListeningState.Once && sender == _recognizerOnce) + { + MR.DBG_TRACE_VERBOSE($"SETTING OFF/SLEEP BECAUSE once completed ({_defaultListeningState})"); + SetState(_defaultListeningState); + } + } } - finally + + private void HandleRecognizedIntentCallback(IntentRecognitionResult result, Action notHandled) { - if (!handled) + var handled = false; + + MR.DBG_TRACE_INFO($"RESULT: intentId={result.IntentId}"); + foreach (var e in result.Entities) { - notHandled(); + MR.DBG_TRACE_INFO($"RESULT: entity: {e.Key}={e.Value}"); } - } - } - private async Task TryHandleCluDirect(IntentRecognitionResult result) - { - bool handled = false; + if (_callbacks.TryGetValue(result.IntentId, out var intentCallback)) + { + MR.DBG_TRACE_INFO($"RESULT: intentId={result.IntentId} (found one or more callbacks by intentId)"); + var matches = intentCallback.EntityCallbacks.Keys.Where(x => result.Entities.ContainsKey(x)); - var cluService = _serviceProvider.GetRequiredService(); - var cluResult = await cluService.CheckCLUAsync(result.Text); + var matchFound = matches.Count() > 0; + if (matchFound) + { + MR.DBG_TRACE_INFO($"RESULT: intentId={result.IntentId} (found callback by entityId; entity={matches.Last()})"); + } - MR.DBG_TRACE_INFO($"CLU DIRECT: intentId={cluResult.intentId}"); - foreach (var e in cluResult.entities) - { - MR.DBG_TRACE_INFO($"CLU DIRECT: entity: {e.Key}={e.Value}"); - } + var actualCallback = matchFound + ? intentCallback.EntityCallbacks[matches.Last()] + : intentCallback.Callback; - if (_callbacks.TryGetValue(cluResult.intentId, out var intentCallback)) - { - MR.DBG_TRACE_INFO($"CLU DIRECT: intentId={cluResult.intentId} (found one or more callbacks by intentId)"); - var matches = intentCallback.EntityCallbacks.Keys.Where(x => cluResult.entities.ContainsKey(x)); + if (actualCallback != null) + { + var resultJson = result.Properties.GetProperty(PropertyId.LanguageUnderstandingServiceResponse_JsonResult); + if (string.IsNullOrEmpty(resultJson)) + { + MR.DBG_TRACE_INFO($"RESULT: intentId={result.IntentId} (calling callback w/ result IntentId and Entities)"); + actualCallback(new IntentResult(result, result.IntentId, result.Entities)); + } + else + { + MR.DBG_TRACE_INFO($"RESULT: intentId={result.IntentId} (calling callback w/ json parsed intentId and entities)"); + var cluService = _serviceProvider.GetRequiredService(); + var stream = new MemoryStream(Encoding.UTF8.GetBytes(resultJson)); + cluService.ParseCLUJsonResponseStream(stream, out var intentId, out var entities, out var entitiesJson); - var matchFound = matches.Count() > 0; - if (matchFound) - { - MR.DBG_TRACE_INFO($"CLU DIRECT: intentId={cluResult.intentId} (found callback by entityId; entity={matches.Last()})"); + actualCallback(new IntentResult(result, result.IntentId, entities, entitiesJson)); + } + handled = true; + } } - var actualCallback = matchFound - ? intentCallback.EntityCallbacks[matches.Last()] - : intentCallback.Callback; - - if (actualCallback != null) + if (!handled) { - MR.DBG_TRACE_INFO($"CLU DIRECT: intentId={cluResult.intentId} (calling callback)"); - actualCallback(new IntentResult(result, cluResult.intentId, cluResult.entities, cluResult.entitiesJson)); - handled = true; + MR.DBG_TRACE_INFO($"RESULT: intentId={result.IntentId} (no matching callback found); {_callbacks.Count()} callback(s) registered"); + notHandled(); } } - if (!handled) + private void HandleRecognizedSpeechCallback(IntentRecognitionResult result) { - MR.DBG_TRACE_INFO($"CLU DIRECT: intentId={cluResult.intentId} (no matching callback found)"); + if (!string.IsNullOrEmpty(_keyword) && result.Text.StartsWith(_keyword)) + { + HandleKeywordStripAndRetryViaEmulation(result); + } + else if (result.Reason == ResultReason.RecognizedSpeech) + { + HandleCluDirect(result, () => + HandleNuggetExecution(result, () => + HandledUnexpectedPhrase(result)) + ); + } + else if (result.Reason == ResultReason.RecognizedIntent) + { + HandleNuggetExecution(result, () => + HandledUnexpectedPhrase(result) + ); + } + else + { + HandledUnexpectedPhrase(result); + } } - return handled; - } + private void HandleKeywordStripAndRetryViaEmulation(IntentRecognitionResult result) + { + var emulate = result.Text.Remove(0, _keyword!.Length).Trim(',', '.', ' '); - private async void HandleNuggetExecution(IntentRecognitionResult result, Action notHandled) - { - var handled = false; - try + EnsureRecognizer(ref _recognizerOnce); + _ = _recognizerOnce?.RecognizeOnceAsync(emulate); + } + + private async void HandleCluDirect(IntentRecognitionResult result, Action notHandled) { - if (_useNuggets) + var handled = false; + try { - var nuggetService = _serviceProvider.GetRequiredService(); - handled = await nuggetService.ExecuteAsync(result.Text); + if (_useCLU) + { + handled = await TryHandleCluDirect(result); + } + } + catch (Exception ex) + { + BroadcastRuntimeException(ex); + } + finally + { + if (!handled) + { + notHandled(); + } } - } - catch (Exception ex) - { - MR.DBG_TRACE_ERROR($"EXCEPTION: {ex.ToString()}"); } - if (!handled) + private async Task TryHandleCluDirect(IntentRecognitionResult result) { - notHandled(); - } - } + bool handled = false; - private void HandledUnexpectedPhrase(IntentRecognitionResult result) - { - BroadcastUnexpectedPhraseMessage(result); - } + var cluService = _serviceProvider.GetRequiredService(); + var cluResult = await cluService.CheckCLUAsync(result.Text); - private void BroadcastUnexpectedPhraseMessage(IntentRecognitionResult result) - { - MR.DBG_TRACE_VERBOSE($"UNKNOWN PHRASE: {result.Text}"); - _broadcastMessageService.BroadcastMessage("unexpected.phrase", result.Text, null); - } + MR.DBG_TRACE_INFO($"CLU DIRECT: intentId={cluResult.intentId}"); + foreach (var e in cluResult.entities) + { + MR.DBG_TRACE_INFO($"CLU DIRECT: entity: {e.Key}={e.Value}"); + } - private Task DisposeAsync(IntentRecognizer recognizer) - { - return Task.Run(() => { - try + if (_callbacks.TryGetValue(cluResult.intentId, out var intentCallback)) { - var stop = recognizer.StopContinuousRecognitionAsync(); - WaitForever(stop); + MR.DBG_TRACE_INFO($"CLU DIRECT: intentId={cluResult.intentId} (found one or more callbacks by intentId)"); + var matches = intentCallback.EntityCallbacks.Keys.Where(x => cluResult.entities.ContainsKey(x)); + + var matchFound = matches.Count() > 0; + if (matchFound) + { + MR.DBG_TRACE_INFO($"CLU DIRECT: intentId={cluResult.intentId} (found callback by entityId; entity={matches.Last()})"); + } + + var actualCallback = matchFound + ? intentCallback.EntityCallbacks[matches.Last()] + : intentCallback.Callback; + + if (actualCallback != null) + { + MR.DBG_TRACE_INFO($"CLU DIRECT: intentId={cluResult.intentId} (calling callback)"); + actualCallback(new IntentResult(result, cluResult.intentId, cluResult.entities, cluResult.entitiesJson)); + handled = true; + } } - catch (Exception ex) + + if (!handled) { - _hackDeadRecognizers.Add(recognizer); - MR.DBG_TRACE_WARNING($"WARNING: Exception when stopping recognition while disposing recognizer... {ex} (deadRecognizers={_hackDeadRecognizers.Count()})"); - return; + MR.DBG_TRACE_INFO($"CLU DIRECT: intentId={cluResult.intentId} (no matching callback found)"); } - MR.DBG_TRACE_INFO("DisposeAsync: Stopping recognizer... Done."); + return handled; + } + + private async void HandleNuggetExecution(IntentRecognitionResult result, Action notHandled) + { + var handled = false; try { - MR.DBG_TRACE_INFO("DisposeAsync: Disposing recognizer..."); - recognizer.Dispose(); + if (_useNuggets) + { + var nuggetService = _serviceProvider.GetRequiredService(); + handled = await nuggetService.ExecuteAsync(result.Text); + } } catch (Exception ex) { - MR.DBG_TRACE_WARNING($"WARNING: Exception when disposing recognizer... {ex}"); + MR.DBG_TRACE_ERROR($"EXCEPTION: {ex.ToString()}"); } - finally + + if (!handled) { - MR.DBG_TRACE_INFO("DisposeAsync: Disposing recognizer... Done."); + notHandled(); } - }); - } + } - private void BroadcastRecognizerStateChanged(ListeningState state) - { - var value = state.ToString(); - _broadcastMessageService.BroadcastMessage("recognizer.state.changed", value, null); - } + private void HandledUnexpectedPhrase(IntentRecognitionResult result) + { + BroadcastUnexpectedPhraseMessage(result); + } - private void BroadcastRecognitionError(string asJson) - { - BroadcastSystemException(new CommandSystemException(asJson)); - } + private void BroadcastUnexpectedPhraseMessage(IntentRecognitionResult result) + { + MR.DBG_TRACE_VERBOSE($"UNKNOWN PHRASE: {result.Text}"); + _broadcastMessageService.BroadcastMessage("unexpected.phrase", result.Text, null); + } - internal class IntentCallback - { - internal IntentCallback(string groupId, Action callback) + private Task DisposeAsync(IntentRecognizer recognizer) { - GroupId = groupId; - Callback = callback; + return Task.Run(() => + { + try + { + var stop = recognizer.StopContinuousRecognitionAsync(); + WaitForever(stop); + } + catch (Exception ex) + { + _hackDeadRecognizers.Add(recognizer); + MR.DBG_TRACE_WARNING($"WARNING: Exception when stopping recognition while disposing recognizer... {ex} (deadRecognizers={_hackDeadRecognizers.Count()})"); + return; + } + MR.DBG_TRACE_INFO("DisposeAsync: Stopping recognizer... Done."); + + try + { + MR.DBG_TRACE_INFO("DisposeAsync: Disposing recognizer..."); + recognizer.Dispose(); + } + catch (Exception ex) + { + MR.DBG_TRACE_WARNING($"WARNING: Exception when disposing recognizer... {ex}"); + } + finally + { + MR.DBG_TRACE_INFO("DisposeAsync: Disposing recognizer... Done."); + } + }); } - internal IntentCallback(string groupId, string entityId, Action callback) + private void BroadcastRecognizerStateChanged(ListeningState state) { - GroupId = groupId; - EntityCallbacks[entityId] = callback; + var value = state.ToString(); + _broadcastMessageService.BroadcastMessage("recognizer.state.changed", value, null); } - internal string GroupId; - internal Action? Callback; - internal Dictionary> EntityCallbacks = new(); - } + private void BroadcastRecognitionError(string asJson) + { + BroadcastSystemException(new CommandSystemException(asJson)); + } - private static UInt32 UpdateState32(ref UInt32 state, ListeningState newState) - { - var oldState = state; + internal class IntentCallback + { + internal IntentCallback(string groupId, Action callback) + { + GroupId = groupId; + Callback = callback; + } - var span = Enum.GetValues().Cast().Max() + 1; - state = (oldState / span + 1) * span + (UInt32)(newState); - MR.DBG_TRACE_INFO($"\n\n**** newListeningState={state}, {newState}"); + internal IntentCallback(string groupId, string entityId, Action callback) + { + GroupId = groupId; + EntityCallbacks[entityId] = callback; + } - return state; - } + internal string GroupId; + internal Action? Callback; + internal Dictionary> EntityCallbacks = new Dictionary>(); + } - private static UInt32 UpdateState32(ref UInt32 state, UInt32 newState) - { - state = newState; + private static UInt32 UpdateState32(ref UInt32 state, ListeningState newState) + { + var oldState = state; - var span = Enum.GetValues().Cast().Max() + 1; - MR.DBG_TRACE_INFO($"\n\n**** newListeningState={state}, {(ListeningState)(newState % span)}"); + var span = Enum.GetValues(typeof(ListeningState)).Cast().Max() + 1; + state = (oldState / span + 1) * span + (UInt32)(newState); + MR.DBG_TRACE_INFO($"\n\n**** newListeningState={state}, {newState}"); - return state; - } + return state; + } - private static UInt64 GetStashState64(UInt32 oldState, UInt32 newState) - { - var stash = ((UInt64)(oldState) << 32) + newState; - return stash; - } + private static UInt32 UpdateState32(ref UInt32 state, UInt32 newState) + { + state = newState; - private static void UnpackStashState64(UInt64 state, out UInt32 oldState, out UInt32 newState) - { - oldState = (UInt32)(state >> 32); - newState = (UInt32)(state & 0xffffffff); - } + var span = Enum.GetValues(typeof(ListeningState)).Cast().Max() + 1; + MR.DBG_TRACE_INFO($"\n\n**** newListeningState={state}, {(ListeningState)(newState % span)}"); - private static ListeningState GetListeningState(UInt64 state) - { - var span = Enum.GetValues().Cast().Max() + 1; - return (ListeningState)(state % span); - } + return state; + } - private string GetMacrosFolder() - { - var context = _serviceProvider.GetRequiredService(); - var folder = context.Get("folders.macros", null) as string ?? "."; - return folder; - } + private static UInt64 GetStashState64(UInt32 oldState, UInt32 newState) + { + var stash = ((UInt64)(oldState) << 32) + newState; + return stash; + } - private void WaitForever(Task? task, int foreverIsActually = 30000) - { - if (task != null) + private static void UnpackStashState64(UInt64 state, out UInt32 oldState, out UInt32 newState) + { + oldState = (UInt32)(state >> 32); + newState = (UInt32)(state & 0xffffffff); + } + + private static ListeningState GetListeningState(UInt64 state) + { + var span = Enum.GetValues(typeof(ListeningState)).Cast().Max() + 1; + return (ListeningState)(state % span); + } + + private string GetMacrosFolder() { - var completed = task.Wait(foreverIsActually); - if (!completed) + var context = _serviceProvider.GetRequiredService(); + var folder = context.Get("folders.macros", null) as string ?? "."; + return folder; + } + + private void WaitForever(Task? task, int foreverIsActually = 30000) + { + if (task != null) { - MR.DBG_TRACE_WARNING($"WARNING: Task did not complete in {foreverIsActually}ms. This is probably a bug."); - throw new TimeoutException($"Task did not complete in {foreverIsActually}ms."); + var completed = task.Wait(foreverIsActually); + if (!completed) + { + MR.DBG_TRACE_WARNING($"WARNING: Task did not complete in {foreverIsActually}ms. This is probably a bug."); + throw new TimeoutException($"Task did not complete in {foreverIsActually}ms."); + } } } - } - private void BroadcastRuntimeException(Exception ex) - { - var broadcastEx = _serviceProvider.GetRequiredService(); - broadcastEx.BroadcastException(ExceptionKind.Runtime, ex); - } + private void BroadcastRuntimeException(Exception ex) + { + var broadcastEx = _serviceProvider.GetRequiredService(); + broadcastEx.BroadcastException(ExceptionKind.Runtime, ex); + } - private void BroadcastSystemException(CommandSystemException ex) - { - var broadcast = _serviceProvider.GetRequiredService(); - broadcast.BroadcastException(ExceptionKind.System, ex); - } + private void BroadcastSystemException(CommandSystemException ex) + { + var broadcast = _serviceProvider.GetRequiredService(); + broadcast.BroadcastException(ExceptionKind.System, ex); + } - private void NotifyNuggetUserText(string text) - { - if (_useNuggets) + private void NotifyNuggetUserText(string text) { - var nuggetService = _serviceProvider.GetRequiredService(); - nuggetService.AddUserChatMessage(text); + if (_useNuggets) + { + var nuggetService = _serviceProvider.GetRequiredService(); + nuggetService.AddUserChatMessage(text); + } } - } - private ListeningState _defaultListeningState = ListeningState.Off; - private bool _allowPushToTalk = false; - private bool _useNuggets = false; - private bool _useCLU = false; - - private readonly IServiceProvider _serviceProvider; - private readonly IBroadcastMessageService _broadcastMessageService; - private readonly IOnScreenDisplayService _osd; - - private int _started = 0; - private UInt32 _state = (UInt32)ListeningState.Off; - - private ISynthesisService? _synthesizer; - private DateTime _createdRecognizerTime; - private IntentRecognizer? _recognizerOnce; - private IntentRecognizer? _recognizerContinuous; - private string? _keyword = null; - private string? _keywordModelFile = null; - private KeywordRecognitionModel? _keywordModel = null; - private LanguageUnderstandingModelCollection _models = new(); - private Dictionary _callbacks = new(); - - private List _hackDeadRecognizers = new(); -} + private ListeningState _defaultListeningState = ListeningState.Off; + private bool _allowPushToTalk = false; + private bool _useNuggets = false; + private bool _useCLU = false; + + private readonly IServiceProvider _serviceProvider; + private readonly IBroadcastMessageService _broadcastMessageService; + private readonly IOnScreenDisplayService _osd; + + private int _started = 0; + private UInt32 _state = (UInt32)ListeningState.Off; + + private ISynthesisService? _synthesizer; + private DateTime _createdRecognizerTime; + private IntentRecognizer? _recognizerOnce; + private IntentRecognizer? _recognizerContinuous; + private string? _keyword = null; + private string? _keywordModelFile = null; + private KeywordRecognitionModel? _keywordModel = null; + private LanguageUnderstandingModelCollection _models = new LanguageUnderstandingModelCollection(); + private Dictionary _callbacks = new Dictionary(); + + private List _hackDeadRecognizers = new List(); + } +} \ No newline at end of file diff --git a/src/cs/IntentRecognition/IntentRecognizerServiceHost.cs b/src/cs/IntentRecognition/IntentRecognizerServiceHost.cs index 708b2129..09e65311 100644 --- a/src/cs/IntentRecognition/IntentRecognizerServiceHost.cs +++ b/src/cs/IntentRecognition/IntentRecognizerServiceHost.cs @@ -1,14 +1,19 @@ -namespace macaroni; +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; -internal class IntentRecognizerServiceHost : StartStopHelperBackgroundService +namespace macaroni { - public IntentRecognizerServiceHost(IServiceProvider services) : base(services) + internal class IntentRecognizerServiceHost : StartStopHelperBackgroundService { - _intentRecognizer = _services.GetRequiredService(); - } + public IntentRecognizerServiceHost(IServiceProvider services) : base(services) + { + _intentRecognizer = _services.GetRequiredService(); + } - override protected Task StartAsync() => _intentRecognizer.StartAsync(); - override protected Task StopAsync() => _intentRecognizer.StopAsync(); + override protected Task StartAsync() => _intentRecognizer.StartAsync(); + override protected Task StopAsync() => _intentRecognizer.StopAsync(); - private IIntentRecognizerService _intentRecognizer; -} + private IIntentRecognizerService _intentRecognizer; + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/AddComponentsMethodAttribute.cs b/src/cs/Interfaces/AddComponentsMethodAttribute.cs index 0af1f94a..b3f33df7 100644 --- a/src/cs/Interfaces/AddComponentsMethodAttribute.cs +++ b/src/cs/Interfaces/AddComponentsMethodAttribute.cs @@ -1,9 +1,13 @@ -namespace macaroni.Components; +using System; -[AttributeUsage(AttributeTargets.Method)] -public class AddComponentsMethodAttribute : Attribute +namespace macaroni.Components { - public AddComponentsMethodAttribute() + + [AttributeUsage(AttributeTargets.Method)] + public class AddComponentsMethodAttribute : Attribute { + public AddComponentsMethodAttribute() + { + } } -} +} \ No newline at end of file diff --git a/src/cs/Interfaces/CommandSystemComponent.cs b/src/cs/Interfaces/CommandSystemComponent.cs index 25e8597c..2818ea7e 100644 --- a/src/cs/Interfaces/CommandSystemComponent.cs +++ b/src/cs/Interfaces/CommandSystemComponent.cs @@ -1,15 +1,17 @@ -namespace macaroni; - -public abstract class CommandSystemComponent : ICommandSystemComponent +namespace macaroni { - public abstract void Configure(ICommandSystemBuilder builder); - void ICommandSystemComponent.SetCommandSystem(ICommandSystem commandSystem) + public abstract class CommandSystemComponent : ICommandSystemComponent { - _commandSystem = commandSystem; - } + public abstract void Configure(ICommandSystemBuilder builder); - public ICommandSystem CommandSystem => _commandSystem!; + void ICommandSystemComponent.SetCommandSystem(ICommandSystem commandSystem) + { + _commandSystem = commandSystem; + } - ICommandSystem? _commandSystem; -} + public ICommandSystem CommandSystem => _commandSystem!; + + ICommandSystem? _commandSystem; + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IAndroidIntentService.cs b/src/cs/Interfaces/IAndroidIntentService.cs index 2643c884..002eae6f 100644 --- a/src/cs/Interfaces/IAndroidIntentService.cs +++ b/src/cs/Interfaces/IAndroidIntentService.cs @@ -1,8 +1,9 @@ -using System.Diagnostics; +using System.Collections.Generic; -namespace macaroni; - -public interface IAndroidIntentService +namespace macaroni { - void StartActivity(string action, string? uri, IEnumerable>? extras); -} + public interface IAndroidIntentService + { + void StartActivity(string action, string? uri, IEnumerable>? extras); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IBroadcastExceptionService.cs b/src/cs/Interfaces/IBroadcastExceptionService.cs index d16ada0c..6b54eed3 100644 --- a/src/cs/Interfaces/IBroadcastExceptionService.cs +++ b/src/cs/Interfaces/IBroadcastExceptionService.cs @@ -1,16 +1,19 @@ -namespace macaroni; +using System; -public enum ExceptionKind +namespace macaroni { - Parsing, - Runtime, - System -} + public enum ExceptionKind + { + Parsing, + Runtime, + System + } -public interface IBroadcastExceptionService -{ - void StartNotify(string scopeId, string callbackId, ExceptionKind kind, Action callback); - void StopNotify(string scopeId, string? callbackId); + public interface IBroadcastExceptionService + { + void StartNotify(string scopeId, string callbackId, ExceptionKind kind, Action callback); + void StopNotify(string scopeId, string? callbackId); - void BroadcastException(ExceptionKind kind, Exception ex); -} + void BroadcastException(ExceptionKind kind, Exception ex); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IBroadcastMessageService.cs b/src/cs/Interfaces/IBroadcastMessageService.cs index d5bee078..769327d8 100644 --- a/src/cs/Interfaces/IBroadcastMessageService.cs +++ b/src/cs/Interfaces/IBroadcastMessageService.cs @@ -1,9 +1,12 @@ -namespace macaroni; +using System; -public interface IBroadcastMessageService +namespace macaroni { - void StartNotify(string scopeId, string callbackId, string messageName, string? messageValue, Action callback); - void StopNotify(string scopeId, string? callbackId); + public interface IBroadcastMessageService + { + void StartNotify(string scopeId, string callbackId, string messageName, string? messageValue, Action callback); + void StopNotify(string scopeId, string? callbackId); - void BroadcastMessage(string name, string? value, string? scope); -} + void BroadcastMessage(string name, string? value, string? scope); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ICLURecognizerService.cs b/src/cs/Interfaces/ICLURecognizerService.cs index b73d5e00..0ffaca91 100644 --- a/src/cs/Interfaces/ICLURecognizerService.cs +++ b/src/cs/Interfaces/ICLURecognizerService.cs @@ -1,9 +1,12 @@ -using Microsoft.CognitiveServices.Speech.Intent; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; -namespace macaroni; - -public interface ICLURecognizerService +namespace macaroni { - Task<(string intentId, Dictionary entities, Dictionary entitiesJson)> CheckCLUAsync(string input); - void ParseCLUJsonResponseStream(Stream stream, out string intentId, out Dictionary entities, out Dictionary entitiesJson); -} + public interface ICLURecognizerService + { + Task<(string intentId, Dictionary entities, Dictionary entitiesJson)> CheckCLUAsync(string input); + void ParseCLUJsonResponseStream(Stream stream, out string intentId, out Dictionary entities, out Dictionary entitiesJson); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IClipboardService.cs b/src/cs/Interfaces/IClipboardService.cs index 789f4286..a8d8a1b1 100644 --- a/src/cs/Interfaces/IClipboardService.cs +++ b/src/cs/Interfaces/IClipboardService.cs @@ -1,13 +1,14 @@ -namespace macaroni; - -public interface IClipboardService +namespace macaroni { - void Clear(); + public interface IClipboardService + { + void Clear(); - void Set(string value, string? format); + void Set(string value, string? format); - string? GetText(); + string? GetText(); - void SetImage(IImage image); - IImage? GetImage(); -} + void SetImage(IImage image); + IImage? GetImage(); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ICommand.cs b/src/cs/Interfaces/ICommand.cs index d168b6ca..59c26f39 100644 --- a/src/cs/Interfaces/ICommand.cs +++ b/src/cs/Interfaces/ICommand.cs @@ -1,21 +1,24 @@ -namespace macaroni; +using System.Collections.Generic; -public interface ICommand : ICondition +namespace macaroni { - string Id { get; } - string? Name { get; } + public interface ICommand : ICondition + { + string Id { get; } + string? Name { get; } - IEnumerable? Examples { get; } + IEnumerable? Examples { get; } - IConditionCollection? Conditions { get; } - ITriggerCollection? Triggers { get; } - IExecutorCollection? Executors { get; } - ITriggerCollection? Expecting { get; } - IUnexpectedDialogPolicy? Unexpected { get; } + IConditionCollection? Conditions { get; } + ITriggerCollection? Triggers { get; } + IExecutorCollection? Executors { get; } + ITriggerCollection? Expecting { get; } + IUnexpectedDialogPolicy? Unexpected { get; } - IExecutionContext GetExecutionContext(); - ExecutionResult Execute(IExecutionContext context); + IExecutionContext GetExecutionContext(); + ExecutionResult Execute(IExecutionContext context); - void PersistContext(IExecutionContext? context, ITriggerCollection? expecting, IUnexpectedDialogPolicy? unexpected); - void ClearContext(); -} + void PersistContext(IExecutionContext? context, ITriggerCollection? expecting, IUnexpectedDialogPolicy? unexpected); + void ClearContext(); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ICommandExecutionService.cs b/src/cs/Interfaces/ICommandExecutionService.cs index 4e3fdc73..f64a5e26 100644 --- a/src/cs/Interfaces/ICommandExecutionService.cs +++ b/src/cs/Interfaces/ICommandExecutionService.cs @@ -1,9 +1,13 @@ -namespace macaroni; +using System; +using System.Collections.Generic; -public interface ICommandExecutionService +namespace macaroni { - void Execute(ICommand? command, Action? configureContext = null); - void Cancel(ICommand? command); + public interface ICommandExecutionService + { + void Execute(ICommand? command, Action? configureContext = null); + void Cancel(ICommand? command); - IEnumerable GetNotCompleted(); -} + IEnumerable GetNotCompleted(); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ICommandExecutor.cs b/src/cs/Interfaces/ICommandExecutor.cs index 836a04bd..c8d0fb43 100644 --- a/src/cs/Interfaces/ICommandExecutor.cs +++ b/src/cs/Interfaces/ICommandExecutor.cs @@ -1,14 +1,16 @@ -namespace macaroni; - -public enum ExecutionResult +namespace macaroni { - Completed = 0, - Yielded = 1, - Stopped = 2, - Canceled = 3 -} -public interface ICommandExecutor -{ - ExecutionResult Execute(IExecutionContext context); -} + public enum ExecutionResult + { + Completed = 0, + Yielded = 1, + Stopped = 2, + Canceled = 3 + } + + public interface ICommandExecutor + { + ExecutionResult Execute(IExecutionContext context); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ICommandSet.cs b/src/cs/Interfaces/ICommandSet.cs index 5e4250bb..90fdd63c 100644 --- a/src/cs/Interfaces/ICommandSet.cs +++ b/src/cs/Interfaces/ICommandSet.cs @@ -1,19 +1,22 @@ -namespace macaroni; +using System.Collections.Generic; -public interface ICommandSet +namespace macaroni { - string Id { get; } - string? Keyword { get; } + public interface ICommandSet + { + string Id { get; } + string? Keyword { get; } - INuggetCollection? Nuggets { get; } - IYamlValueCollection? Values { get; } - IConditionCollection? Conditions { get; } - IEnumerable? Commands { get; } + INuggetCollection? Nuggets { get; } + IYamlValueCollection? Values { get; } + IConditionCollection? Conditions { get; } + IEnumerable? Commands { get; } - IEnumerable? Warnings { get; } + IEnumerable? Warnings { get; } - void StartCommandSet(ICommandSystemService commandSystem); - void StopCommandSet(); + void StartCommandSet(ICommandSystemService commandSystem); + void StopCommandSet(); - IExecutionContext CreateExecutionContext(); -} + IExecutionContext CreateExecutionContext(); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ICommandSetExtension.cs b/src/cs/Interfaces/ICommandSetExtension.cs index 9d24f957..e251801c 100644 --- a/src/cs/Interfaces/ICommandSetExtension.cs +++ b/src/cs/Interfaces/ICommandSetExtension.cs @@ -1,7 +1,8 @@ -namespace macaroni; - -public interface ICommandSetExtension +namespace macaroni { - void InitCommandSetExtension(ICommandSet commandSet); - void EnableExtension(bool enabled); -} + public interface ICommandSetExtension + { + void InitCommandSetExtension(ICommandSet commandSet); + void EnableExtension(bool enabled); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ICommandSetFactory.cs b/src/cs/Interfaces/ICommandSetFactory.cs index ddc90548..ef69e4da 100644 --- a/src/cs/Interfaces/ICommandSetFactory.cs +++ b/src/cs/Interfaces/ICommandSetFactory.cs @@ -1,7 +1,10 @@ -namespace macaroni; +using System.Threading.Tasks; -public interface ICommandSetFactory +namespace macaroni { - Task StartAsync(); - Task StopAsync(); -} + public interface ICommandSetFactory + { + Task StartAsync(); + Task StopAsync(); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ICommandSetYamlParser.cs b/src/cs/Interfaces/ICommandSetYamlParser.cs index ff121c4f..1eeb7005 100644 --- a/src/cs/Interfaces/ICommandSetYamlParser.cs +++ b/src/cs/Interfaces/ICommandSetYamlParser.cs @@ -1,7 +1,11 @@ -namespace macaroni; +using System.Collections.Generic; +using System.IO; -public interface ICommandSetYamlParser +namespace macaroni { - IEnumerable Parse(string file); - IEnumerable Parse(string documentName, TextReader reader); -} + public interface ICommandSetYamlParser + { + IEnumerable Parse(string file); + IEnumerable Parse(string documentName, TextReader reader); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ICommandSite.cs b/src/cs/Interfaces/ICommandSite.cs index 66103f3a..bd5f592c 100644 --- a/src/cs/Interfaces/ICommandSite.cs +++ b/src/cs/Interfaces/ICommandSite.cs @@ -1,5 +1,6 @@ -namespace macaroni; - -public interface ICommandSite : INotifyCondition +namespace macaroni { -} + public interface ICommandSite : INotifyCondition + { + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ICommandSystem.cs b/src/cs/Interfaces/ICommandSystem.cs index 6561149f..1d887333 100644 --- a/src/cs/Interfaces/ICommandSystem.cs +++ b/src/cs/Interfaces/ICommandSystem.cs @@ -1,95 +1,100 @@ -using Microsoft.CognitiveServices.Speech; -using Microsoft.CognitiveServices.Speech.Intent; - -namespace macaroni; - -public interface ICommandSystem : IHost -{ - void SetContext(string name, object value); - - //string? Resolve(string? text, bool deleteUnresolved = false); - - //public ICommandSystemRecognizer Recognizer { get; } - //public ICommandSystemSynthesizer Synthesizer { get; } - - /// - /// Start the program. - /// - /// Used to abort program start. - /// A System.Threading.Tasks.Task that will be completed when the Microsoft.Extensions.Hosting.IHost - // starts. - new Task StartAsync(CancellationToken cancellationToken = default(CancellationToken)); - - - /// - /// Attempts to gracefully stop the program. - /// - /// Used to indicate when stop should no longer be graceful - /// A System.Threading.Tasks.Task that will be completed when the Microsoft.Extensions.Hosting.IHost - // stops. - new Task StopAsync(CancellationToken cancellationToken = default(CancellationToken)); - - - /// - /// Sets the Command System context variable with name to the value provided. - /// - /// Name of the context variable. - /// Value to set. - void BroadcastMessage(string name, string? value); - - - /// - /// Emulates speech recognition with the provided text. This method takes a string of text - /// and simulates a speech recognition process, allowing the user to interact with the application - /// as if they had spoken the text. The text is then processed and the appropriate action is taken. - /// - /// Text to emulate. - void EmulateSpeechRecognition(string text); -} - -public enum CommandSystemRecognitionState -{ - Off = 0, - On = 1, - Keyword = 2 -} - -public interface ICommandSystemRecognizer -{ - public CommandSystemRecognitionState State { get; } - - public Task StartContinuousRecognitionAsync(); - public Task StartKeywordRecognitionAsync(); - public Task RecognizeOnceAsync(string text); - - public Task StopRecognitionAsync(); - public Task PauseRecognitionAsync(); - public Task RestoreRecognitionAsync(UInt64 previous); - - - public bool ApplyLanguageModels(LanguageUnderstandingModelCollection collection); - - public event EventHandler RecognitionStarted; - public event EventHandler RecognitionStopped; - - public event EventHandler Recognizing; - public event EventHandler Recognized; -} - -public interface ICommandSystemSynthesizer -{ - public Task GetVoicesAsync(string locale = ""); - - public Task SpeakTextAsync(string text); - public Task SpeakSsmlAsync(string ssml); - public Task StartSpeakingTextAsync(string text); - public Task StartSpeakingSsmlAsync(string ssml); - public Task StopSpeakingAsync(); - - public event EventHandler SynthesisStarted; - public event EventHandler Synthesizing; - public event EventHandler SynthesisCompleted; - public event EventHandler WordBoundary; - public event EventHandler VisemeReceived; - public event EventHandler BookmarkReached; -} +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CognitiveServices.Speech; +using Microsoft.CognitiveServices.Speech.Intent; +using Microsoft.Extensions.Hosting; +namespace macaroni +{ + + public interface ICommandSystem : IHost + { + void SetContext(string name, object value); + + //string? Resolve(string? text, bool deleteUnresolved = false); + + //public ICommandSystemRecognizer Recognizer { get; } + //public ICommandSystemSynthesizer Synthesizer { get; } + + /// + /// Start the program. + /// + /// Used to abort program start. + /// A System.Threading.Tasks.Task that will be completed when the Microsoft.Extensions.Hosting.IHost + // starts. + new Task StartAsync(CancellationToken cancellationToken = default(CancellationToken)); + + + /// + /// Attempts to gracefully stop the program. + /// + /// Used to indicate when stop should no longer be graceful + /// A System.Threading.Tasks.Task that will be completed when the Microsoft.Extensions.Hosting.IHost + // stops. + new Task StopAsync(CancellationToken cancellationToken = default(CancellationToken)); + + + /// + /// Sets the Command System context variable with name to the value provided. + /// + /// Name of the context variable. + /// Value to set. + void BroadcastMessage(string name, string? value); + + + /// + /// Emulates speech recognition with the provided text. This method takes a string of text + /// and simulates a speech recognition process, allowing the user to interact with the application + /// as if they had spoken the text. The text is then processed and the appropriate action is taken. + /// + /// Text to emulate. + void EmulateSpeechRecognition(string text); + } + + public enum CommandSystemRecognitionState + { + Off = 0, + On = 1, + Keyword = 2 + } + + public interface ICommandSystemRecognizer + { + public CommandSystemRecognitionState State { get; } + + public Task StartContinuousRecognitionAsync(); + public Task StartKeywordRecognitionAsync(); + public Task RecognizeOnceAsync(string text); + + public Task StopRecognitionAsync(); + public Task PauseRecognitionAsync(); + public Task RestoreRecognitionAsync(UInt64 previous); + + + public bool ApplyLanguageModels(LanguageUnderstandingModelCollection collection); + + public event EventHandler RecognitionStarted; + public event EventHandler RecognitionStopped; + + public event EventHandler Recognizing; + public event EventHandler Recognized; + } + + public interface ICommandSystemSynthesizer + { + public Task GetVoicesAsync(string locale = ""); + + public Task SpeakTextAsync(string text); + public Task SpeakSsmlAsync(string ssml); + public Task StartSpeakingTextAsync(string text); + public Task StartSpeakingSsmlAsync(string ssml); + public Task StopSpeakingAsync(); + + public event EventHandler SynthesisStarted; + public event EventHandler Synthesizing; + public event EventHandler SynthesisCompleted; + public event EventHandler WordBoundary; + public event EventHandler VisemeReceived; + public event EventHandler BookmarkReached; + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ICommandSystemBuilder.cs b/src/cs/Interfaces/ICommandSystemBuilder.cs index ab6db481..72755119 100644 --- a/src/cs/Interfaces/ICommandSystemBuilder.cs +++ b/src/cs/Interfaces/ICommandSystemBuilder.cs @@ -1,29 +1,33 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using Microsoft.Extensions.Hosting; -namespace macaroni; - -public interface ICommandSystemBuilder +namespace macaroni { - IDictionary Properties { get; } + public interface ICommandSystemBuilder + { + IDictionary Properties { get; } - ICommandSystemBuilder ConfigureAppConfiguration(Action configureDelegate); - ICommandSystemBuilder ConfigureContainer(Action configureDelegate); - ICommandSystemBuilder ConfigureHostConfiguration(Action configureDelegate); - ICommandSystemBuilder ConfigureServices(Action configureDelegate); - ICommandSystemBuilder UseServiceProviderFactory(Func> factory) where TContainerBuilder : notnull; - ICommandSystemBuilder UseServiceProviderFactory(IServiceProviderFactory factory) where TContainerBuilder : notnull; + ICommandSystemBuilder ConfigureAppConfiguration(Action configureDelegate); + ICommandSystemBuilder ConfigureContainer(Action configureDelegate); + ICommandSystemBuilder ConfigureHostConfiguration(Action configureDelegate); + ICommandSystemBuilder ConfigureServices(Action configureDelegate); + ICommandSystemBuilder UseServiceProviderFactory(Func> factory) where TContainerBuilder : notnull; + ICommandSystemBuilder UseServiceProviderFactory(IServiceProviderFactory factory) where TContainerBuilder : notnull; - ICommandSystemBuilder ConfigureLogging(Action configureDelegate); - ICommandSystemBuilder ConfigureSources(Action configureDelegate); - ICommandSystemBuilder ConfigureSecrets(Action configureDelegate); - ICommandSystemBuilder ConfigureSpeech(Action configureDelegate); - ICommandSystemBuilder ConfigureComponents(Action configureDelegate); - ICommandSystemBuilder ConfigureResolvers(Action configureDelegate); - ICommandSystemBuilder ConfigureMessages(Action configureDelegate); - ICommandSystemBuilder ConfigureUi(Action configureDelegate); - ICommandSystemBuilder ConfigureMedia(Action configureDelegate); - ICommandSystemBuilder ConfigureClipboard(Action configureDelegate); + ICommandSystemBuilder ConfigureLogging(Action configureDelegate); + ICommandSystemBuilder ConfigureSources(Action configureDelegate); + ICommandSystemBuilder ConfigureSecrets(Action configureDelegate); + ICommandSystemBuilder ConfigureSpeech(Action configureDelegate); + ICommandSystemBuilder ConfigureComponents(Action configureDelegate); + ICommandSystemBuilder ConfigureResolvers(Action configureDelegate); + ICommandSystemBuilder ConfigureMessages(Action configureDelegate); + ICommandSystemBuilder ConfigureUi(Action configureDelegate); + ICommandSystemBuilder ConfigureMedia(Action configureDelegate); + ICommandSystemBuilder ConfigureClipboard(Action configureDelegate); - ICommandSystem Build(); -} + ICommandSystem Build(); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ICommandSystemComponent.cs b/src/cs/Interfaces/ICommandSystemComponent.cs index aa955947..ac8dc92c 100644 --- a/src/cs/Interfaces/ICommandSystemComponent.cs +++ b/src/cs/Interfaces/ICommandSystemComponent.cs @@ -1,7 +1,9 @@ -namespace macaroni; - -public interface ICommandSystemComponent +namespace macaroni { - void Configure(ICommandSystemBuilder builder); - void SetCommandSystem(ICommandSystem commandSystem); -} + + public interface ICommandSystemComponent + { + void Configure(ICommandSystemBuilder builder); + void SetCommandSystem(ICommandSystem commandSystem); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ICommandSystemHost.cs b/src/cs/Interfaces/ICommandSystemHost.cs index 24de345d..aa065963 100644 --- a/src/cs/Interfaces/ICommandSystemHost.cs +++ b/src/cs/Interfaces/ICommandSystemHost.cs @@ -1,6 +1,7 @@ -namespace macaroni; - -public interface ICommandSystemHost +namespace macaroni { - public void Quit(); -} + public interface ICommandSystemHost + { + public void Quit(); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ICommandSystemService.cs b/src/cs/Interfaces/ICommandSystemService.cs index b88e7d11..bb6e45db 100644 --- a/src/cs/Interfaces/ICommandSystemService.cs +++ b/src/cs/Interfaces/ICommandSystemService.cs @@ -1,12 +1,18 @@ -namespace macaroni; +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; -public interface ICommandSystemService +namespace macaroni { - IServiceProvider Services { get; } + public interface ICommandSystemService + { + IServiceProvider Services { get; } - Task LoadFileAsync(string file); - Task LoadFileAsync(string documentName, TextReader reader); - Task UnloadFileAsync(string file); + Task LoadFileAsync(string file); + Task LoadFileAsync(string documentName, TextReader reader); + Task UnloadFileAsync(string file); - IEnumerable? GetTips(); -} + IEnumerable? GetTips(); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ICommandSystemSetting.cs b/src/cs/Interfaces/ICommandSystemSetting.cs index cdf06933..8a693c21 100644 --- a/src/cs/Interfaces/ICommandSystemSetting.cs +++ b/src/cs/Interfaces/ICommandSystemSetting.cs @@ -1,6 +1,7 @@ -namespace macaroni; - -public interface ICommandSystemSettings +namespace macaroni { - string? Get(string name, string? defaultValue = null); -} + public interface ICommandSystemSettings + { + string? Get(string name, string? defaultValue = null); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ICommandTrigger.cs b/src/cs/Interfaces/ICommandTrigger.cs index ccb00313..56e66718 100644 --- a/src/cs/Interfaces/ICommandTrigger.cs +++ b/src/cs/Interfaces/ICommandTrigger.cs @@ -1,5 +1,6 @@ -namespace macaroni; - -public interface ICommandTrigger +namespace macaroni { -} + public interface ICommandTrigger + { + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ICondition.cs b/src/cs/Interfaces/ICondition.cs index 8d1c8713..69f04f52 100644 --- a/src/cs/Interfaces/ICondition.cs +++ b/src/cs/Interfaces/ICondition.cs @@ -1,6 +1,7 @@ -namespace macaroni; - -public interface ICondition +namespace macaroni { - bool IsSatisfied(IResolutionContext? context = null); -} + public interface ICondition + { + bool IsSatisfied(IResolutionContext? context = null); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IConditionCollection.cs b/src/cs/Interfaces/IConditionCollection.cs index 113f56d8..bde46943 100644 --- a/src/cs/Interfaces/IConditionCollection.cs +++ b/src/cs/Interfaces/IConditionCollection.cs @@ -1,13 +1,16 @@ -namespace macaroni; +using System.Collections.Generic; -public enum ConditionCollectionEvaluationOperation +namespace macaroni { - All = 1, - Any = 2, - None = 3 -} + public enum ConditionCollectionEvaluationOperation + { + All = 1, + Any = 2, + None = 3 + } -public interface IConditionCollection : IEnumerable, ICondition -{ - ConditionCollectionEvaluationOperation Operation { get; set; } -} + public interface IConditionCollection : IEnumerable, ICondition + { + ConditionCollectionEvaluationOperation Operation { get; set; } + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IConditionCollectionYamlParser.cs b/src/cs/Interfaces/IConditionCollectionYamlParser.cs index 3f62bcae..8ece9f3a 100644 --- a/src/cs/Interfaces/IConditionCollectionYamlParser.cs +++ b/src/cs/Interfaces/IConditionCollectionYamlParser.cs @@ -1,7 +1,9 @@ -namespace macaroni; - -public interface IConditionCollectionYamlParser +using YamlDotNet.RepresentationModel; +namespace macaroni { - IConditionCollection? CheckForConditions(string file, YamlMappingNode mapping, string conditionsMappingName, IParsedValueWarningChecker? warnings); - IConditionCollection ConditionsFromSequence(string file, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings); -} + public interface IConditionCollectionYamlParser + { + IConditionCollection? CheckForConditions(string file, YamlMappingNode mapping, string conditionsMappingName, IParsedValueWarningChecker? warnings); + IConditionCollection ConditionsFromSequence(string file, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IConditionFactory.cs b/src/cs/Interfaces/IConditionFactory.cs index 77f75828..a7015a1d 100644 --- a/src/cs/Interfaces/IConditionFactory.cs +++ b/src/cs/Interfaces/IConditionFactory.cs @@ -1,8 +1,11 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -public interface IConditionFactory +namespace macaroni { - bool IsInvalidConditionNode(YamlMappingNode mapping); - ICondition ConditionFromYamlNode(string file, YamlNode node, IParsedValueWarningChecker? warnings); - string GetValidConditionMappingTypes(); -} + public interface IConditionFactory + { + bool IsInvalidConditionNode(YamlMappingNode mapping); + ICondition ConditionFromYamlNode(string file, YamlNode node, IParsedValueWarningChecker? warnings); + string GetValidConditionMappingTypes(); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IConditionYamlParser.cs b/src/cs/Interfaces/IConditionYamlParser.cs index 17b5a3b8..0e451c43 100644 --- a/src/cs/Interfaces/IConditionYamlParser.cs +++ b/src/cs/Interfaces/IConditionYamlParser.cs @@ -1,7 +1,10 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -public interface IConditionYamlParser +namespace macaroni { - string Kind { get; } - ICondition Parse(string file, YamlMappingNode condition, YamlNode value, IParsedValueWarningChecker? warnings); -} + public interface IConditionYamlParser + { + string Kind { get; } + ICondition Parse(string file, YamlMappingNode condition, YamlNode value, IParsedValueWarningChecker? warnings); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IConditionalCommandExecutor.cs b/src/cs/Interfaces/IConditionalCommandExecutor.cs index aa1b7eaf..e6ce715e 100644 --- a/src/cs/Interfaces/IConditionalCommandExecutor.cs +++ b/src/cs/Interfaces/IConditionalCommandExecutor.cs @@ -1,6 +1,7 @@ -namespace macaroni; - -public interface IConditionalCommandExecutor : ICommandExecutor +namespace macaroni { - IConditionCollection? Conditions { get; } -} + public interface IConditionalCommandExecutor : ICommandExecutor + { + IConditionCollection? Conditions { get; } + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IConfigureClipboardBuilder.cs b/src/cs/Interfaces/IConfigureClipboardBuilder.cs index 85f2ab38..8e117429 100644 --- a/src/cs/Interfaces/IConfigureClipboardBuilder.cs +++ b/src/cs/Interfaces/IConfigureClipboardBuilder.cs @@ -1,8 +1,11 @@ -namespace macaroni; +using System; -public interface IConfigureClipboardBuilder +namespace macaroni { - IConfigureClipboardBuilder UseSet(Action setText); - IConfigureClipboardBuilder UseGet(Func getText); - IConfigureClipboardBuilder UseClear(Action clear); -} + public interface IConfigureClipboardBuilder + { + IConfigureClipboardBuilder UseSet(Action setText); + IConfigureClipboardBuilder UseGet(Func getText); + IConfigureClipboardBuilder UseClear(Action clear); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IConfigureComponentBuilder.cs b/src/cs/Interfaces/IConfigureComponentBuilder.cs index 9ac56f86..7e6b86cb 100644 --- a/src/cs/Interfaces/IConfigureComponentBuilder.cs +++ b/src/cs/Interfaces/IConfigureComponentBuilder.cs @@ -1,9 +1,11 @@ using System.Reflection; -namespace macaroni; - -public interface IConfigureComponentBuilder +namespace macaroni { - IConfigureComponentBuilder AddComponent(ICommandSystemComponent component); - IConfigureComponentBuilder AddComponentsFromAssembly(Assembly assembly); + + public interface IConfigureComponentBuilder + { + IConfigureComponentBuilder AddComponent(ICommandSystemComponent component); + IConfigureComponentBuilder AddComponentsFromAssembly(Assembly assembly); + } } diff --git a/src/cs/Interfaces/IConfigureLoggingBuilder.cs b/src/cs/Interfaces/IConfigureLoggingBuilder.cs index 676e64f2..e9726b7a 100644 --- a/src/cs/Interfaces/IConfigureLoggingBuilder.cs +++ b/src/cs/Interfaces/IConfigureLoggingBuilder.cs @@ -1,8 +1,12 @@ -namespace macaroni; +using System; -public interface IConfigureLoggingBuilder +namespace macaroni { - IConfigureLoggingBuilder UseFileLogging(string path); - IConfigureLoggingBuilder AddExceptionHandler(ExceptionKind kind, Action handler); -} + public interface IConfigureLoggingBuilder + { + IConfigureLoggingBuilder UseFileLogging(string path); + + IConfigureLoggingBuilder AddExceptionHandler(ExceptionKind kind, Action handler); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IConfigureMediaBuilder.cs b/src/cs/Interfaces/IConfigureMediaBuilder.cs index 3af372b1..3e2049d5 100644 --- a/src/cs/Interfaces/IConfigureMediaBuilder.cs +++ b/src/cs/Interfaces/IConfigureMediaBuilder.cs @@ -1,12 +1,15 @@ -namespace macaroni; +using System; -public interface IConfigureMediaBuilder +namespace macaroni { - IConfigureMediaBuilder UseBeep(Action beep); - IConfigureMediaBuilder UsePlay(Action play); - IConfigureMediaBuilder UsePause(Action pause); - IConfigureMediaBuilder UseResume(Action resume); - IConfigureMediaBuilder UseStop(Action stop); + public interface IConfigureMediaBuilder + { + IConfigureMediaBuilder UseBeep(Action beep); + IConfigureMediaBuilder UsePlay(Action play); + IConfigureMediaBuilder UsePause(Action pause); + IConfigureMediaBuilder UseResume(Action resume); + IConfigureMediaBuilder UseStop(Action stop); - IConfigureMediaBuilder UseNullAudio(bool useNullAudio = true); -} + IConfigureMediaBuilder UseNullAudio(bool useNullAudio = true); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IConfigureMessageBuilder.cs b/src/cs/Interfaces/IConfigureMessageBuilder.cs index 0d369563..3ae9f683 100644 --- a/src/cs/Interfaces/IConfigureMessageBuilder.cs +++ b/src/cs/Interfaces/IConfigureMessageBuilder.cs @@ -1,7 +1,10 @@ -namespace macaroni; +using System; -public interface IConfigureMessageBuilder +namespace macaroni { - IConfigureMessageBuilder AddHandler(string name, Action handler); - IConfigureMessageBuilder AddHandler(Action handler); -} + public interface IConfigureMessageBuilder + { + IConfigureMessageBuilder AddHandler(string name, Action handler); + IConfigureMessageBuilder AddHandler(Action handler); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IConfigureResolverBuilder.cs b/src/cs/Interfaces/IConfigureResolverBuilder.cs index b8f13c8b..062210bf 100644 --- a/src/cs/Interfaces/IConfigureResolverBuilder.cs +++ b/src/cs/Interfaces/IConfigureResolverBuilder.cs @@ -1,8 +1,11 @@ -namespace macaroni; +using System; -public interface IConfigureResolverBuilder +namespace macaroni { - IConfigureResolverBuilder UseContext(string name, object value); - IConfigureResolverBuilder AddResolver(string name, Func resolver); - IConfigureResolverBuilder AddResolver(Func resolver); -} + public interface IConfigureResolverBuilder + { + IConfigureResolverBuilder UseContext(string name, object value); + IConfigureResolverBuilder AddResolver(string name, Func resolver); + IConfigureResolverBuilder AddResolver(Func resolver); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IConfigureSecretBuilder.cs b/src/cs/Interfaces/IConfigureSecretBuilder.cs index 2d9f5d76..53e37014 100644 --- a/src/cs/Interfaces/IConfigureSecretBuilder.cs +++ b/src/cs/Interfaces/IConfigureSecretBuilder.cs @@ -1,29 +1,32 @@ -namespace macaroni; +using System; -public enum CredentialKind +namespace macaroni { - SpeechAuthToken, - // ... -} + public enum CredentialKind + { + SpeechAuthToken, + // ... + } -public enum SecretKind -{ - SpeechKey, - SpeechRegion, - SpeechRecognitionEndpoint, - SpeechRecognitionEndpointId, - SpeechSynthesisEndpoint, - SpeechSynthesisEndpointId - // ... -} + public enum SecretKind + { + SpeechKey, + SpeechRegion, + SpeechRecognitionEndpoint, + SpeechRecognitionEndpointId, + SpeechSynthesisEndpoint, + SpeechSynthesisEndpointId + // ... + } -public interface IConfigureSecretBuilder -{ - IConfigureSecretBuilder AddSecret(SecretKind secret, string value); - IConfigureSecretBuilder AddSecret(SecretKind secret, Func func); - IConfigureSecretBuilder AddSecret(string name, string value); - IConfigureSecretBuilder AddSecret(string name, Func func); - IConfigureSecretBuilder UseKeyVault(string uri, string tenantId, string clientId); + public interface IConfigureSecretBuilder + { + IConfigureSecretBuilder AddSecret(SecretKind secret, string value); + IConfigureSecretBuilder AddSecret(SecretKind secret, Func func); + IConfigureSecretBuilder AddSecret(string name, string value); + IConfigureSecretBuilder AddSecret(string name, Func func); + IConfigureSecretBuilder UseKeyVault(string uri, string tenantId, string clientId); - // IConfigureSecretBuilder UseCredential(CredentialKind kind, Func credentialDelegate); -} + // IConfigureSecretBuilder UseCredential(CredentialKind kind, Func credentialDelegate); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IConfigureSourceBuilder.cs b/src/cs/Interfaces/IConfigureSourceBuilder.cs index 17a2cd2f..f444fc3b 100644 --- a/src/cs/Interfaces/IConfigureSourceBuilder.cs +++ b/src/cs/Interfaces/IConfigureSourceBuilder.cs @@ -1,10 +1,14 @@ -namespace macaroni; +using System; +using System.IO; -public interface IConfigureSourceBuilder +namespace macaroni { - IConfigureSourceBuilder AddFile(string fileName); - IConfigureSourceBuilder AddDocument(string documentName, TextReader reader); - IConfigureSourceBuilder AddTemplateReader(Func reader); - IConfigureSourceBuilder MonitorFolder(string folder, string pattern = "*.mac"); - IConfigureSourceBuilder UseDefaultFolderMonitor(bool useDefaultFolderMonitor = true); -} + public interface IConfigureSourceBuilder + { + IConfigureSourceBuilder AddFile(string fileName); + IConfigureSourceBuilder AddDocument(string documentName, TextReader reader); + IConfigureSourceBuilder AddTemplateReader(Func reader); + IConfigureSourceBuilder MonitorFolder(string folder, string pattern = "*.mac"); + IConfigureSourceBuilder UseDefaultFolderMonitor(bool useDefaultFolderMonitor = true); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IConfigureSpeechBuilder.cs b/src/cs/Interfaces/IConfigureSpeechBuilder.cs index c1561f22..08ecc3bd 100644 --- a/src/cs/Interfaces/IConfigureSpeechBuilder.cs +++ b/src/cs/Interfaces/IConfigureSpeechBuilder.cs @@ -1,12 +1,15 @@ -namespace macaroni; +using System; -public interface IConfigureSpeechBuilder +namespace macaroni { - IConfigureSpeechBuilder AddListeningStateChangedHandler(Action handler); - IConfigureSpeechBuilder AddSpeakingStateChangedHandler(Action handler); + public interface IConfigureSpeechBuilder + { + IConfigureSpeechBuilder AddListeningStateChangedHandler(Action handler); + IConfigureSpeechBuilder AddSpeakingStateChangedHandler(Action handler); - IConfigureSpeechBuilder UseDefaultListeningState(ListeningState listeningState); - IConfigureSpeechBuilder UseKeywordRecognition(string keyword, string modelFile); - IConfigureSpeechBuilder UseHighRecall(bool clu = true, bool nuggets = true); - IConfigureSpeechBuilder UsePullStream(Func reader, Action? closer); -} + IConfigureSpeechBuilder UseDefaultListeningState(ListeningState listeningState); + IConfigureSpeechBuilder UseKeywordRecognition(string keyword, string modelFile); + IConfigureSpeechBuilder UseHighRecall(bool clu = true, bool nuggets = true); + IConfigureSpeechBuilder UsePullStream(Func reader, Action? closer); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IConfigureUiBuilder.cs b/src/cs/Interfaces/IConfigureUiBuilder.cs index 887ac594..cadf94e7 100644 --- a/src/cs/Interfaces/IConfigureUiBuilder.cs +++ b/src/cs/Interfaces/IConfigureUiBuilder.cs @@ -1,12 +1,16 @@ -namespace macaroni; +using System; +using System.Collections.Generic; -public interface IConfigureUiBuilder +namespace macaroni { - IConfigureUiBuilder UseDisplay(Action display); - IConfigureUiBuilder UseAlert(Action alert); - IConfigureUiBuilder UseAlert(Func alert); - IConfigureUiBuilder UseConfirm(Action confirm); - IConfigureUiBuilder UseConfirm(Func confirm); - IConfigureUiBuilder UsePrompt(Func prompt); - IConfigureUiBuilder UsePick(Func, string?, string?> pick); -} + public interface IConfigureUiBuilder + { + IConfigureUiBuilder UseDisplay(Action display); + IConfigureUiBuilder UseAlert(Action alert); + IConfigureUiBuilder UseAlert(Func alert); + IConfigureUiBuilder UseConfirm(Action confirm); + IConfigureUiBuilder UseConfirm(Func confirm); + IConfigureUiBuilder UsePrompt(Func prompt); + IConfigureUiBuilder UsePick(Func, string?, string?> pick); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IContextResolver.cs b/src/cs/Interfaces/IContextResolver.cs index bd5f4394..6bac221e 100644 --- a/src/cs/Interfaces/IContextResolver.cs +++ b/src/cs/Interfaces/IContextResolver.cs @@ -1,6 +1,7 @@ -namespace macaroni; - -public interface IContextResolver +namespace macaroni { - object? Get(string key, object? defaultValue); -} + public interface IContextResolver + { + object? Get(string key, object? defaultValue); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IConversationAnalysisClientService.cs b/src/cs/Interfaces/IConversationAnalysisClientService.cs index a83c63bb..92c533c7 100644 --- a/src/cs/Interfaces/IConversationAnalysisClientService.cs +++ b/src/cs/Interfaces/IConversationAnalysisClientService.cs @@ -1,9 +1,9 @@ using Azure.AI.Language.Conversations; -using Microsoft.CognitiveServices.Speech; -namespace macaroni; - -public interface IConversationAnalysisClientService -{ - ConversationAnalysisClient GetConversationAnalysisClient(); -} +namespace macaroni +{ + public interface IConversationAnalysisClientService + { + ConversationAnalysisClient GetConversationAnalysisClient(); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IDeveloperSettings.cs b/src/cs/Interfaces/IDeveloperSettings.cs index 9a8a09f6..1c2e2d92 100644 --- a/src/cs/Interfaces/IDeveloperSettings.cs +++ b/src/cs/Interfaces/IDeveloperSettings.cs @@ -1,7 +1,8 @@ -namespace macaroni; - -public interface IDeveloperSettings +namespace macaroni { - void Set(string name, string value); - string? Get(string name, string? defaultValue = null); -} + public interface IDeveloperSettings + { + void Set(string name, string value); + string? Get(string name, string? defaultValue = null); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IExecutionContext.cs b/src/cs/Interfaces/IExecutionContext.cs index d2e89bb4..92b7e31e 100644 --- a/src/cs/Interfaces/IExecutionContext.cs +++ b/src/cs/Interfaces/IExecutionContext.cs @@ -1,13 +1,14 @@ -namespace macaroni; - -public interface IExecutionContext : IResolutionContext +namespace macaroni { - void Start(); + public interface IExecutionContext : IResolutionContext + { + void Start(); - void Yield(); - void Stop(); - void Cancel(); - void Complete(); + void Yield(); + void Stop(); + void Cancel(); + void Complete(); - ExecutionResult? Result { get; } -} + ExecutionResult? Result { get; } + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IExecutorCollection.cs b/src/cs/Interfaces/IExecutorCollection.cs index 11d29445..538b9cc0 100644 --- a/src/cs/Interfaces/IExecutorCollection.cs +++ b/src/cs/Interfaces/IExecutorCollection.cs @@ -1,5 +1,8 @@ -namespace macaroni; +using System.Collections.Generic; -public interface IExecutorCollection : IEnumerable, ICommandExecutor +namespace macaroni { -} + public interface IExecutorCollection : IEnumerable, ICommandExecutor + { + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IExecutorCollectionYamlParser.cs b/src/cs/Interfaces/IExecutorCollectionYamlParser.cs index f15fb301..91c0f25d 100644 --- a/src/cs/Interfaces/IExecutorCollectionYamlParser.cs +++ b/src/cs/Interfaces/IExecutorCollectionYamlParser.cs @@ -1,7 +1,10 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -public interface IExecutorCollectionYamlParser +namespace macaroni { - IExecutorCollection? CheckForExecutors(string file, YamlMappingNode mapping, string executorsMappingName, IParsedValueWarningChecker? warnings); - IExecutorCollection ExecutorsFromSequence(string file, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings); -} + public interface IExecutorCollectionYamlParser + { + IExecutorCollection? CheckForExecutors(string file, YamlMappingNode mapping, string executorsMappingName, IParsedValueWarningChecker? warnings); + IExecutorCollection ExecutorsFromSequence(string file, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IExecutorFactory.cs b/src/cs/Interfaces/IExecutorFactory.cs index 4db176e6..d0624456 100644 --- a/src/cs/Interfaces/IExecutorFactory.cs +++ b/src/cs/Interfaces/IExecutorFactory.cs @@ -1,8 +1,11 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -public interface IExecutorFactory +namespace macaroni { - bool IsInvalidExecutorNode(YamlMappingNode mapping); - ICommandExecutor ExecutorFromYamlNode(string file, YamlNode node, IParsedValueWarningChecker? warnings); - string GetValidExecutorMappingTypes(); -} + public interface IExecutorFactory + { + bool IsInvalidExecutorNode(YamlMappingNode mapping); + ICommandExecutor ExecutorFromYamlNode(string file, YamlNode node, IParsedValueWarningChecker? warnings); + string GetValidExecutorMappingTypes(); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IExecutorYamlParser.cs b/src/cs/Interfaces/IExecutorYamlParser.cs index dac967ab..5c7c9af8 100644 --- a/src/cs/Interfaces/IExecutorYamlParser.cs +++ b/src/cs/Interfaces/IExecutorYamlParser.cs @@ -1,7 +1,10 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -public interface IExecutorYamlParser +namespace macaroni { - string Kind { get; } - ICommandExecutor Parse(string file, YamlMappingNode executor, YamlNode value, IParsedValueWarningChecker? warnings); -} + public interface IExecutorYamlParser + { + string Kind { get; } + ICommandExecutor Parse(string file, YamlMappingNode executor, YamlNode value, IParsedValueWarningChecker? warnings); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IFileMonitoringService.cs b/src/cs/Interfaces/IFileMonitoringService.cs index acc1659c..6d031968 100644 --- a/src/cs/Interfaces/IFileMonitoringService.cs +++ b/src/cs/Interfaces/IFileMonitoringService.cs @@ -1,7 +1,12 @@ -namespace macaroni; +using System; +using System.Collections.Generic; +using System.IO; -public interface IFileMonitoringService +namespace macaroni { - void StartNotify(string path, string filter, Action newFiles, Action changedFiles, Action deletedFiles, Action>? updatedFileList = null); - void StopNotify(); -} + public interface IFileMonitoringService + { + void StartNotify(string path, string filter, Action newFiles, Action changedFiles, Action deletedFiles, Action>? updatedFileList = null); + void StopNotify(); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IGlobalNamedState.cs b/src/cs/Interfaces/IGlobalNamedState.cs index ddab3a17..bcced521 100644 --- a/src/cs/Interfaces/IGlobalNamedState.cs +++ b/src/cs/Interfaces/IGlobalNamedState.cs @@ -1,7 +1,8 @@ -namespace macaroni; - -public interface IGlobalNamedState +namespace macaroni { - string Name { get; } - string? Value { get; } -} + public interface IGlobalNamedState + { + string Name { get; } + string? Value { get; } + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IGlobalNamedStateMonitorService.cs b/src/cs/Interfaces/IGlobalNamedStateMonitorService.cs index e440fea8..cb505dff 100644 --- a/src/cs/Interfaces/IGlobalNamedStateMonitorService.cs +++ b/src/cs/Interfaces/IGlobalNamedStateMonitorService.cs @@ -1,7 +1,10 @@ -namespace macaroni; +using System; -public interface IGlobalNamedStateMonitorService +namespace macaroni { - void StartNotify(string name, Action? notify); - void StopNotify(); -} + public interface IGlobalNamedStateMonitorService + { + void StartNotify(string name, Action? notify); + void StopNotify(); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IGlobalNamedStateService.cs b/src/cs/Interfaces/IGlobalNamedStateService.cs index 753dafae..ad8ccc7b 100644 --- a/src/cs/Interfaces/IGlobalNamedStateService.cs +++ b/src/cs/Interfaces/IGlobalNamedStateService.cs @@ -1,13 +1,14 @@ -namespace macaroni; - -public interface IGlobalNamedStateService +namespace macaroni { - void SetNamedState(string name, string? value); - string? GetNamedState(string name); + public interface IGlobalNamedStateService + { + void SetNamedState(string name, string? value); + string? GetNamedState(string name); - void StartNotify(INotifyGlobalNamedState notify); - void StopNotify(INotifyGlobalNamedState notify); + void StartNotify(INotifyGlobalNamedState notify); + void StopNotify(INotifyGlobalNamedState notify); - // Task WaitForNamedStateAsync(string name, int timeout); - // Task WaitForNamedStatesAsync(IEnumerable names, int timeout, bool waitForAll = true); -} + // Task WaitForNamedStateAsync(string name, int timeout); + // Task WaitForNamedStatesAsync(IEnumerable names, int timeout, bool waitForAll = true); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IHotkeyService.cs b/src/cs/Interfaces/IHotkeyService.cs index c9ddfc58..a99aa45e 100644 --- a/src/cs/Interfaces/IHotkeyService.cs +++ b/src/cs/Interfaces/IHotkeyService.cs @@ -1,7 +1,10 @@ -namespace macaroni; +using System; -public interface IHotkeyService +namespace macaroni { - void StartNotify(string groupId, string hotkeyId, string hotkey, Action callback); - void StopNotify(string groupId, string? hotkeyId); -} + public interface IHotkeyService + { + void StartNotify(string groupId, string hotkeyId, string hotkey, Action callback); + void StopNotify(string groupId, string? hotkeyId); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IHttpClientService.cs b/src/cs/Interfaces/IHttpClientService.cs index 76f51ad5..d76b467e 100644 --- a/src/cs/Interfaces/IHttpClientService.cs +++ b/src/cs/Interfaces/IHttpClientService.cs @@ -1,8 +1,11 @@ -using System.Diagnostics; +using System.Collections.Generic; +using System.Net.Http; +using System.Threading.Tasks; -namespace macaroni; - -public interface IHttpClientService +namespace macaroni { - Task SendRequestAsync(string uri, string? method, string? content, IEnumerable? headers); -} + public interface IHttpClientService + { + Task SendRequestAsync(string uri, string? method, string? content, IEnumerable? headers); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IImage.cs b/src/cs/Interfaces/IImage.cs index c379168c..0493b3c3 100644 --- a/src/cs/Interfaces/IImage.cs +++ b/src/cs/Interfaces/IImage.cs @@ -1,9 +1,10 @@ -namespace macaroni; - -public interface IImage +namespace macaroni { - bool TryInit(object? platformImageOrStream); + public interface IImage + { + bool TryInit(object? platformImageOrStream); - object? GetPlatformImage(); - void Save(string fileName); -} + object? GetPlatformImage(); + void Save(string fileName); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IImageAnalysisService.cs b/src/cs/Interfaces/IImageAnalysisService.cs index 9ec21435..c34e13ec 100644 --- a/src/cs/Interfaces/IImageAnalysisService.cs +++ b/src/cs/Interfaces/IImageAnalysisService.cs @@ -1,8 +1,10 @@ +using System.Threading.Tasks; using Azure.AI.Vision.ImageAnalysis; -namespace macaroni; - -public interface IImageAnalysisService +namespace macaroni { - Task Analyze(string fileName, string? feature, string? language); -} + public interface IImageAnalysisService + { + Task Analyze(string fileName, string? feature, string? language); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IImageAnalyzerConfigService.cs b/src/cs/Interfaces/IImageAnalyzerConfigService.cs index 79b2f694..4b1380b6 100644 --- a/src/cs/Interfaces/IImageAnalyzerConfigService.cs +++ b/src/cs/Interfaces/IImageAnalyzerConfigService.cs @@ -1,10 +1,9 @@ -using Microsoft.CognitiveServices.Speech; - -namespace macaroni; - -public interface IImageAnalyzerConfigService +namespace macaroni { - string GetDefaultLanguage(); - - void GetImageAnalyzerConnectionInfo(out string? key, out string? endpoint); -} + public interface IImageAnalyzerConfigService + { + string GetDefaultLanguage(); + + void GetImageAnalyzerConnectionInfo(out string? key, out string? endpoint); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IIntentRecognizerService.cs b/src/cs/Interfaces/IIntentRecognizerService.cs index 22a5c587..cba86b89 100644 --- a/src/cs/Interfaces/IIntentRecognizerService.cs +++ b/src/cs/Interfaces/IIntentRecognizerService.cs @@ -1,22 +1,25 @@ +using System; +using System.Threading.Tasks; using macaroni.DataTypes; using Microsoft.CognitiveServices.Speech.Intent; -namespace macaroni; - -public interface IIntentRecognizerService +namespace macaroni { - Task StartAsync(); - Task StopAsync(); + public interface IIntentRecognizerService + { + Task StartAsync(); + Task StopAsync(); - UInt64 SetState(ListeningState state); - UInt64 RestoreState(UInt64 state); - ListeningState GetState(); - ListeningState GetDefaultState(); + UInt64 SetState(ListeningState state); + UInt64 RestoreState(UInt64 state); + ListeningState GetState(); + ListeningState GetDefaultState(); - void Emulate(string text); + void Emulate(string text); - void LoadPatternMatchingModel(PatternMatchingModel model, Action matchedCallback); - void UnloadPatternMatchingModel(PatternMatchingModel model); - void RegisterIntentCallback(string intentId, string? entityId, string groupId, Action matchedCallback); - void RemoveIntentCallbackGroup(string groupId); -} + void LoadPatternMatchingModel(PatternMatchingModel model, Action matchedCallback); + void UnloadPatternMatchingModel(PatternMatchingModel model); + void RegisterIntentCallback(string intentId, string? entityId, string groupId, Action matchedCallback); + void RemoveIntentCallbackGroup(string groupId); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IIntentTrigger.cs b/src/cs/Interfaces/IIntentTrigger.cs index 433e561a..adbc8242 100644 --- a/src/cs/Interfaces/IIntentTrigger.cs +++ b/src/cs/Interfaces/IIntentTrigger.cs @@ -1,7 +1,8 @@ -namespace macaroni; - -public interface IIntentTrigger : ICommandTrigger +namespace macaroni { - string IntentId { get; } - string? EntityId { get; } + public interface IIntentTrigger : ICommandTrigger + { + string IntentId { get; } + string? EntityId { get; } + } } \ No newline at end of file diff --git a/src/cs/Interfaces/IInvokeOnUiThread.cs b/src/cs/Interfaces/IInvokeOnUiThread.cs index bcdd7dd3..2a3ff22c 100644 --- a/src/cs/Interfaces/IInvokeOnUiThread.cs +++ b/src/cs/Interfaces/IInvokeOnUiThread.cs @@ -1,6 +1,9 @@ -namespace macaroni; +using System; -public interface IInvokeOnUiThread +namespace macaroni { - void Invoke(Action action); -} + public interface IInvokeOnUiThread + { + void Invoke(Action action); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IKeyVaultSettingsService.cs b/src/cs/Interfaces/IKeyVaultSettingsService.cs index 3fbf8768..dae9ad14 100644 --- a/src/cs/Interfaces/IKeyVaultSettingsService.cs +++ b/src/cs/Interfaces/IKeyVaultSettingsService.cs @@ -1,6 +1,7 @@ -namespace macaroni; - -public interface IKeyVaultSettingsService +namespace macaroni { - public bool TryGetSettingValue(string settingKey, out string value, bool allowFastFailBeforeInit = true); -} + public interface IKeyVaultSettingsService + { + public bool TryGetSettingValue(string settingKey, out string value, bool allowFastFailBeforeInit = true); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ILoadedFromYamlExtensions.cs b/src/cs/Interfaces/ILoadedFromYamlExtensions.cs index 1925c007..303fd119 100644 --- a/src/cs/Interfaces/ILoadedFromYamlExtensions.cs +++ b/src/cs/Interfaces/ILoadedFromYamlExtensions.cs @@ -1,57 +1,59 @@ +using System; using Microsoft.Extensions.DependencyInjection; -namespace macaroni; - -internal static class ILoadedFromYamlExtensions +namespace macaroni { - internal static T? GetParentOrService(this ILoadedFromYamlFile node) where T : class + internal static class ILoadedFromYamlExtensions { - var check = node.YamlParent; - for (;;) + internal static T? GetParentOrService(this ILoadedFromYamlFile node) where T : class { - if (check is T) return check as T; - - if (check is IServiceProvider) + var check = node.YamlParent; + for (; ; ) { - var service = (check as IServiceProvider)?.GetService(); - if (service != null) return service; - } + if (check is T) return check as T; - if (check is ICommandSystemService) - { - return (check as ICommandSystemService)?.Services.GetService(); - } + if (check is IServiceProvider) + { + var service = (check as IServiceProvider)?.GetService(); + if (service != null) return service; + } - var parent = (check as ILoadedFromYamlFile)?.YamlParent; - if (parent == null) break; + if (check is ICommandSystemService) + { + return (check as ICommandSystemService)?.Services.GetService(); + } - check = parent; - } + var parent = (check as ILoadedFromYamlFile)?.YamlParent; + if (parent == null) break; - return null; - } + check = parent; + } - internal static T? GetParentOrService(this ICommandSet commandSet) where T : class - { - return (commandSet as ILoadedFromYamlFile)?.GetParentOrService(); - } + return null; + } - internal static T GetRequiredParentOrService(this ILoadedFromYamlFile node) where T : class - { - var requested = node.GetParentOrService(); - return requested ?? throw new ApplicationException($"Unexpected: could not get required service ({nameof(node)}"); - } + internal static T? GetParentOrService(this ICommandSet commandSet) where T : class + { + return (commandSet as ILoadedFromYamlFile)?.GetParentOrService(); + } - internal static T GetRequiredParentOrService(this ICommandSet commandSet) where T : class - { - var requested = commandSet.GetParentOrService(); - return requested ?? throw new ApplicationException($"Unexpected: could not get required service ({nameof(commandSet)}"); - } + internal static T GetRequiredParentOrService(this ILoadedFromYamlFile node) where T : class + { + var requested = node.GetParentOrService(); + return requested ?? throw new ApplicationException($"Unexpected: could not get required service ({nameof(node)}"); + } - internal static bool IsEditorDesignMode(this ILoadedFromYamlFile node) - { - var resolve = node.GetRequiredParentOrService(); - var value = resolve.Get("IsEditorDesignMode", null); - return value != null && value is string && value as string == "true"; + internal static T GetRequiredParentOrService(this ICommandSet commandSet) where T : class + { + var requested = commandSet.GetParentOrService(); + return requested ?? throw new ApplicationException($"Unexpected: could not get required service ({nameof(commandSet)}"); + } + + internal static bool IsEditorDesignMode(this ILoadedFromYamlFile node) + { + var resolve = node.GetRequiredParentOrService(); + var value = resolve.Get("IsEditorDesignMode", null); + return value != null && value is string && value as string == "true"; + } } -} +} \ No newline at end of file diff --git a/src/cs/Interfaces/ILoadedFromYamlFile.cs b/src/cs/Interfaces/ILoadedFromYamlFile.cs index 5eeb6fb2..6c19ce70 100644 --- a/src/cs/Interfaces/ILoadedFromYamlFile.cs +++ b/src/cs/Interfaces/ILoadedFromYamlFile.cs @@ -1,11 +1,14 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal interface ILoadedFromYamlFile +namespace macaroni { - YamlNode? Yaml { get; } - string? YamlFile { get; } - object? YamlParent { get; } + internal interface ILoadedFromYamlFile + { + YamlNode? Yaml { get; } + string? YamlFile { get; } + object? YamlParent { get; } - void LoadComplete(object parent); - void Unload(); -} + void LoadComplete(object parent); + void Unload(); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ILocalContext.cs b/src/cs/Interfaces/ILocalContext.cs index 20b9719e..ddde97bb 100644 --- a/src/cs/Interfaces/ILocalContext.cs +++ b/src/cs/Interfaces/ILocalContext.cs @@ -1,5 +1,6 @@ -namespace macaroni; - -public interface ILocalContext : IResolutionContext +namespace macaroni { -} + public interface ILocalContext : IResolutionContext + { + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IMessageBoxService.cs b/src/cs/Interfaces/IMessageBoxService.cs index 3b5e311f..c58d27e1 100644 --- a/src/cs/Interfaces/IMessageBoxService.cs +++ b/src/cs/Interfaces/IMessageBoxService.cs @@ -1,14 +1,15 @@ using System.Collections.Generic; -namespace macaroni; - -public interface IMessageBoxService +namespace macaroni { - bool Show(string message, string? title, string? timeout); + public interface IMessageBoxService + { + bool Show(string message, string? title, string? timeout); - bool Confirm(string message, string? title, string? timeout); + bool Confirm(string message, string? title, string? timeout); - bool Prompt(string prompt, string? title, string? timeout, ref string text); + bool Prompt(string prompt, string? title, string? timeout, ref string text); - bool Pick(IEnumerable choices, string? message, string? title, string? timeout, ref string? choice); -} + bool Pick(IEnumerable choices, string? message, string? title, string? timeout, ref string? choice); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IMessageTrigger.cs b/src/cs/Interfaces/IMessageTrigger.cs index bf3d9c24..7073b0a3 100644 --- a/src/cs/Interfaces/IMessageTrigger.cs +++ b/src/cs/Interfaces/IMessageTrigger.cs @@ -1,8 +1,9 @@ -namespace macaroni; - -public interface IMessageTrigger : ICommandTrigger +namespace macaroni { - string Name { get; set; } - string? Value { get; set; } - string? Scope { get; set; } -} + public interface IMessageTrigger : ICommandTrigger + { + string Name { get; set; } + string? Value { get; set; } + string? Scope { get; set; } + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IMouseService.cs b/src/cs/Interfaces/IMouseService.cs index 94866c48..513d2f85 100644 --- a/src/cs/Interfaces/IMouseService.cs +++ b/src/cs/Interfaces/IMouseService.cs @@ -1,10 +1,11 @@ -namespace macaroni; - -public interface IMouseService +namespace macaroni { - void Move(string? position, string? relative); - void ClickButton(string? position, string? relative, string? button); - void PressButton(string? position, string? relative, string? button); - void ReleaseButton(string? position, string? relative, string? button); - (int, int) GetPosition(); -} + public interface IMouseService + { + void Move(string? position, string? relative); + void ClickButton(string? position, string? relative, string? button); + void PressButton(string? position, string? relative, string? button); + void ReleaseButton(string? position, string? relative, string? button); + (int, int) GetPosition(); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/INotifyCondition.cs b/src/cs/Interfaces/INotifyCondition.cs index f32d8fbe..3c6fc60c 100644 --- a/src/cs/Interfaces/INotifyCondition.cs +++ b/src/cs/Interfaces/INotifyCondition.cs @@ -1,6 +1,7 @@ -namespace macaroni; - -public interface INotifyCondition +namespace macaroni { - void ConditionChanged(ICondition condition); -} + public interface INotifyCondition + { + void ConditionChanged(ICondition condition); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/INotifyGlobalNamedState.cs b/src/cs/Interfaces/INotifyGlobalNamedState.cs index 4d5d1316..5af3c2d8 100644 --- a/src/cs/Interfaces/INotifyGlobalNamedState.cs +++ b/src/cs/Interfaces/INotifyGlobalNamedState.cs @@ -1,6 +1,7 @@ -namespace macaroni; - -public interface INotifyGlobalNamedState +namespace macaroni { - void NamedStateChanged(IGlobalNamedState state); -} + public interface INotifyGlobalNamedState + { + void NamedStateChanged(IGlobalNamedState state); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/INotifyYamlValues.cs b/src/cs/Interfaces/INotifyYamlValues.cs index 27895f07..26355ea4 100644 --- a/src/cs/Interfaces/INotifyYamlValues.cs +++ b/src/cs/Interfaces/INotifyYamlValues.cs @@ -1,6 +1,7 @@ -namespace macaroni; - -public interface INotifyYamlValues +namespace macaroni { - void ValueChanged(IYamlValue value); -} + public interface INotifyYamlValues + { + void ValueChanged(IYamlValue value); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/INugget.cs b/src/cs/Interfaces/INugget.cs index 5fb2fe99..35f9730a 100644 --- a/src/cs/Interfaces/INugget.cs +++ b/src/cs/Interfaces/INugget.cs @@ -1,14 +1,17 @@ -namespace macaroni; +using System.Collections.Generic; -public interface INugget +namespace macaroni { - string? Name { get; } - string? Description { get; } + public interface INugget + { + string? Name { get; } + string? Description { get; } - IEnumerable? Parameters { get; } - IEnumerable? Instructions { get; } - IEnumerable? Examples { get; } + IEnumerable? Parameters { get; } + IEnumerable? Instructions { get; } + IEnumerable? Examples { get; } - IExecutorCollection? Executors { get; } - IEnumerable? Outputs { get; } -} + IExecutorCollection? Executors { get; } + IEnumerable? Outputs { get; } + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/INuggetCollection.cs b/src/cs/Interfaces/INuggetCollection.cs index 4cf99ab8..ade77613 100644 --- a/src/cs/Interfaces/INuggetCollection.cs +++ b/src/cs/Interfaces/INuggetCollection.cs @@ -1,5 +1,8 @@ -namespace macaroni; +using System.Collections.Generic; -public interface INuggetCollection : IEnumerable +namespace macaroni { -} + public interface INuggetCollection : IEnumerable + { + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/INuggetCollectionYamlParser.cs b/src/cs/Interfaces/INuggetCollectionYamlParser.cs index a0963498..c8777fdd 100644 --- a/src/cs/Interfaces/INuggetCollectionYamlParser.cs +++ b/src/cs/Interfaces/INuggetCollectionYamlParser.cs @@ -1,7 +1,10 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -public interface INuggetCollectionYamlParser +namespace macaroni { - INuggetCollection? CheckForNuggets(string file, YamlMappingNode mapping, string nuggetsMappingName); - INuggetCollection NuggetsFromSequence(string file, YamlSequenceNode sequence); -} + public interface INuggetCollectionYamlParser + { + INuggetCollection? CheckForNuggets(string file, YamlMappingNode mapping, string nuggetsMappingName); + INuggetCollection NuggetsFromSequence(string file, YamlSequenceNode sequence); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/INuggetExample.cs b/src/cs/Interfaces/INuggetExample.cs index 30fb3b9f..4a22b45d 100644 --- a/src/cs/Interfaces/INuggetExample.cs +++ b/src/cs/Interfaces/INuggetExample.cs @@ -1,7 +1,8 @@ -namespace macaroni; - -public interface INuggetExample +namespace macaroni { - string? User { get; } - string? Assistant { get; } -} + public interface INuggetExample + { + string? User { get; } + string? Assistant { get; } + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/INuggetExecutionService.cs b/src/cs/Interfaces/INuggetExecutionService.cs index 9add596d..19572d7c 100644 --- a/src/cs/Interfaces/INuggetExecutionService.cs +++ b/src/cs/Interfaces/INuggetExecutionService.cs @@ -1,13 +1,18 @@ -namespace macaroni; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; -public interface INuggetExecutionService +namespace macaroni { - void RegisterNuggets(string groupId, IEnumerable nuggets); - void UnRegisterNuggets(string groupId); + public interface INuggetExecutionService + { + void RegisterNuggets(string groupId, IEnumerable nuggets); + void UnRegisterNuggets(string groupId); - void StartNotify(string groupId, string callbackId, string nuggetName, string? nuggetParameter, Action callback); - void StopNotify(string groupId, string? callbackId); + void StartNotify(string groupId, string callbackId, string nuggetName, string? nuggetParameter, Action callback); + void StopNotify(string groupId, string? callbackId); - public bool AddUserChatMessage(string text); - Task ExecuteAsync(string text); + public bool AddUserChatMessage(string text); + Task ExecuteAsync(string text); + } } diff --git a/src/cs/Interfaces/INuggetTrigger.cs b/src/cs/Interfaces/INuggetTrigger.cs index 9c633edc..0221d019 100644 --- a/src/cs/Interfaces/INuggetTrigger.cs +++ b/src/cs/Interfaces/INuggetTrigger.cs @@ -1,7 +1,8 @@ -namespace macaroni; - -public interface INuggetTrigger : ICommandTrigger +namespace macaroni { - string Name { get; set; } - string? Parameter { get; set; } + public interface INuggetTrigger : ICommandTrigger + { + string Name { get; set; } + string? Parameter { get; set; } + } } \ No newline at end of file diff --git a/src/cs/Interfaces/IOnScreenDisplayService.cs b/src/cs/Interfaces/IOnScreenDisplayService.cs index 6a52d7de..84e89ed5 100644 --- a/src/cs/Interfaces/IOnScreenDisplayService.cs +++ b/src/cs/Interfaces/IOnScreenDisplayService.cs @@ -1,15 +1,19 @@ -namespace macaroni; +using System; +using System.Collections.Generic; -public enum DisplayAlsoSpeaks +namespace macaroni { - Default = -1, - Never = 0, - Always = 1, -} + public enum DisplayAlsoSpeaks + { + Default = -1, + Never = 0, + Always = 1, + } -public interface IOnScreenDisplayService -{ - void DisplayText(string text, string from = "SYSTEM", bool? pending = null, int timeInMs = 0); + public interface IOnScreenDisplayService + { + void DisplayText(string text, string from = "SYSTEM", bool? pending = null, int timeInMs = 0); - void DisplayTips(IEnumerable? tips = null, Func?>? moreTips = null); -} + void DisplayTips(IEnumerable? tips = null, Func?>? moreTips = null); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IOpenAICompletionService.cs b/src/cs/Interfaces/IOpenAICompletionService.cs index c7b765c8..c0595e23 100644 --- a/src/cs/Interfaces/IOpenAICompletionService.cs +++ b/src/cs/Interfaces/IOpenAICompletionService.cs @@ -1,30 +1,33 @@ +using System.Collections.Generic; +using System.Threading.Tasks; using Azure.AI.OpenAI; -namespace macaroni; - -public interface IOpenAiCompletionService +namespace macaroni { - Task Complete( - string prompt, - string? key = null, - string? endpoint = null, - string? deployment = null, - string? maxTokens = null, - string? temperature = null, - string? frequencyPenalty = null, - string? presencePenalty = null, - string? topP = null, - string? stop = null); + public interface IOpenAiCompletionService + { + Task Complete( + string prompt, + string? key = null, + string? endpoint = null, + string? deployment = null, + string? maxTokens = null, + string? temperature = null, + string? frequencyPenalty = null, + string? presencePenalty = null, + string? topP = null, + string? stop = null); - Task CompleteChat( - IList messages, - string? key = null, - string? endpoint = null, - string? deployment = null, - string? maxTokens = null, - string? temperature = null, - string? frequencyPenalty = null, - string? presencePenalty = null, - string? topP = null, - string? stop = null); -} + Task CompleteChat( + IList messages, + string? key = null, + string? endpoint = null, + string? deployment = null, + string? maxTokens = null, + string? temperature = null, + string? frequencyPenalty = null, + string? presencePenalty = null, + string? topP = null, + string? stop = null); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IOpenAIConfigService.cs b/src/cs/Interfaces/IOpenAIConfigService.cs index 52ec3300..8cb4b002 100644 --- a/src/cs/Interfaces/IOpenAIConfigService.cs +++ b/src/cs/Interfaces/IOpenAIConfigService.cs @@ -1,8 +1,7 @@ -using Microsoft.CognitiveServices.Speech; - -namespace macaroni; - -public interface IOpenAiConfigService +namespace macaroni { - void GetOpenAiConnectionInfo(out string? key, out string? endpoint, out string? deployment); -} + public interface IOpenAiConfigService + { + void GetOpenAiConnectionInfo(out string? key, out string? endpoint, out string? deployment); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IParsedValueWarningChecker.cs b/src/cs/Interfaces/IParsedValueWarningChecker.cs index 6feb23e6..9ec28df9 100644 --- a/src/cs/Interfaces/IParsedValueWarningChecker.cs +++ b/src/cs/Interfaces/IParsedValueWarningChecker.cs @@ -1,8 +1,13 @@ -namespace macaroni; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -public interface IParsedValueWarningChecker +namespace macaroni { - IEnumerable Warnings { get; } - void CheckParsedValue(string file, string? mappingName, YamlNode? node, string? value); -} + public interface IParsedValueWarningChecker + { + IEnumerable Warnings { get; } + + void CheckParsedValue(string file, string? mappingName, YamlNode? node, string? value); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IPhraseTrigger.cs b/src/cs/Interfaces/IPhraseTrigger.cs index 3ed74745..81769961 100644 --- a/src/cs/Interfaces/IPhraseTrigger.cs +++ b/src/cs/Interfaces/IPhraseTrigger.cs @@ -1,6 +1,9 @@ -namespace macaroni; +using System.Collections.Generic; -public interface IPhraseTrigger : ICommandTrigger +namespace macaroni { - IEnumerable Phrases { get; } -} + public interface IPhraseTrigger : ICommandTrigger + { + IEnumerable Phrases { get; } + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IPlayMediaService.cs b/src/cs/Interfaces/IPlayMediaService.cs index 71c07a96..86838c1c 100644 --- a/src/cs/Interfaces/IPlayMediaService.cs +++ b/src/cs/Interfaces/IPlayMediaService.cs @@ -1,12 +1,13 @@ -namespace macaroni; - -public interface IPlayMediaService +namespace macaroni { - void Beep(); - void Beep(int frequency, int duration); + public interface IPlayMediaService + { + void Beep(); + void Beep(int frequency, int duration); - void Play(string file, int pos = 0); - void Pause(); - void Resume(); - void Stop(); -} + void Play(string file, int pos = 0); + void Pause(); + void Resume(); + void Stop(); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IProtectedSecretSettingsCache.cs b/src/cs/Interfaces/IProtectedSecretSettingsCache.cs index 604d78df..289a77a0 100644 --- a/src/cs/Interfaces/IProtectedSecretSettingsCache.cs +++ b/src/cs/Interfaces/IProtectedSecretSettingsCache.cs @@ -1,6 +1,7 @@ -namespace macaroni; - -public interface IProtectedSecretSettingsCache : ISecretSettings +namespace macaroni { - void Set(string name, string? value); -} + public interface IProtectedSecretSettingsCache : ISecretSettings + { + void Set(string name, string? value); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IRandomService.cs b/src/cs/Interfaces/IRandomService.cs index 6e2f4c11..43ba63fb 100644 --- a/src/cs/Interfaces/IRandomService.cs +++ b/src/cs/Interfaces/IRandomService.cs @@ -1,8 +1,9 @@ -using System.Diagnostics; +using System.Collections.Generic; -namespace macaroni; - -public interface IRandomNumberService +namespace macaroni { - string PickRandom(IEnumerable values); -} + public interface IRandomNumberService + { + string PickRandom(IEnumerable values); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IResolutionContext.cs b/src/cs/Interfaces/IResolutionContext.cs index cfa208bb..b3678fcc 100644 --- a/src/cs/Interfaces/IResolutionContext.cs +++ b/src/cs/Interfaces/IResolutionContext.cs @@ -1,19 +1,22 @@ -namespace macaroni; +using System; -public enum SetValueKind +namespace macaroni { - OverrideAllResolvers = 1, - InterleavedWithResolvers = 2 -} + public enum SetValueKind + { + OverrideAllResolvers = 1, + InterleavedWithResolvers = 2 + } -public interface IResolutionContext -{ - void Set(string key, object value, SetValueKind kind = SetValueKind.OverrideAllResolvers); - object? Get(string key, object? defaultValue); + public interface IResolutionContext + { + void Set(string key, object value, SetValueKind kind = SetValueKind.OverrideAllResolvers); + object? Get(string key, object? defaultValue); + + string RegisterResolver(string name, Func resolver); - string RegisterResolver(string name, Func resolver); + string? Resolve(string? text, bool deleteUnresolved = false); - string? Resolve(string? text, bool deleteUnresolved = false); - - IImage? ResolveImage(string? text); -} + IImage? ResolveImage(string? text); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IRunAppService.cs b/src/cs/Interfaces/IRunAppService.cs index 252869dc..ca5380bf 100644 --- a/src/cs/Interfaces/IRunAppService.cs +++ b/src/cs/Interfaces/IRunAppService.cs @@ -1,16 +1,17 @@ using System.Diagnostics; -namespace macaroni; - -public interface IRunAppService +namespace macaroni { - void Run(string processOrCommand, string? arguments); - Process? StartProcess(string fileName, string? arguments); - Process? StartCommand(string command, string? arguments); + public interface IRunAppService + { + void Run(string processOrCommand, string? arguments); + Process? StartProcess(string fileName, string? arguments); + Process? StartCommand(string command, string? arguments); - bool SwitchTo(string? title, string? process, string? titleOrProcess, string? exclude); - bool Minimize(string? title, string? process, string? titleOrProcess, string? exclude, bool all = false); - bool Maximize(string? title, string? process, string? titleOrProcess, string? exclude, bool all = false); - bool Restore(string? title, string? process, string? titleOrProcess, string? exclude, bool all = false); - bool Close(string? title, string? process, string? titleOrProcess, string? exclude, bool all = false); -} + bool SwitchTo(string? title, string? process, string? titleOrProcess, string? exclude); + bool Minimize(string? title, string? process, string? titleOrProcess, string? exclude, bool all = false); + bool Maximize(string? title, string? process, string? titleOrProcess, string? exclude, bool all = false); + bool Restore(string? title, string? process, string? titleOrProcess, string? exclude, bool all = false); + bool Close(string? title, string? process, string? titleOrProcess, string? exclude, bool all = false); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IScreenCaptureService.cs b/src/cs/Interfaces/IScreenCaptureService.cs index 554c0560..11dc415c 100644 --- a/src/cs/Interfaces/IScreenCaptureService.cs +++ b/src/cs/Interfaces/IScreenCaptureService.cs @@ -1,12 +1,13 @@ -namespace macaroni; - -public interface IScreenCaptureService +namespace macaroni { - string? GetScreenText(); - string? GetWindowText(); - string? GetFocusText(); + public interface IScreenCaptureService + { + string? GetScreenText(); + string? GetWindowText(); + string? GetFocusText(); - IImage? GetScreenImage(); - IImage? GetWindowImage(); - IImage? GetFocusImage(); -} + IImage? GetScreenImage(); + IImage? GetWindowImage(); + IImage? GetFocusImage(); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IScriptExecutionService.cs b/src/cs/Interfaces/IScriptExecutionService.cs index b4911d23..5a5d584f 100644 --- a/src/cs/Interfaces/IScriptExecutionService.cs +++ b/src/cs/Interfaces/IScriptExecutionService.cs @@ -1,7 +1,8 @@ -namespace macaroni; - -public interface IScriptExecutionService +namespace macaroni { - void Execute(IExecutionContext context, string code, string? language = "javascript"); - object? Evaluate(string code, string? language = "javascript"); -} + public interface IScriptExecutionService + { + void Execute(IExecutionContext context, string code, string? language = "javascript"); + object? Evaluate(string code, string? language = "javascript"); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ISecretSettings.cs b/src/cs/Interfaces/ISecretSettings.cs index b6d3ac31..bfcf4f8c 100644 --- a/src/cs/Interfaces/ISecretSettings.cs +++ b/src/cs/Interfaces/ISecretSettings.cs @@ -1,6 +1,7 @@ -namespace macaroni; - -public interface ISecretSettings +namespace macaroni { - bool TryGet(string name, out string? value); -} + public interface ISecretSettings + { + bool TryGet(string name, out string? value); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ISendKeysService.cs b/src/cs/Interfaces/ISendKeysService.cs index 1f4f3281..c0ac95a4 100644 --- a/src/cs/Interfaces/ISendKeysService.cs +++ b/src/cs/Interfaces/ISendKeysService.cs @@ -1,7 +1,8 @@ -namespace macaroni; - -public interface ISendKeysService +namespace macaroni { - void SendKeys(string keys, int times); - void InsertText(string text); -} + public interface ISendKeysService + { + void SendKeys(string keys, int times); + void InsertText(string text); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ISpeechConfigService.cs b/src/cs/Interfaces/ISpeechConfigService.cs index b7b1e080..eedf8b36 100644 --- a/src/cs/Interfaces/ISpeechConfigService.cs +++ b/src/cs/Interfaces/ISpeechConfigService.cs @@ -1,17 +1,18 @@ using Microsoft.CognitiveServices.Speech; -namespace macaroni; - -public enum SpeechConfigKind +namespace macaroni { - SpeechRecognition = 1, - SpeechSynthesis = 2 -} + public enum SpeechConfigKind + { + SpeechRecognition = 1, + SpeechSynthesis = 2 + } -public interface ISpeechConfigService -{ - string GetDefaultLanguage(); + public interface ISpeechConfigService + { + string GetDefaultLanguage(); - SpeechConfig GetSpeechConfig(SpeechConfigKind kind); - EmbeddedSpeechConfig? GetEmbeddedSpeechConfig(); -} + SpeechConfig GetSpeechConfig(SpeechConfigKind kind); + EmbeddedSpeechConfig? GetEmbeddedSpeechConfig(); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ISynthesisService.cs b/src/cs/Interfaces/ISynthesisService.cs index 97d41118..6543d34b 100644 --- a/src/cs/Interfaces/ISynthesisService.cs +++ b/src/cs/Interfaces/ISynthesisService.cs @@ -1,10 +1,12 @@ +using System.Threading.Tasks; using Microsoft.CognitiveServices.Speech; -namespace macaroni; - -public interface ISynthesisService +namespace macaroni { - Task SpeakText(string text, string? voice, string? output, string? bargeIn); - Task SpeakSsml(string ssml, string? voice, string? output, string? bargeIn); - Task StopSpeaking(); -} + public interface ISynthesisService + { + Task SpeakText(string text, string? voice, string? output, string? bargeIn); + Task SpeakSsml(string ssml, string? voice, string? output, string? bargeIn); + Task StopSpeaking(); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ISystemContext.cs b/src/cs/Interfaces/ISystemContext.cs index 1352ef38..c7cbd48c 100644 --- a/src/cs/Interfaces/ISystemContext.cs +++ b/src/cs/Interfaces/ISystemContext.cs @@ -1,5 +1,6 @@ -namespace macaroni; - -public interface ISystemContext : IResolutionContext +namespace macaroni { -} + public interface ISystemContext : IResolutionContext + { + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ISystemContextResolver.cs b/src/cs/Interfaces/ISystemContextResolver.cs index 0fdb2a1c..0a85e9a7 100644 --- a/src/cs/Interfaces/ISystemContextResolver.cs +++ b/src/cs/Interfaces/ISystemContextResolver.cs @@ -1,5 +1,6 @@ -namespace macaroni; - -public interface ISystemContextResolver : IContextResolver +namespace macaroni { -} + public interface ISystemContextResolver : IContextResolver + { + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ITimeIntervalService.cs b/src/cs/Interfaces/ITimeIntervalService.cs index c3cc04d1..92e5743a 100644 --- a/src/cs/Interfaces/ITimeIntervalService.cs +++ b/src/cs/Interfaces/ITimeIntervalService.cs @@ -1,7 +1,10 @@ -namespace macaroni; +using System; -public interface ITimeIntervalService +namespace macaroni { - int SetInterval(Action action, int milliseconds); - void ClearInterval(int intervalId); -} + public interface ITimeIntervalService + { + int SetInterval(Action action, int milliseconds); + void ClearInterval(int intervalId); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ITranslatorConfigService.cs b/src/cs/Interfaces/ITranslatorConfigService.cs index c573f364..4d685186 100644 --- a/src/cs/Interfaces/ITranslatorConfigService.cs +++ b/src/cs/Interfaces/ITranslatorConfigService.cs @@ -1,8 +1,7 @@ -using Microsoft.CognitiveServices.Speech; - -namespace macaroni; - -public interface ITranslatorServiceConfig +namespace macaroni { - void GetTranslatorConnectionInfo(out string? key, out string? endpoint, out string? region); -} + public interface ITranslatorServiceConfig + { + void GetTranslatorConnectionInfo(out string? key, out string? endpoint, out string? region); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ITranslatorService.cs b/src/cs/Interfaces/ITranslatorService.cs index 3fffec3b..9a0b7ddb 100644 --- a/src/cs/Interfaces/ITranslatorService.cs +++ b/src/cs/Interfaces/ITranslatorService.cs @@ -1,7 +1,10 @@ -namespace macaroni; +using System.Threading.Tasks; -public interface ITranslatorService +namespace macaroni { - string Translate(string text, string? from, string? to); - Task TranslateAsync(string text, string? from, string? to); -} + public interface ITranslatorService + { + string Translate(string text, string? from, string? to); + Task TranslateAsync(string text, string? from, string? to); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ITrayIconDoubleClicked.cs b/src/cs/Interfaces/ITrayIconDoubleClicked.cs index 96a0fe3b..f4b115e9 100644 --- a/src/cs/Interfaces/ITrayIconDoubleClicked.cs +++ b/src/cs/Interfaces/ITrayIconDoubleClicked.cs @@ -1,6 +1,7 @@ -namespace macaroni; - -public interface ITrayIconDoubleClicked +namespace macaroni { - void Notify(); -} + public interface ITrayIconDoubleClicked + { + void Notify(); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ITriggerCollection.cs b/src/cs/Interfaces/ITriggerCollection.cs index 285c9436..a0559761 100644 --- a/src/cs/Interfaces/ITriggerCollection.cs +++ b/src/cs/Interfaces/ITriggerCollection.cs @@ -1,5 +1,8 @@ -namespace macaroni; +using System.Collections.Generic; -public interface ITriggerCollection : IEnumerable, ICommandTrigger +namespace macaroni { -} + public interface ITriggerCollection : IEnumerable, ICommandTrigger + { + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ITriggerCollectionYamlParser.cs b/src/cs/Interfaces/ITriggerCollectionYamlParser.cs index 34267a1c..22eb918f 100644 --- a/src/cs/Interfaces/ITriggerCollectionYamlParser.cs +++ b/src/cs/Interfaces/ITriggerCollectionYamlParser.cs @@ -1,7 +1,10 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -public interface ITriggerCollectionYamlParser +namespace macaroni { - ITriggerCollection? CheckForTriggers(string file, YamlMappingNode mapping, string triggersMappingName, IParsedValueWarningChecker? warnings); - ITriggerCollection TriggersFromSequence(string file, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings); -} + public interface ITriggerCollectionYamlParser + { + ITriggerCollection? CheckForTriggers(string file, YamlMappingNode mapping, string triggersMappingName, IParsedValueWarningChecker? warnings); + ITriggerCollection TriggersFromSequence(string file, YamlSequenceNode sequence, IParsedValueWarningChecker? warnings); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ITriggerFactory.cs b/src/cs/Interfaces/ITriggerFactory.cs index 9b1abdbb..ac748009 100644 --- a/src/cs/Interfaces/ITriggerFactory.cs +++ b/src/cs/Interfaces/ITriggerFactory.cs @@ -1,8 +1,11 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -public interface ITriggerFactory +namespace macaroni { - bool IsInvalidTriggerNode(YamlMappingNode mapping); - ICommandTrigger TriggerFromYamlNode(string file, YamlNode node, IParsedValueWarningChecker? warnings); - string GetValidTriggerMappingTypes(); -} + public interface ITriggerFactory + { + bool IsInvalidTriggerNode(YamlMappingNode mapping); + ICommandTrigger TriggerFromYamlNode(string file, YamlNode node, IParsedValueWarningChecker? warnings); + string GetValidTriggerMappingTypes(); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ITriggerYamlParser.cs b/src/cs/Interfaces/ITriggerYamlParser.cs index 833b3349..dcb7826a 100644 --- a/src/cs/Interfaces/ITriggerYamlParser.cs +++ b/src/cs/Interfaces/ITriggerYamlParser.cs @@ -1,7 +1,10 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -public interface ITriggerYamlParser +namespace macaroni { - string Kind { get; } - ICommandTrigger Parse(string file, YamlMappingNode? trigger, YamlNode value, IParsedValueWarningChecker? warnings); -} + public interface ITriggerYamlParser + { + string Kind { get; } + ICommandTrigger Parse(string file, YamlMappingNode? trigger, YamlNode value, IParsedValueWarningChecker? warnings); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IUiAutomationService.cs b/src/cs/Interfaces/IUiAutomationService.cs index f351a6a6..c15707d9 100644 --- a/src/cs/Interfaces/IUiAutomationService.cs +++ b/src/cs/Interfaces/IUiAutomationService.cs @@ -1,11 +1,14 @@ -namespace macaroni; +using System.Threading.Tasks; -public interface IUiAutomationService +namespace macaroni { - Task StartAsync(); - Task StopAsync(); + public interface IUiAutomationService + { + Task StartAsync(); + Task StopAsync(); - bool GetPosition(string element, out PAL.Rectangle rect); - bool GetWindowPosition(out PAL.Rectangle rect); - bool GetFocusPosition(out PAL.Rectangle rect); -} + bool GetPosition(string element, out PAL.Rectangle rect); + bool GetWindowPosition(out PAL.Rectangle rect); + bool GetFocusPosition(out PAL.Rectangle rect); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IUnexpectedDialogPolicy.cs b/src/cs/Interfaces/IUnexpectedDialogPolicy.cs index 160b59b6..3126821f 100644 --- a/src/cs/Interfaces/IUnexpectedDialogPolicy.cs +++ b/src/cs/Interfaces/IUnexpectedDialogPolicy.cs @@ -1,32 +1,33 @@ -namespace macaroni; - -public interface IUnexpectedDialogPolicy +namespace macaroni { - public enum Action + public interface IUnexpectedDialogPolicy { - Ignore = 0, - Cancel = 1, - Retry = 2 - } + public enum Action + { + Ignore = 0, + Cancel = 1, + Retry = 2 + } - // CommandPolicy and PhrasePolicy are used to control how "dialogs" work, specifically, what happens when a - // dialog is "open" (not completed) and either (a) an unknown phrase is processed, or (b) a different command is executed - // - // The Policy values can be either (i) an Action enumerated value (e.g. Cancel) or (ii) an implementation of IExecutorCollection - // - // In cases (a) and (b), all "open" dialog commands marked as "Cancel" will be canceled, removed, and thus, no longer "open"; - // their carried context will be destroyed. - // - // In cases (a) and (b), additionally, the most recent "open" dialog command marked as either "Retry" or containing an implementation of - // IExecutorCollection, will be selected to be "retried/re-executed". If marked with action == "Retry", it will simply be "re-executed" - // with the "carried" context (dialog frame), with two changes: - // - the "context.turn" will be incremented by 1 - // - the "trigger.type" will be updated to be either "unexpected.phrase" or "unexpected.command" for cases (a) and (b) respectively. - // - // If it contains an implementation of IExeuctorCollection, the carried context changes will be applied, but instead of re-executing - // the full dialog, simply the executors contained in that policy will be executed. - - public object? CommandPolicy { get; } - public object? PhrasePolicy { get; } - public object? TimeoutPolicy { get; } -} + // CommandPolicy and PhrasePolicy are used to control how "dialogs" work, specifically, what happens when a + // dialog is "open" (not completed) and either (a) an unknown phrase is processed, or (b) a different command is executed + // + // The Policy values can be either (i) an Action enumerated value (e.g. Cancel) or (ii) an implementation of IExecutorCollection + // + // In cases (a) and (b), all "open" dialog commands marked as "Cancel" will be canceled, removed, and thus, no longer "open"; + // their carried context will be destroyed. + // + // In cases (a) and (b), additionally, the most recent "open" dialog command marked as either "Retry" or containing an implementation of + // IExecutorCollection, will be selected to be "retried/re-executed". If marked with action == "Retry", it will simply be "re-executed" + // with the "carried" context (dialog frame), with two changes: + // - the "context.turn" will be incremented by 1 + // - the "trigger.type" will be updated to be either "unexpected.phrase" or "unexpected.command" for cases (a) and (b) respectively. + // + // If it contains an implementation of IExeuctorCollection, the carried context changes will be applied, but instead of re-executing + // the full dialog, simply the executors contained in that policy will be executed. + + public object? CommandPolicy { get; } + public object? PhrasePolicy { get; } + public object? TimeoutPolicy { get; } + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IWhenTrigger.cs b/src/cs/Interfaces/IWhenTrigger.cs index c2bf3656..947c3e35 100644 --- a/src/cs/Interfaces/IWhenTrigger.cs +++ b/src/cs/Interfaces/IWhenTrigger.cs @@ -1,6 +1,7 @@ -namespace macaroni; - -public interface IWhenTrigger : ICommandTrigger +namespace macaroni { - IConditionCollection? Conditions { get; } -} + public interface IWhenTrigger : ICommandTrigger + { + IConditionCollection? Conditions { get; } + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IWindowMonitoringService.cs b/src/cs/Interfaces/IWindowMonitoringService.cs index 3a03ee91..4a276154 100644 --- a/src/cs/Interfaces/IWindowMonitoringService.cs +++ b/src/cs/Interfaces/IWindowMonitoringService.cs @@ -1,10 +1,14 @@ -namespace macaroni; +using System; +using System.Collections.Generic; -public interface IWindowMonitoringService +namespace macaroni { - WindowInfo GetCurrentWindowInfo(); - IDictionary GetAllWindowInfo(); + public interface IWindowMonitoringService + { + WindowInfo GetCurrentWindowInfo(); + IDictionary GetAllWindowInfo(); - void StartNotify(Action foregroundChanged, Action, IDictionary> backgroundChanged); - void StopNotify(); -} + void StartNotify(Action foregroundChanged, Action, IDictionary> backgroundChanged); + void StopNotify(); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IYamlValue.cs b/src/cs/Interfaces/IYamlValue.cs index 4367b8b3..524cae9b 100644 --- a/src/cs/Interfaces/IYamlValue.cs +++ b/src/cs/Interfaces/IYamlValue.cs @@ -1,7 +1,8 @@ -namespace macaroni; - -public interface IYamlValue +namespace macaroni { - string Name { get; } - object? Value { get; } -} + public interface IYamlValue + { + string Name { get; } + object? Value { get; } + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IYamlValueCollection.cs b/src/cs/Interfaces/IYamlValueCollection.cs index 32d38d61..718a4366 100644 --- a/src/cs/Interfaces/IYamlValueCollection.cs +++ b/src/cs/Interfaces/IYamlValueCollection.cs @@ -1,5 +1,8 @@ -namespace macaroni; +using System.Collections.Generic; -public interface IYamlValueCollection : IDictionary +namespace macaroni { -} + public interface IYamlValueCollection : IDictionary + { + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IYamlValueCollectionYamlParser.cs b/src/cs/Interfaces/IYamlValueCollectionYamlParser.cs index 67b6355c..b5a1c22b 100644 --- a/src/cs/Interfaces/IYamlValueCollectionYamlParser.cs +++ b/src/cs/Interfaces/IYamlValueCollectionYamlParser.cs @@ -1,7 +1,10 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -public interface IYamlValueCollectionYamlParser +namespace macaroni { - IYamlValueCollection? CheckForValues(string file, YamlMappingNode mapping, string valuesMappingName, IParsedValueWarningChecker? warnings); - IYamlValueCollection ValuesFromYamlMapping(string file, YamlMappingNode mapping, IParsedValueWarningChecker? warnings); -} + public interface IYamlValueCollectionYamlParser + { + IYamlValueCollection? CheckForValues(string file, YamlMappingNode mapping, string valuesMappingName, IParsedValueWarningChecker? warnings); + IYamlValueCollection ValuesFromYamlMapping(string file, YamlMappingNode mapping, IParsedValueWarningChecker? warnings); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IYamlValueExtensions.cs b/src/cs/Interfaces/IYamlValueExtensions.cs index 900fbad2..bb12fd2d 100644 --- a/src/cs/Interfaces/IYamlValueExtensions.cs +++ b/src/cs/Interfaces/IYamlValueExtensions.cs @@ -1,34 +1,37 @@ -namespace macaroni; +using System.Collections.Generic; -public static class IYamlValueExtensions +namespace macaroni { - public static string Before(this string value, char ch) + public static class IYamlValueExtensions { - var at = value.IndexOf(ch); - return at == 0 ? string.Empty - : at >= 1 ? value.Substring(0, at).TrimEnd(' ') - : value; - } + public static string Before(this string value, char ch) + { + var at = value.IndexOf(ch); + return at == 0 ? string.Empty + : at >= 1 ? value.Substring(0, at).TrimEnd(' ') + : value; + } - public static string After(this string value, char ch) - { - var at = value.IndexOf(ch); - return at >= value.Length ? string.Empty - : at >= 0 ? value.Substring(at + 1).TrimStart(' ') - : value; - } + public static string After(this string value, char ch) + { + var at = value.IndexOf(ch); + return at >= value.Length ? string.Empty + : at >= 0 ? value.Substring(at + 1).TrimStart(' ') + : value; + } - public static IEnumerable? ToStrings(this IYamlValue value) - { - var values = value.Value as IEnumerable; - if (values == null) + public static IEnumerable? ToStrings(this IYamlValue value) { - var str = value.Value as string; - if (str != null) + var values = value.Value as IEnumerable; + if (values == null) { - values = new[] { str }; + var str = value.Value as string; + if (str != null) + { + values = new[] { str }; + } } + return values; } - return values; } -} +} \ No newline at end of file diff --git a/src/cs/Interfaces/IYamlValueFactory.cs b/src/cs/Interfaces/IYamlValueFactory.cs index 36f1c475..545b8491 100644 --- a/src/cs/Interfaces/IYamlValueFactory.cs +++ b/src/cs/Interfaces/IYamlValueFactory.cs @@ -1,7 +1,10 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -public interface IYamlValueFactory +namespace macaroni { - IYamlValue ValueFromYamlNode(string file, string name, YamlNode node, IParsedValueWarningChecker? warnings); - string GetValidValueMappingTypes(); -} + public interface IYamlValueFactory + { + IYamlValue ValueFromYamlNode(string file, string name, YamlNode node, IParsedValueWarningChecker? warnings); + string GetValidValueMappingTypes(); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/IYamlValueYamlParser.cs b/src/cs/Interfaces/IYamlValueYamlParser.cs index cceda6a4..18162d56 100644 --- a/src/cs/Interfaces/IYamlValueYamlParser.cs +++ b/src/cs/Interfaces/IYamlValueYamlParser.cs @@ -1,7 +1,10 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -public interface IYamlValueYamlParser +namespace macaroni { - string Kind { get; } - IYamlValue Parse(string file, string name, YamlNode value, IParsedValueWarningChecker? warnings); -} + public interface IYamlValueYamlParser + { + string Kind { get; } + IYamlValue Parse(string file, string name, YamlNode value, IParsedValueWarningChecker? warnings); + } +} \ No newline at end of file diff --git a/src/cs/Interfaces/ListeningState.cs b/src/cs/Interfaces/ListeningState.cs index 355a32b5..63688081 100644 --- a/src/cs/Interfaces/ListeningState.cs +++ b/src/cs/Interfaces/ListeningState.cs @@ -1,53 +1,67 @@ -namespace macaroni; +using System; -public enum ListeningState +namespace macaroni { - Off = 0, // No audio captured, no AI tech processing audio - On = 1, // Audio captured, SR processing audio, will listen for multiple utterances - Sleep = 2, // Audio captured, KWS processing audio, will listen for multiple utterances, with leading word being a/the keyword - Once = 3 // Audio captured, SR processing audio, will listen for one utterance, then transit to Off -} - -public static class ListeningStateHelpers -{ - public static string AsString(this ListeningState state) + public enum ListeningState { - return state switch - { - ListeningState.Once => "Listening (once)", - ListeningState.On => "Listening", - ListeningState.Off => "Off", - ListeningState.Sleep => "Sleeping", - _ => throw new Exception() - }; + Off = 0, // No audio captured, no AI tech processing audio + On = 1, // Audio captured, SR processing audio, will listen for multiple utterances + Sleep = 2, // Audio captured, KWS processing audio, will listen for multiple utterances, with leading word being a/the keyword + Once = 3 // Audio captured, SR processing audio, will listen for one utterance, then transit to Off } - public static bool TryParse(string s, out ListeningState state) + public static class ListeningStateHelpers { - (var ok, state) = s.ToLower() switch + public static string AsString(this ListeningState state) { - "sleep" or "keyword" or "kws" => (true, ListeningState.Sleep), - "start" or "on" or "true" or "yes" => (true, ListeningState.On), - "stop" or "off" or "false" or "no" => (true, ListeningState.Off), - "once" => (true, ListeningState.Once), - _ => (false, ListeningState.Off) - }; - return ok; - } + return state switch + { + ListeningState.Once => "Listening (once)", + ListeningState.On => "Listening", + ListeningState.Off => "Off", + ListeningState.Sleep => "Sleeping", + _ => throw new Exception() + }; + } - public static ListeningState Parse(string s) - { - TryParse(s, out var state); - return state; - } + public static bool TryParse(string s, out ListeningState state) + { + bool ok; + (ok, state) = s.ToLower() switch + { + "sleep" => (true, ListeningState.Sleep), + "keyword" => (true, ListeningState.Sleep), + "kws" => (true, ListeningState.Sleep), + "start" => (true, ListeningState.On), + "on" => (true, ListeningState.On), + "true" => (true, ListeningState.On), + "yes" => (true, ListeningState.On), + "stop" => (true, ListeningState.Off), + "off" => (true, ListeningState.Off), + "false" => (true, ListeningState.Off), + "no" => (true, ListeningState.Off), + "once" => (true, ListeningState.Once), + _ => (false, ListeningState.Off) + }; + return ok; + } - public static ListeningState ToggleState(ListeningState state) - { - return state switch + public static ListeningState Parse(string s) { - ListeningState.Off or ListeningState.Sleep => ListeningState.On, - ListeningState.On or _ => ListeningState.Off - }; - } + TryParse(s, out var state); + return state; + } + public static ListeningState ToggleState(ListeningState state) + { + return state switch + { + ListeningState.Off => ListeningState.On, + ListeningState.Sleep => ListeningState.On, + ListeningState.On => ListeningState.Off, + _ => ListeningState.Off + }; + } + + } } \ No newline at end of file diff --git a/src/cs/Interfaces/PAL/Rectangle.cs b/src/cs/Interfaces/PAL/Rectangle.cs index ff8585a9..9006103c 100644 --- a/src/cs/Interfaces/PAL/Rectangle.cs +++ b/src/cs/Interfaces/PAL/Rectangle.cs @@ -1,335 +1,337 @@ +using System; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; -namespace macaroni.PAL; - -public struct Rectangle : IEquatable +namespace macaroni.PAL { - public static readonly Rectangle Empty; - - private int x; // Do not rename (binary serialization) - private int y; // Do not rename (binary serialization) - private int width; // Do not rename (binary serialization) - private int height; // Do not rename (binary serialization) - - /// - /// Initializes a new instance of the class with the specified location - /// and size. - /// - public Rectangle(int x, int y, int width, int height) + public struct Rectangle : IEquatable { - this.x = x; - this.y = y; - this.width = width; - this.height = height; - } + public static readonly Rectangle Empty; + + private int x; // Do not rename (binary serialization) + private int y; // Do not rename (binary serialization) + private int width; // Do not rename (binary serialization) + private int height; // Do not rename (binary serialization) + + /// + /// Initializes a new instance of the class with the specified location + /// and size. + /// + public Rectangle(int x, int y, int width, int height) + { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } - // /// - // /// Initializes a new instance of the Rectangle class with the specified location and size. - // /// - // public Rectangle(Point location, Size size) - // { - // x = location.X; - // y = location.Y; - // width = size.Width; - // height = size.Height; - // } - - /// - /// Creates a new with the specified location and size. - /// - public static Rectangle FromLTRB(int left, int top, int right, int bottom) => - new Rectangle(left, top, unchecked(right - left), unchecked(bottom - top)); - - // /// - // /// Gets or sets the coordinates of the upper-left corner of the rectangular region represented by this - // /// . - // /// - // [Browsable(false)] - // public Point Location - // { - // readonly get => new Point(X, Y); - // set - // { - // X = value.X; - // Y = value.Y; - // } - // } - - // /// - // /// Gets or sets the size of this . - // /// - // [Browsable(false)] - // public Size Size - // { - // readonly get => new Size(Width, Height); - // set - // { - // Width = value.Width; - // Height = value.Height; - // } - // } - - /// - /// Gets or sets the x-coordinate of the upper-left corner of the rectangular region defined by this - /// . - /// - public int X - { - readonly get => x; - set => x = value; - } + // /// + // /// Initializes a new instance of the Rectangle class with the specified location and size. + // /// + // public Rectangle(Point location, Size size) + // { + // x = location.X; + // y = location.Y; + // width = size.Width; + // height = size.Height; + // } + + /// + /// Creates a new with the specified location and size. + /// + public static Rectangle FromLTRB(int left, int top, int right, int bottom) => + new Rectangle(left, top, unchecked(right - left), unchecked(bottom - top)); + + // /// + // /// Gets or sets the coordinates of the upper-left corner of the rectangular region represented by this + // /// . + // /// + // [Browsable(false)] + // public Point Location + // { + // readonly get => new Point(X, Y); + // set + // { + // X = value.X; + // Y = value.Y; + // } + // } + + // /// + // /// Gets or sets the size of this . + // /// + // [Browsable(false)] + // public Size Size + // { + // readonly get => new Size(Width, Height); + // set + // { + // Width = value.Width; + // Height = value.Height; + // } + // } + + /// + /// Gets or sets the x-coordinate of the upper-left corner of the rectangular region defined by this + /// . + /// + public int X + { + readonly get => x; + set => x = value; + } - /// - /// Gets or sets the y-coordinate of the upper-left corner of the rectangular region defined by this - /// . - /// - public int Y - { - readonly get => y; - set => y = value; - } + /// + /// Gets or sets the y-coordinate of the upper-left corner of the rectangular region defined by this + /// . + /// + public int Y + { + readonly get => y; + set => y = value; + } - /// - /// Gets or sets the width of the rectangular region defined by this . - /// - public int Width - { - readonly get => width; - set => width = value; - } + /// + /// Gets or sets the width of the rectangular region defined by this . + /// + public int Width + { + readonly get => width; + set => width = value; + } - /// - /// Gets or sets the width of the rectangular region defined by this . - /// - public int Height - { - readonly get => height; - set => height = value; - } + /// + /// Gets or sets the width of the rectangular region defined by this . + /// + public int Height + { + readonly get => height; + set => height = value; + } - /// - /// Gets the x-coordinate of the upper-left corner of the rectangular region defined by this - /// . - /// - [Browsable(false)] - public readonly int Left => X; - - /// - /// Gets the y-coordinate of the upper-left corner of the rectangular region defined by this - /// . - /// - [Browsable(false)] - public readonly int Top => Y; - - /// - /// Gets the x-coordinate of the lower-right corner of the rectangular region defined by this - /// . - /// - [Browsable(false)] - public readonly int Right => unchecked(X + Width); - - /// - /// Gets the y-coordinate of the lower-right corner of the rectangular region defined by this - /// . - /// - [Browsable(false)] - public readonly int Bottom => unchecked(Y + Height); - - /// - /// Tests whether this has a - /// or a of 0. - /// - [Browsable(false)] - public readonly bool IsEmpty => height == 0 && width == 0 && x == 0 && y == 0; - - /// - /// Tests whether is a with the same location - /// and size of this Rectangle. - /// - public override readonly bool Equals([NotNullWhen(true)] object? obj) => obj is Rectangle && Equals((Rectangle)obj); - - public readonly bool Equals(Rectangle other) => this == other; - - /// - /// Tests whether two objects have equal location and size. - /// - public static bool operator ==(Rectangle left, Rectangle right) => - left.X == right.X && left.Y == right.Y && left.Width == right.Width && left.Height == right.Height; - - /// - /// Tests whether two objects differ in location or size. - /// - public static bool operator !=(Rectangle left, Rectangle right) => !(left == right); - - // /// - // /// Converts a RectangleF to a Rectangle by performing a ceiling operation on all the coordinates. - // /// - // public static Rectangle Ceiling(RectangleF value) - // { - // unchecked - // { - // return new Rectangle( - // (int)Math.Ceiling(value.X), - // (int)Math.Ceiling(value.Y), - // (int)Math.Ceiling(value.Width), - // (int)Math.Ceiling(value.Height)); - // } - // } - - // /// - // /// Converts a RectangleF to a Rectangle by performing a truncate operation on all the coordinates. - // /// - // public static Rectangle Truncate(RectangleF value) - // { - // unchecked - // { - // return new Rectangle( - // (int)value.X, - // (int)value.Y, - // (int)value.Width, - // (int)value.Height); - // } - // } - - // /// - // /// Converts a RectangleF to a Rectangle by performing a round operation on all the coordinates. - // /// - // public static Rectangle Round(RectangleF value) - // { - // unchecked - // { - // return new Rectangle( - // (int)Math.Round(value.X), - // (int)Math.Round(value.Y), - // (int)Math.Round(value.Width), - // (int)Math.Round(value.Height)); - // } - // } - - /// - /// Determines if the specified point is contained within the rectangular region defined by this - /// . - /// - public readonly bool Contains(int x, int y) => X <= x && x < X + Width && Y <= y && y < Y + Height; - - // /// - // /// Determines if the specified point is contained within the rectangular region defined by this - // /// . - // /// - // public readonly bool Contains(Point pt) => Contains(pt.X, pt.Y); - - /// - /// Determines if the rectangular region represented by is entirely contained within the - /// rectangular region represented by this . - /// - public readonly bool Contains(Rectangle rect) => - (X <= rect.X) && (rect.X + rect.Width <= X + Width) && - (Y <= rect.Y) && (rect.Y + rect.Height <= Y + Height); - - public override readonly int GetHashCode() => HashCode.Combine(X, Y, Width, Height); - - /// - /// Inflates this by the specified amount. - /// - public void Inflate(int width, int height) - { - unchecked + /// + /// Gets the x-coordinate of the upper-left corner of the rectangular region defined by this + /// . + /// + [Browsable(false)] + public readonly int Left => X; + + /// + /// Gets the y-coordinate of the upper-left corner of the rectangular region defined by this + /// . + /// + [Browsable(false)] + public readonly int Top => Y; + + /// + /// Gets the x-coordinate of the lower-right corner of the rectangular region defined by this + /// . + /// + [Browsable(false)] + public readonly int Right => unchecked(X + Width); + + /// + /// Gets the y-coordinate of the lower-right corner of the rectangular region defined by this + /// . + /// + [Browsable(false)] + public readonly int Bottom => unchecked(Y + Height); + + /// + /// Tests whether this has a + /// or a of 0. + /// + [Browsable(false)] + public readonly bool IsEmpty => height == 0 && width == 0 && x == 0 && y == 0; + + /// + /// Tests whether is a with the same location + /// and size of this Rectangle. + /// + public override readonly bool Equals([NotNullWhen(true)] object? obj) => obj is Rectangle && Equals((Rectangle)obj); + + public readonly bool Equals(Rectangle other) => this == other; + + /// + /// Tests whether two objects have equal location and size. + /// + public static bool operator ==(Rectangle left, Rectangle right) => + left.X == right.X && left.Y == right.Y && left.Width == right.Width && left.Height == right.Height; + + /// + /// Tests whether two objects differ in location or size. + /// + public static bool operator !=(Rectangle left, Rectangle right) => !(left == right); + + // /// + // /// Converts a RectangleF to a Rectangle by performing a ceiling operation on all the coordinates. + // /// + // public static Rectangle Ceiling(RectangleF value) + // { + // unchecked + // { + // return new Rectangle( + // (int)Math.Ceiling(value.X), + // (int)Math.Ceiling(value.Y), + // (int)Math.Ceiling(value.Width), + // (int)Math.Ceiling(value.Height)); + // } + // } + + // /// + // /// Converts a RectangleF to a Rectangle by performing a truncate operation on all the coordinates. + // /// + // public static Rectangle Truncate(RectangleF value) + // { + // unchecked + // { + // return new Rectangle( + // (int)value.X, + // (int)value.Y, + // (int)value.Width, + // (int)value.Height); + // } + // } + + // /// + // /// Converts a RectangleF to a Rectangle by performing a round operation on all the coordinates. + // /// + // public static Rectangle Round(RectangleF value) + // { + // unchecked + // { + // return new Rectangle( + // (int)Math.Round(value.X), + // (int)Math.Round(value.Y), + // (int)Math.Round(value.Width), + // (int)Math.Round(value.Height)); + // } + // } + + /// + /// Determines if the specified point is contained within the rectangular region defined by this + /// . + /// + public readonly bool Contains(int x, int y) => X <= x && x < X + Width && Y <= y && y < Y + Height; + + // /// + // /// Determines if the specified point is contained within the rectangular region defined by this + // /// . + // /// + // public readonly bool Contains(Point pt) => Contains(pt.X, pt.Y); + + /// + /// Determines if the rectangular region represented by is entirely contained within the + /// rectangular region represented by this . + /// + public readonly bool Contains(Rectangle rect) => + (X <= rect.X) && (rect.X + rect.Width <= X + Width) && + (Y <= rect.Y) && (rect.Y + rect.Height <= Y + Height); + + public override readonly int GetHashCode() => HashCode.Combine(X, Y, Width, Height); + + /// + /// Inflates this by the specified amount. + /// + public void Inflate(int width, int height) { - X -= width; - Y -= height; + unchecked + { + X -= width; + Y -= height; + + Width += 2 * width; + Height += 2 * height; + } + } - Width += 2 * width; - Height += 2 * height; + // /// + // /// Inflates this by the specified amount. + // /// + // public void Inflate(Size size) => Inflate(size.Width, size.Height); + + /// + /// Creates a that is inflated by the specified amount. + /// + public static Rectangle Inflate(Rectangle rect, int x, int y) + { + Rectangle r = rect; + r.Inflate(x, y); + return r; } - } - // /// - // /// Inflates this by the specified amount. - // /// - // public void Inflate(Size size) => Inflate(size.Width, size.Height); + /// + /// Creates a Rectangle that represents the intersection between this Rectangle and rect. + /// + public void Intersect(Rectangle rect) + { + Rectangle result = Intersect(rect, this); - /// - /// Creates a that is inflated by the specified amount. - /// - public static Rectangle Inflate(Rectangle rect, int x, int y) - { - Rectangle r = rect; - r.Inflate(x, y); - return r; - } + X = result.X; + Y = result.Y; + Width = result.Width; + Height = result.Height; + } - /// - /// Creates a Rectangle that represents the intersection between this Rectangle and rect. - /// - public void Intersect(Rectangle rect) - { - Rectangle result = Intersect(rect, this); + /// + /// Creates a rectangle that represents the intersection between a and b. If there is no intersection, an + /// empty rectangle is returned. + /// + public static Rectangle Intersect(Rectangle a, Rectangle b) + { + int x1 = Math.Max(a.X, b.X); + int x2 = Math.Min(a.X + a.Width, b.X + b.Width); + int y1 = Math.Max(a.Y, b.Y); + int y2 = Math.Min(a.Y + a.Height, b.Y + b.Height); - X = result.X; - Y = result.Y; - Width = result.Width; - Height = result.Height; - } + if (x2 >= x1 && y2 >= y1) + { + return new Rectangle(x1, y1, x2 - x1, y2 - y1); + } - /// - /// Creates a rectangle that represents the intersection between a and b. If there is no intersection, an - /// empty rectangle is returned. - /// - public static Rectangle Intersect(Rectangle a, Rectangle b) - { - int x1 = Math.Max(a.X, b.X); - int x2 = Math.Min(a.X + a.Width, b.X + b.Width); - int y1 = Math.Max(a.Y, b.Y); - int y2 = Math.Min(a.Y + a.Height, b.Y + b.Height); + return Empty; + } - if (x2 >= x1 && y2 >= y1) + /// + /// Determines if this rectangle intersects with rect. + /// + public readonly bool IntersectsWith(Rectangle rect) => + (rect.X < X + Width) && (X < rect.X + rect.Width) && + (rect.Y < Y + Height) && (Y < rect.Y + rect.Height); + + /// + /// Creates a rectangle that represents the union between a and b. + /// + public static Rectangle Union(Rectangle a, Rectangle b) { + int x1 = Math.Min(a.X, b.X); + int x2 = Math.Max(a.X + a.Width, b.X + b.Width); + int y1 = Math.Min(a.Y, b.Y); + int y2 = Math.Max(a.Y + a.Height, b.Y + b.Height); + return new Rectangle(x1, y1, x2 - x1, y2 - y1); } - return Empty; - } - - /// - /// Determines if this rectangle intersects with rect. - /// - public readonly bool IntersectsWith(Rectangle rect) => - (rect.X < X + Width) && (X < rect.X + rect.Width) && - (rect.Y < Y + Height) && (Y < rect.Y + rect.Height); - - /// - /// Creates a rectangle that represents the union between a and b. - /// - public static Rectangle Union(Rectangle a, Rectangle b) - { - int x1 = Math.Min(a.X, b.X); - int x2 = Math.Max(a.X + a.Width, b.X + b.Width); - int y1 = Math.Min(a.Y, b.Y); - int y2 = Math.Max(a.Y + a.Height, b.Y + b.Height); + // /// + // /// Adjusts the location of this rectangle by the specified amount. + // /// + // public void Offset(Point pos) => Offset(pos.X, pos.Y); - return new Rectangle(x1, y1, x2 - x1, y2 - y1); - } - - // /// - // /// Adjusts the location of this rectangle by the specified amount. - // /// - // public void Offset(Point pos) => Offset(pos.X, pos.Y); - - /// - /// Adjusts the location of this rectangle by the specified amount. - /// - public void Offset(int x, int y) - { - unchecked + /// + /// Adjusts the location of this rectangle by the specified amount. + /// + public void Offset(int x, int y) { - X += x; - Y += y; + unchecked + { + X += x; + Y += y; + } } - } - /// - /// Converts the attributes of this to a human readable string. - /// - public override readonly string ToString() => $"{{X={X},Y={Y},Width={Width},Height={Height}}}"; -} + /// + /// Converts the attributes of this to a human readable string. + /// + public override readonly string ToString() => $"{{X={X},Y={Y},Width={Width},Height={Height}}}"; + } +} \ No newline at end of file diff --git a/src/cs/NativeLogging/DiagnosticsInterop.cs b/src/cs/NativeLogging/DiagnosticsInterop.cs index e9f26125..891446d0 100644 --- a/src/cs/NativeLogging/DiagnosticsInterop.cs +++ b/src/cs/NativeLogging/DiagnosticsInterop.cs @@ -1,36 +1,38 @@ -using System.Runtime.CompilerServices; +using System.IO; using macaroni.interop; +using System.Runtime.CompilerServices; -namespace macaroni; - -internal static class DiagnosticsInterop -{ - public static void diagnostics_log_trace_string( - int level, - string title, - string message, - [CallerFilePath] string? fileName = null, - [CallerLineNumber] int lineNumber = 0) +namespace macaroni +{ + internal static class DiagnosticsInterop { - using var nativeTitle = NativeUtils.ToNativeNullTerminatedUtf8String(title); - using var nativeMessage = NativeUtils.ToNativeNullTerminatedUtf8String(message); - using var nativeFileName = NativeUtils.ToNativeNullTerminatedUtf8String(Path.GetFileName(fileName)); - if (OS.IsWindows()) - { - SpeechNativeMethods.diagnostics_log_trace_string((int)level, nativeTitle.Handle, nativeFileName.Handle, lineNumber, nativeMessage.Handle); - } - else if (OS.IsAndroid()) + public static void diagnostics_log_trace_string( + int level, + string title, + string message, + [CallerFilePath] string? fileName = null, + [CallerLineNumber] int lineNumber = 0) { - SpeechNativeMethods.android_diagnostics_log_trace_string((int)level, nativeTitle.Handle, nativeFileName.Handle, lineNumber, nativeMessage.Handle); + using var nativeTitle = NativeUtils.ToNativeNullTerminatedUtf8String(title); + using var nativeMessage = NativeUtils.ToNativeNullTerminatedUtf8String(message); + using var nativeFileName = NativeUtils.ToNativeNullTerminatedUtf8String(Path.GetFileName(fileName)); + if (OS.IsWindows()) + { + SpeechNativeMethods.diagnostics_log_trace_string((int)level, nativeTitle.Handle, nativeFileName.Handle, lineNumber, nativeMessage.Handle); + } + else if (OS.IsAndroid()) + { + SpeechNativeMethods.android_diagnostics_log_trace_string((int)level, nativeTitle.Handle, nativeFileName.Handle, lineNumber, nativeMessage.Handle); + } + else + { + SpeechNativeMethods.unix_diagnostics_log_trace_string((int)level, nativeTitle.Handle, nativeFileName.Handle, lineNumber, nativeMessage.Handle); + } } - else - { - SpeechNativeMethods.unix_diagnostics_log_trace_string((int)level, nativeTitle.Handle, nativeFileName.Handle, lineNumber, nativeMessage.Handle); - } - } - public const int __TRACE_LEVEL_INFO = 0x08; // Trace_Info - public const int __TRACE_LEVEL_WARNING = 0x04; // Trace_Warning - public const int __TRACE_LEVEL_ERROR = 0x02; // Trace_Error - public const int __TRACE_LEVEL_VERBOSE = 0x10; // Trace_Verbose -} + public const int __TRACE_LEVEL_INFO = 0x08; // Trace_Info + public const int __TRACE_LEVEL_WARNING = 0x04; // Trace_Warning + public const int __TRACE_LEVEL_ERROR = 0x02; // Trace_Error + public const int __TRACE_LEVEL_VERBOSE = 0x10; // Trace_Verbose + } +} \ No newline at end of file diff --git a/src/cs/NativeLogging/DisposableBase.cs b/src/cs/NativeLogging/DisposableBase.cs index 88d8431d..a30d7132 100644 --- a/src/cs/NativeLogging/DisposableBase.cs +++ b/src/cs/NativeLogging/DisposableBase.cs @@ -1,59 +1,60 @@ using System; using System.Threading; -namespace macaroni.interop; - -internal abstract class DisposableBase : IDisposable +namespace macaroni.interop { - private int isDisposed; - - /// - /// The base destructor - /// - ~DisposableBase() + internal abstract class DisposableBase : IDisposable { - this.Dispose(false); - } + private int isDisposed; - /// - /// Indicates whether this object has been disposed. - /// - public virtual bool IsDisposed - { - get + /// + /// The base destructor + /// + ~DisposableBase() { - return this.isDisposed == 1; + this.Dispose(false); } - } - /// - /// Disposes the current object. Safe to call multiple times. - /// - public void Dispose() - { - if (Interlocked.Exchange(ref this.isDisposed, 1) == 0) + /// + /// Indicates whether this object has been disposed. + /// + public virtual bool IsDisposed { - this.Dispose(true); - GC.SuppressFinalize(this); + get + { + return this.isDisposed == 1; + } } - } - /// - /// Method that actually disposes of resources. - /// - /// True if we should dispose both managed and native - /// resources, false if we should only dispose native resources - protected abstract void Dispose(bool disposeManaged); + /// + /// Disposes the current object. Safe to call multiple times. + /// + public void Dispose() + { + if (Interlocked.Exchange(ref this.isDisposed, 1) == 0) + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + } - /// - /// Throws an exception if the object has been disposed. - /// - /// If the object has been disposed - protected virtual void CheckDisposed() - { - if (this.IsDisposed) + /// + /// Method that actually disposes of resources. + /// + /// True if we should dispose both managed and native + /// resources, false if we should only dispose native resources + protected abstract void Dispose(bool disposeManaged); + + /// + /// Throws an exception if the object has been disposed. + /// + /// If the object has been disposed + protected virtual void CheckDisposed() { - throw new ObjectDisposedException(this.GetType().FullName); + if (this.IsDisposed) + { + throw new ObjectDisposedException(this.GetType().FullName); + } } } -} +} \ No newline at end of file diff --git a/src/cs/NativeLogging/MRDEBUG.cs b/src/cs/NativeLogging/MRDEBUG.cs index 50be9e10..7e9f1023 100644 --- a/src/cs/NativeLogging/MRDEBUG.cs +++ b/src/cs/NativeLogging/MRDEBUG.cs @@ -1,104 +1,104 @@ -using System.Globalization; using System.Runtime.CompilerServices; -namespace macaroni; - -public static class MR +namespace macaroni { - public static void TRACE_INFO(string message, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) - { - DiagnosticsInterop.diagnostics_log_trace_string(DiagnosticsInterop.__TRACE_LEVEL_INFO, "MR_TRACE_INFO:", message, file, line); - } - - public static void TRACE_WARNING(string message, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) - { - DiagnosticsInterop.diagnostics_log_trace_string(DiagnosticsInterop.__TRACE_LEVEL_WARNING, "MR_TRACE_WARNING:", message, file, line); - } - - public static void TRACE_ERROR(string message, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) - { - DiagnosticsInterop.diagnostics_log_trace_string(DiagnosticsInterop.__TRACE_LEVEL_ERROR, "MR_TRACE_ERROR:", message, file, line); - } - - public static void TRACE_VERBOSE(string message, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) - { - DiagnosticsInterop.diagnostics_log_trace_string(DiagnosticsInterop.__TRACE_LEVEL_VERBOSE, "MR_TRACE_VERBOSE:", message, file, line); - } - - public static void DBG_TRACE_INFO(string message, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) - { - DiagnosticsInterop.diagnostics_log_trace_string(DiagnosticsInterop.__TRACE_LEVEL_INFO, "MR_DBG_TRACE_INFO:", message, file, line); - System.Diagnostics.Debug.WriteLine($"MR_DBG_TRACE_INFO: {message}"); - } - - public static void DBG_TRACE_WARNING(string message, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) - { - DiagnosticsInterop.diagnostics_log_trace_string(DiagnosticsInterop.__TRACE_LEVEL_WARNING, "MR_DBG_TRACE_WARNING:", message, file, line); - System.Diagnostics.Debug.WriteLine($"MR_DBG_TRACE_WARNING: {message}"); - } - - public static void DBG_TRACE_ERROR(string message, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) - { - DiagnosticsInterop.diagnostics_log_trace_string(DiagnosticsInterop.__TRACE_LEVEL_ERROR, "MR_DBG_TRACE_ERROR:", message, file, line); - System.Diagnostics.Debug.WriteLine($"MR_DBG_TRACE_ERROR: {message}"); - } - - public static void DBG_TRACE_VERBOSE(string message, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) - { - DiagnosticsInterop.diagnostics_log_trace_string(DiagnosticsInterop.__TRACE_LEVEL_VERBOSE, "MR_DBG_TRACE_VERBOSE:", message, file, line); - System.Diagnostics.Debug.WriteLine($"MR_DBG_TRACE_VERBOSE: {message}"); - } - - public static void TRACE_INFO(string format, object[] args, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) - { - var message = string.Format(format, args); - TRACE_INFO(message, line, caller, file); - } - - private static void TRACE_WARNING(string format, object[] args, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) - { - var message = string.Format(format, args); - TRACE_WARNING(message, line, caller, file); - } - - private static void TRACE_ERROR(string format, object[] args, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) - { - var message = string.Format(format, args); - TRACE_ERROR(message, line, caller, file); - } - - private static void TRACE_VERBOSE(string format, object[] args, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) - { - var message = string.Format(format, args); - TRACE_VERBOSE(message, line, caller, file); - } - - public static void DBG_TRACE_INFO(string format, object[] args, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) - { - var message = string.Format(format, args); - DBG_TRACE_INFO(message, line, caller, file); - } - - private static void DBG_TRACE_WARNING(string format, object[] args, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) - { - var message = string.Format(format, args); - DBG_TRACE_WARNING(message, line, caller, file); - } - - private static void DBG_TRACE_ERROR(string format, object[] args, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) - { - var message = string.Format(format, args); - DBG_TRACE_ERROR(message, line, caller, file); - } - - private static void DBG_TRACE_VERBOSE(string format, object[] args, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) - { - var message = string.Format(format, args); - DBG_TRACE_VERBOSE(message, line, caller, file); - } - - private static object[] Args(params object[] args) - { - return args; - } -} + public static class MR + { + public static void TRACE_INFO(string message, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) + { + DiagnosticsInterop.diagnostics_log_trace_string(DiagnosticsInterop.__TRACE_LEVEL_INFO, "MR_TRACE_INFO:", message, file, line); + } + + public static void TRACE_WARNING(string message, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) + { + DiagnosticsInterop.diagnostics_log_trace_string(DiagnosticsInterop.__TRACE_LEVEL_WARNING, "MR_TRACE_WARNING:", message, file, line); + } + + public static void TRACE_ERROR(string message, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) + { + DiagnosticsInterop.diagnostics_log_trace_string(DiagnosticsInterop.__TRACE_LEVEL_ERROR, "MR_TRACE_ERROR:", message, file, line); + } + + public static void TRACE_VERBOSE(string message, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) + { + DiagnosticsInterop.diagnostics_log_trace_string(DiagnosticsInterop.__TRACE_LEVEL_VERBOSE, "MR_TRACE_VERBOSE:", message, file, line); + } + + public static void DBG_TRACE_INFO(string message, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) + { + DiagnosticsInterop.diagnostics_log_trace_string(DiagnosticsInterop.__TRACE_LEVEL_INFO, "MR_DBG_TRACE_INFO:", message, file, line); + System.Diagnostics.Debug.WriteLine($"MR_DBG_TRACE_INFO: {message}"); + } + + public static void DBG_TRACE_WARNING(string message, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) + { + DiagnosticsInterop.diagnostics_log_trace_string(DiagnosticsInterop.__TRACE_LEVEL_WARNING, "MR_DBG_TRACE_WARNING:", message, file, line); + System.Diagnostics.Debug.WriteLine($"MR_DBG_TRACE_WARNING: {message}"); + } + + public static void DBG_TRACE_ERROR(string message, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) + { + DiagnosticsInterop.diagnostics_log_trace_string(DiagnosticsInterop.__TRACE_LEVEL_ERROR, "MR_DBG_TRACE_ERROR:", message, file, line); + System.Diagnostics.Debug.WriteLine($"MR_DBG_TRACE_ERROR: {message}"); + } + + public static void DBG_TRACE_VERBOSE(string message, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) + { + DiagnosticsInterop.diagnostics_log_trace_string(DiagnosticsInterop.__TRACE_LEVEL_VERBOSE, "MR_DBG_TRACE_VERBOSE:", message, file, line); + System.Diagnostics.Debug.WriteLine($"MR_DBG_TRACE_VERBOSE: {message}"); + } + + public static void TRACE_INFO(string format, object[] args, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) + { + var message = string.Format(format, args); + TRACE_INFO(message, line, caller, file); + } + + private static void TRACE_WARNING(string format, object[] args, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) + { + var message = string.Format(format, args); + TRACE_WARNING(message, line, caller, file); + } + + private static void TRACE_ERROR(string format, object[] args, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) + { + var message = string.Format(format, args); + TRACE_ERROR(message, line, caller, file); + } + + private static void TRACE_VERBOSE(string format, object[] args, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) + { + var message = string.Format(format, args); + TRACE_VERBOSE(message, line, caller, file); + } + + public static void DBG_TRACE_INFO(string format, object[] args, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) + { + var message = string.Format(format, args); + DBG_TRACE_INFO(message, line, caller, file); + } + + private static void DBG_TRACE_WARNING(string format, object[] args, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) + { + var message = string.Format(format, args); + DBG_TRACE_WARNING(message, line, caller, file); + } + + private static void DBG_TRACE_ERROR(string format, object[] args, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) + { + var message = string.Format(format, args); + DBG_TRACE_ERROR(message, line, caller, file); + } + + private static void DBG_TRACE_VERBOSE(string format, object[] args, [CallerLineNumber] int line = 0, [CallerMemberName] string? caller = null, [CallerFilePath] string? file = null) + { + var message = string.Format(format, args); + DBG_TRACE_VERBOSE(message, line, caller, file); + } + + private static object[] Args(params object[] args) + { + return args; + } + } +} \ No newline at end of file diff --git a/src/cs/NativeLogging/NativeMemory.cs b/src/cs/NativeLogging/NativeMemory.cs index 54be388d..dd0b0a56 100644 --- a/src/cs/NativeLogging/NativeMemory.cs +++ b/src/cs/NativeLogging/NativeMemory.cs @@ -1,24 +1,26 @@ +using System; using System.Runtime.InteropServices; -namespace macaroni.interop; - -internal class NativeMemory : DisposableBase +namespace macaroni.interop { - public NativeMemory(IntPtr handle, int size) + internal class NativeMemory : DisposableBase { - Handle = handle; - Size = size; - } + public NativeMemory(IntPtr handle, int size) + { + Handle = handle; + Size = size; + } - public IntPtr Handle { get; } + public IntPtr Handle { get; } - public int Size { get; } + public int Size { get; } - protected override void Dispose(bool disposeManaged) - { - if (Handle != IntPtr.Zero) + protected override void Dispose(bool disposeManaged) { - Marshal.FreeHGlobal(Handle); + if (Handle != IntPtr.Zero) + { + Marshal.FreeHGlobal(Handle); + } } } -} +} \ No newline at end of file diff --git a/src/cs/NativeLogging/NativeUtils.cs b/src/cs/NativeLogging/NativeUtils.cs index 86ce978e..3ac7ccd7 100644 --- a/src/cs/NativeLogging/NativeUtils.cs +++ b/src/cs/NativeLogging/NativeUtils.cs @@ -1,35 +1,37 @@ +using System; using System.Runtime.InteropServices; using System.Text; -namespace macaroni.interop; - -internal static class NativeUtils +namespace macaroni.interop { - public static NativeMemory ToNativeNullTerminatedUtf8String(string? str) + internal static class NativeUtils { - if (str == null) + public static NativeMemory ToNativeNullTerminatedUtf8String(string? str) { - return new NativeMemory(IntPtr.Zero, 0); - } + if (str == null) + { + return new NativeMemory(IntPtr.Zero, 0); + } - var utf8Bytes = Encoding.UTF8.GetBytes(str); - var utf8LengthWithTerminator = utf8Bytes.Length + 1; - var nativeHandle = IntPtr.Zero; + var utf8Bytes = Encoding.UTF8.GetBytes(str); + var utf8LengthWithTerminator = utf8Bytes.Length + 1; + var nativeHandle = IntPtr.Zero; - try - { - nativeHandle = Marshal.AllocHGlobal(utf8LengthWithTerminator); - Marshal.Copy(utf8Bytes, 0, nativeHandle, utf8LengthWithTerminator - 1); - Marshal.WriteByte(nativeHandle, utf8LengthWithTerminator - 1, 0); - return new NativeMemory(nativeHandle, utf8LengthWithTerminator); - } - catch - { - if (nativeHandle != IntPtr.Zero) + try + { + nativeHandle = Marshal.AllocHGlobal(utf8LengthWithTerminator); + Marshal.Copy(utf8Bytes, 0, nativeHandle, utf8LengthWithTerminator - 1); + Marshal.WriteByte(nativeHandle, utf8LengthWithTerminator - 1, 0); + return new NativeMemory(nativeHandle, utf8LengthWithTerminator); + } + catch { - Marshal.FreeHGlobal(nativeHandle); + if (nativeHandle != IntPtr.Zero) + { + Marshal.FreeHGlobal(nativeHandle); + } + throw; } - throw; } } -} +} \ No newline at end of file diff --git a/src/cs/NativeLogging/SpeechNativeMethods.cs b/src/cs/NativeLogging/SpeechNativeMethods.cs index 91a5d843..31a7689d 100644 --- a/src/cs/NativeLogging/SpeechNativeMethods.cs +++ b/src/cs/NativeLogging/SpeechNativeMethods.cs @@ -1,54 +1,55 @@ using System; using System.Runtime.InteropServices; -namespace macaroni.interop; - -[UnmanagedFunctionPointer(CallingConvention.Cdecl)] -internal delegate void LogMessageCallbackFunctionDelegate(IntPtr nativeUtf8); - -/// -/// Cognitive Speech SDK native methods -/// -internal static class SpeechNativeMethods +namespace macaroni.interop { - public const string IOS_NativeDllName = "__Internal"; - public const CallingConvention IOS_NativeCallConvention = CallingConvention.Cdecl; + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate void LogMessageCallbackFunctionDelegate(IntPtr nativeUtf8); + + /// + /// Cognitive Speech SDK native methods + /// + internal static class SpeechNativeMethods + { + public const string IOS_NativeDllName = "__Internal"; + public const CallingConvention IOS_NativeCallConvention = CallingConvention.Cdecl; - public const string OSX_NativeDllName = "libMicrosoft.CognitiveServices.Speech.core.dylib"; - public const CallingConvention OSX_NativeCallConvention = CallingConvention.Cdecl; + public const string OSX_NativeDllName = "libMicrosoft.CognitiveServices.Speech.core.dylib"; + public const CallingConvention OSX_NativeCallConvention = CallingConvention.Cdecl; - public const string UNIX_NativeDllName = "libMicrosoft.CognitiveServices.Speech.core.so"; - public const CallingConvention UNIX_NativeCallConvention = CallingConvention.Cdecl; + public const string UNIX_NativeDllName = "libMicrosoft.CognitiveServices.Speech.core.so"; + public const CallingConvention UNIX_NativeCallConvention = CallingConvention.Cdecl; - public const string Android_NativeDllName = "libMicrosoft.CognitiveServices.Speech.core.so"; - public const CallingConvention Android_NativeCallConvention = CallingConvention.Cdecl; + public const string Android_NativeDllName = "libMicrosoft.CognitiveServices.Speech.core.so"; + public const CallingConvention Android_NativeCallConvention = CallingConvention.Cdecl; - public const string Windows_NativeDllName = "Microsoft.CognitiveServices.Speech.core.dll"; - public const CallingConvention Windows_NativeCallConvention = CallingConvention.StdCall; + public const string Windows_NativeDllName = "Microsoft.CognitiveServices.Speech.core.dll"; + public const CallingConvention Windows_NativeCallConvention = CallingConvention.StdCall; - #if IOS +#if IOS public const string NativeDllName = "__Internal"; public const CallingConvention NativeCallConvention = CallingConvention.Cdecl; - #elif OSX +#elif OSX public const string NativeDllName = "libMicrosoft.CognitiveServices.Speech.core.dylib"; public const CallingConvention NativeCallConvention = CallingConvention.Cdecl; - #elif UNIX +#elif UNIX public const string NativeDllName = "libMicrosoft.CognitiveServices.Speech.core.so"; public const CallingConvention NativeCallConvention = CallingConvention.Cdecl; - #elif Android +#elif Android public const string NativeDllName = "libMicrosoft.CognitiveServices.Speech.core.so"; public const CallingConvention NativeCallConvention = CallingConvention.Cdecl; - #else +#else public const string NativeDllName = "Microsoft.CognitiveServices.Speech.core.dll"; public const CallingConvention NativeCallConvention = CallingConvention.StdCall; - #endif +#endif - [DllImport(NativeDllName, CallingConvention = NativeCallConvention)] - public static extern void diagnostics_log_trace_string(int level, IntPtr title, IntPtr fileName, int lineNumber, IntPtr message); + [DllImport(NativeDllName, CallingConvention = NativeCallConvention)] + public static extern void diagnostics_log_trace_string(int level, IntPtr title, IntPtr fileName, int lineNumber, IntPtr message); - [DllImport(Android_NativeDllName, CallingConvention = Android_NativeCallConvention, EntryPoint = "diagnostics_log_trace_string")] - public static extern void android_diagnostics_log_trace_string(int level, IntPtr title, IntPtr fileName, int lineNumber, IntPtr message); + [DllImport(Android_NativeDllName, CallingConvention = Android_NativeCallConvention, EntryPoint = "diagnostics_log_trace_string")] + public static extern void android_diagnostics_log_trace_string(int level, IntPtr title, IntPtr fileName, int lineNumber, IntPtr message); - [DllImport(UNIX_NativeDllName, CallingConvention = UNIX_NativeCallConvention, EntryPoint = "diagnostics_log_trace_string")] - public static extern void unix_diagnostics_log_trace_string(int level, IntPtr title, IntPtr fileName, int lineNumber, IntPtr message); -} + [DllImport(UNIX_NativeDllName, CallingConvention = UNIX_NativeCallConvention, EntryPoint = "diagnostics_log_trace_string")] + public static extern void unix_diagnostics_log_trace_string(int level, IntPtr title, IntPtr fileName, int lineNumber, IntPtr message); + } +} \ No newline at end of file diff --git a/src/cs/NativeLogging/VisionNativeMethods.cs b/src/cs/NativeLogging/VisionNativeMethods.cs index 93fc3920..74e1b05c 100644 --- a/src/cs/NativeLogging/VisionNativeMethods.cs +++ b/src/cs/NativeLogging/VisionNativeMethods.cs @@ -1,27 +1,28 @@ using System; using System.Runtime.InteropServices; -namespace macaroni.interop; - -internal static class VisionNativeMethods +namespace macaroni.interop { - #if IOS + internal static class VisionNativeMethods + { +#if IOS public const string NativeDllName = "__Internal"; public const CallingConvention NativeCallConvention = CallingConvention.Cdecl; - #elif OSX +#elif OSX public const string NativeDllName = "libAzure-AI-Vision-Core.dylib"; public const CallingConvention NativeCallConvention = CallingConvention.Cdecl; - #elif UNIX +#elif UNIX public const string NativeDllName = "libAzure-AI-Vision-Core.so"; public const CallingConvention NativeCallConvention = CallingConvention.Cdecl; - #elif Android +#elif Android public const string NativeDllName = "libAzure-AI-Vision-Core.so"; public const CallingConvention NativeCallConvention = CallingConvention.Cdecl; - #else +#else public const string NativeDllName = "Azure-AI-Vision-Core.dll"; public const CallingConvention NativeCallConvention = CallingConvention.StdCall; - #endif +#endif - [DllImport(NativeDllName, CallingConvention = NativeCallConvention)] - public static extern void diagnostics_log_trace_string(int level, IntPtr title, IntPtr fileName, int lineNumber, IntPtr message); -} + [DllImport(NativeDllName, CallingConvention = NativeCallConvention)] + public static extern void diagnostics_log_trace_string(int level, IntPtr title, IntPtr fileName, int lineNumber, IntPtr message); + } +} \ No newline at end of file diff --git a/src/cs/Nuggets/Nugget.cs b/src/cs/Nuggets/Nugget.cs index 40c7a110..6cac9e72 100644 --- a/src/cs/Nuggets/Nugget.cs +++ b/src/cs/Nuggets/Nugget.cs @@ -1,31 +1,36 @@ -namespace macaroni; +using System.Collections.Generic; +using System.Linq; +using YamlDotNet.RepresentationModel; -internal class Nugget : INugget, ILoadedFromYamlFile +namespace macaroni { - public string? Name { get; internal set; } - public string? Description { get; internal set; } + internal class Nugget : INugget, ILoadedFromYamlFile + { + public string? Name { get; internal set; } + public string? Description { get; internal set; } - public IEnumerable? Parameters { get; internal set; } - public IEnumerable? Instructions { get; internal set; } - public IEnumerable? Examples { get; internal set; } + public IEnumerable? Parameters { get; internal set; } + public IEnumerable? Instructions { get; internal set; } + public IEnumerable? Examples { get; internal set; } - public IExecutorCollection? Executors { get; internal set; } - public IEnumerable? Outputs { get; internal set; } + public IExecutorCollection? Executors { get; internal set; } + public IEnumerable? Outputs { get; internal set; } - public YamlNode? Yaml { get; internal set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } + public YamlNode? Yaml { get; internal set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public void LoadComplete(object parent) - { - YamlParent = parent; - Examples?.ToList().ForEach(x => (x as ILoadedFromYamlFile)?.LoadComplete(this)); - (Executors as ILoadedFromYamlFile)?.LoadComplete(this); - } + public void LoadComplete(object parent) + { + YamlParent = parent; + Examples?.ToList().ForEach(x => (x as ILoadedFromYamlFile)?.LoadComplete(this)); + (Executors as ILoadedFromYamlFile)?.LoadComplete(this); + } - public void Unload() - { - Examples?.ToList().ForEach(x => (x as ILoadedFromYamlFile)?.Unload()); - (Executors as ILoadedFromYamlFile)?.Unload(); + public void Unload() + { + Examples?.ToList().ForEach(x => (x as ILoadedFromYamlFile)?.Unload()); + (Executors as ILoadedFromYamlFile)?.Unload(); + } } -} +} \ No newline at end of file diff --git a/src/cs/Nuggets/NuggetCollection.cs b/src/cs/Nuggets/NuggetCollection.cs index 4c6b9752..709239e5 100644 --- a/src/cs/Nuggets/NuggetCollection.cs +++ b/src/cs/Nuggets/NuggetCollection.cs @@ -1,27 +1,30 @@ -namespace macaroni; +using System.Collections.Generic; +using YamlDotNet.RepresentationModel; -internal class NuggetCollection : List, INuggetCollection, ILoadedFromYamlFile +namespace macaroni { - public NuggetCollection(IEnumerable nuggets) : base(nuggets) + internal class NuggetCollection : List, INuggetCollection, ILoadedFromYamlFile { - } + public NuggetCollection(IEnumerable nuggets) : base(nuggets) + { + } - public YamlNode? Yaml { get; internal set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } - - public void LoadComplete(object parent) - { - YamlParent = parent; - if (Yaml == null) Yaml = (parent as ILoadedFromYamlFile)?.Yaml; - if (YamlFile == null) YamlFile = (parent as ILoadedFromYamlFile)?.YamlFile; + public YamlNode? Yaml { get; internal set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - this.ForEach(x => (x as ILoadedFromYamlFile)?.LoadComplete(this)); - } + public void LoadComplete(object parent) + { + YamlParent = parent; + if (Yaml == null) Yaml = (parent as ILoadedFromYamlFile)?.Yaml; + if (YamlFile == null) YamlFile = (parent as ILoadedFromYamlFile)?.YamlFile; - public void Unload() - { - this.ForEach(x => (x as ILoadedFromYamlFile)?.Unload()); - } -} + this.ForEach(x => (x as ILoadedFromYamlFile)?.LoadComplete(this)); + } + public void Unload() + { + this.ForEach(x => (x as ILoadedFromYamlFile)?.Unload()); + } + } +} \ No newline at end of file diff --git a/src/cs/Nuggets/NuggetCollectionYamlParser.cs b/src/cs/Nuggets/NuggetCollectionYamlParser.cs index 91181314..4e9db75b 100644 --- a/src/cs/Nuggets/NuggetCollectionYamlParser.cs +++ b/src/cs/Nuggets/NuggetCollectionYamlParser.cs @@ -1,195 +1,200 @@ -namespace macaroni; +using System.Collections.Generic; +using System.Linq; +using YamlDotNet.RepresentationModel; -internal class NuggetCollectionYamlParser : YamlParserBase, INuggetCollectionYamlParser +namespace macaroni { - public NuggetCollectionYamlParser(IExecutorCollectionYamlParser executorsParser, ISystemContext context) : base(context) + internal class NuggetCollectionYamlParser : YamlParserBase, INuggetCollectionYamlParser { - _executorsParser = executorsParser; - } - - public INuggetCollection? CheckForNuggets(string file, YamlMappingNode mapping, string nuggetsMappingName = "nuggets") - { - var sequence = mapping.Children.ContainsKey(nuggetsMappingName) - ? mapping.Children[nuggetsMappingName] as YamlSequenceNode - : null; - return sequence != null - ? NuggetsFromSequence(file, sequence) - : null; - } - - public INuggetCollection NuggetsFromSequence(string file, YamlSequenceNode sequence) - { - var nuggets = RequireSequenceOf(file, sequence, - "nugget", - (file, node) => NuggetFromYamlNode(file, node), - (file, node) => ErrorUnexpectedNode(file, node, "{nugget sequence}")); - - return new NuggetCollection(nuggets); - } - - private INugget NuggetFromYamlNode(string file, YamlNode node) - { - var mapping = node as YamlMappingNode; - if (mapping != null) + public NuggetCollectionYamlParser(IExecutorCollectionYamlParser executorsParser, ISystemContext context) : base(context) { - var nugget = CheckForNugget(file, mapping); - if (nugget != null) return nugget; + _executorsParser = executorsParser; } - var message = $"Unexpected node type ({node.GetType().Name})"; - var expected = "EXPECTED: {a nugget, e.g. `name: {string}` AND `description: {string}}"; - throw ErrorParsingYamlException(file, node.Start.Line, node.Start.Column, message, expected); - } - - private INugget? CheckForNugget(string file, YamlMappingNode mapping) - { - var name = mapping.Children.ContainsKey("name"); - var description = mapping.Children.ContainsKey("description"); - var instructions = mapping.Children.ContainsKey("instructions"); - var parameters = mapping.Children.ContainsKey("parameters"); - var outputs = mapping.Children.ContainsKey("outputs") || mapping.Children.ContainsKey("output"); - - return name && (description || instructions || parameters || outputs) - ? NuggetFromYamlMapping(file, mapping) - : null; - } - - private INugget NuggetFromYamlMapping(string file, YamlMappingNode mapping) - { - var Kind = "nugget"; - - var invalid = mapping.Children.Where(x => IsInvalidNuggetChildNodeMappingKey(x.Key)); - if (invalid.Count() > 0) + public INuggetCollection? CheckForNuggets(string file, YamlMappingNode mapping, string nuggetsMappingName = "nuggets") { - var first = invalid.First(); - var key = (first.Key as YamlScalarNode)?.Value ?? first.Key.ToString(); - var expected = GetValidNuggetChildrenTypes(); - var message = - $" FOUND: {key}\n" + - $"EXPECTED: {expected}"; - throw ErrorParsingYamlException(file, first.Key.Start.Line, first.Key.Start.Column, "Unexpected node mapping", message); + var sequence = mapping.Children.ContainsKey(nuggetsMappingName) + ? mapping.Children[nuggetsMappingName] as YamlSequenceNode + : null; + return sequence != null + ? NuggetsFromSequence(file, sequence) + : null; } - var name = RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "name", null); // TODO: Should nuggets do warnings? - var description = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "description", null); // TODO: Should nuggets do warnings? - - var parameters = GetScalarStrings(file, mapping, "parameters", null); // TODO: Should nuggets do warnings? - var instructions = GetScalarStrings(file, mapping, "instructions", null); // TODO: Should nuggets do warnings? - - var example = CheckForNuggetExamples(file, mapping, "example"); - var examples = CheckForNuggetExamples(file, mapping, "examples") ?? example; - - var executors = _executorsParser.CheckForExecutors(file, mapping, "execute", null); // TODO: Warnings object? - var outputs = GetScalarStrings(file, mapping, "outputs", null) ?? GetScalarStrings(file, mapping, "output", null); - - return new Nugget() + public INuggetCollection NuggetsFromSequence(string file, YamlSequenceNode sequence) { - Name = name, - Description = description, - Parameters = parameters, - Instructions = instructions, - Examples = examples, - Executors = executors, - Outputs = outputs, - - Yaml = mapping, - YamlFile = file - }; - } + var nuggets = RequireSequenceOf(file, sequence, + "nugget", + (file, node) => NuggetFromYamlNode(file, node), + (file, node) => ErrorUnexpectedNode(file, node, "{nugget sequence}")); - private static string GetValidNuggetChildrenTypes() - { - return string.Join(", ", _validNuggetNodeMappingKeys); - } + return new NuggetCollection(nuggets); + } - private bool IsInvalidNuggetChildNodeMappingKey(YamlNode child) - { - var key = (child as YamlScalarNode)?.Value; - return string.IsNullOrEmpty(key) || !_validNuggetNodeMappingKeys.Contains(key); - } + private INugget NuggetFromYamlNode(string file, YamlNode node) + { + var mapping = node as YamlMappingNode; + if (mapping != null) + { + var nugget = CheckForNugget(file, mapping); + if (nugget != null) return nugget; + } + + var message = $"Unexpected node type ({node.GetType().Name})"; + var expected = "EXPECTED: {a nugget, e.g. `name: {string}` AND `description: {string}}"; + throw ErrorParsingYamlException(file, node.Start.Line, node.Start.Column, message, expected); + } - private IEnumerable? CheckForNuggetExamples(string file, YamlMappingNode mapping, string nuggetExampleMappingName = "examples") - { - var sequence = mapping.Children.ContainsKey(nuggetExampleMappingName) - ? mapping.Children[nuggetExampleMappingName] as YamlSequenceNode - : null; - return sequence != null - ? NuggetExamplesFromSequence(file, sequence) - : null; - } + private INugget? CheckForNugget(string file, YamlMappingNode mapping) + { + var name = mapping.Children.ContainsKey("name"); + var description = mapping.Children.ContainsKey("description"); + var instructions = mapping.Children.ContainsKey("instructions"); + var parameters = mapping.Children.ContainsKey("parameters"); + var outputs = mapping.Children.ContainsKey("outputs") || mapping.Children.ContainsKey("output"); + + return name && (description || instructions || parameters || outputs) + ? NuggetFromYamlMapping(file, mapping) + : null; + } - private IEnumerable NuggetExamplesFromSequence(string file, YamlSequenceNode sequence) - { - var examples = RequireSequenceOf(file, sequence, - "example", - (file, node) => NuggetExampleFromYamlNode(file, node), - (file, node) => ErrorUnexpectedNode(file, node, "{nugget example sequence}")); + private INugget NuggetFromYamlMapping(string file, YamlMappingNode mapping) + { + var Kind = "nugget"; + + var invalid = mapping.Children.Where(x => IsInvalidNuggetChildNodeMappingKey(x.Key)); + if (invalid.Count() > 0) + { + var first = invalid.First(); + var key = (first.Key as YamlScalarNode)?.Value ?? first.Key.ToString(); + var expected = GetValidNuggetChildrenTypes(); + var message = + $" FOUND: {key}\n" + + $"EXPECTED: {expected}"; + throw ErrorParsingYamlException(file, first.Key.Start.Line, first.Key.Start.Column, "Unexpected node mapping", message); + } + + var name = RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "name", null); // TODO: Should nuggets do warnings? + var description = RequireMappingStringValueNotNullOrEmptyIfPresent(file, Kind, mapping, "description", null); // TODO: Should nuggets do warnings? + + var parameters = GetScalarStrings(file, mapping, "parameters", null); // TODO: Should nuggets do warnings? + var instructions = GetScalarStrings(file, mapping, "instructions", null); // TODO: Should nuggets do warnings? + + var example = CheckForNuggetExamples(file, mapping, "example"); + var examples = CheckForNuggetExamples(file, mapping, "examples") ?? example; + + var executors = _executorsParser.CheckForExecutors(file, mapping, "execute", null); // TODO: Warnings object? + var outputs = GetScalarStrings(file, mapping, "outputs", null) ?? GetScalarStrings(file, mapping, "output", null); + + return new Nugget() + { + Name = name, + Description = description, + Parameters = parameters, + Instructions = instructions, + Examples = examples, + Executors = executors, + Outputs = outputs, + + Yaml = mapping, + YamlFile = file + }; + } - return new List(examples); - } + private static string GetValidNuggetChildrenTypes() + { + return string.Join(", ", _validNuggetNodeMappingKeys); + } - private INuggetExample NuggetExampleFromYamlNode(string file, YamlNode node) - { - var mapping = node as YamlMappingNode; - if (mapping != null) + private bool IsInvalidNuggetChildNodeMappingKey(YamlNode child) { - var example = CheckForNuggetExample(file, mapping); - if (example != null) return example; + var key = (child as YamlScalarNode)?.Value; + return string.IsNullOrEmpty(key) || !_validNuggetNodeMappingKeys.Contains(key); } - var message = $"Unexpected node type ({node.GetType().Name})"; - var expected = "EXPECTED: {a nugget example, e.g. `user: {string}` AND `assistant: {string}}"; - throw ErrorParsingYamlException(file, node.Start.Line, node.Start.Column, message, expected); - } + private IEnumerable? CheckForNuggetExamples(string file, YamlMappingNode mapping, string nuggetExampleMappingName = "examples") + { + var sequence = mapping.Children.ContainsKey(nuggetExampleMappingName) + ? mapping.Children[nuggetExampleMappingName] as YamlSequenceNode + : null; + return sequence != null + ? NuggetExamplesFromSequence(file, sequence) + : null; + } - private INuggetExample? CheckForNuggetExample(string file, YamlMappingNode mapping) - { - return mapping.Children.ContainsKey("user") && mapping.Children.ContainsKey("assistant") - ? NuggetExampleFromYamlMapping(file, mapping) - : null; - } + private IEnumerable NuggetExamplesFromSequence(string file, YamlSequenceNode sequence) + { + var examples = RequireSequenceOf(file, sequence, + "example", + (file, node) => NuggetExampleFromYamlNode(file, node), + (file, node) => ErrorUnexpectedNode(file, node, "{nugget example sequence}")); - private INuggetExample NuggetExampleFromYamlMapping(string file, YamlMappingNode mapping) - { - var Kind = "example"; + return new List(examples); + } - var invalid = mapping.Children.Where(x => IsInvalidNuggetExampleChildNodeMappingKey(x.Key)); - if (invalid.Count() > 0) + private INuggetExample NuggetExampleFromYamlNode(string file, YamlNode node) { - var first = invalid.First(); - var key = (first.Key as YamlScalarNode)?.Value ?? first.Key.ToString(); - var expected = GetValidNuggetExampleChildrenTypes(); - var message = - $" FOUND: {key}\n" + - $"EXPECTED: {expected}"; - throw ErrorParsingYamlException(file, first.Key.Start.Line, first.Key.Start.Column, "Unexpected node mapping", message); + var mapping = node as YamlMappingNode; + if (mapping != null) + { + var example = CheckForNuggetExample(file, mapping); + if (example != null) return example; + } + + var message = $"Unexpected node type ({node.GetType().Name})"; + var expected = "EXPECTED: {a nugget example, e.g. `user: {string}` AND `assistant: {string}}"; + throw ErrorParsingYamlException(file, node.Start.Line, node.Start.Column, message, expected); } - var user = RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "user", null); - var assistant = RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "assistant", null); + private INuggetExample? CheckForNuggetExample(string file, YamlMappingNode mapping) + { + return mapping.Children.ContainsKey("user") && mapping.Children.ContainsKey("assistant") + ? NuggetExampleFromYamlMapping(file, mapping) + : null; + } - return new NuggetExample() + private INuggetExample NuggetExampleFromYamlMapping(string file, YamlMappingNode mapping) { - User = user, - Assistant = assistant, + var Kind = "example"; + + var invalid = mapping.Children.Where(x => IsInvalidNuggetExampleChildNodeMappingKey(x.Key)); + if (invalid.Count() > 0) + { + var first = invalid.First(); + var key = (first.Key as YamlScalarNode)?.Value ?? first.Key.ToString(); + var expected = GetValidNuggetExampleChildrenTypes(); + var message = + $" FOUND: {key}\n" + + $"EXPECTED: {expected}"; + throw ErrorParsingYamlException(file, first.Key.Start.Line, first.Key.Start.Column, "Unexpected node mapping", message); + } + + var user = RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "user", null); + var assistant = RequireMappingStringValueNotNullOrEmpty(file, Kind, mapping, "assistant", null); + + return new NuggetExample() + { + User = user, + Assistant = assistant, + + Yaml = mapping, + YamlFile = file + }; + } - Yaml = mapping, - YamlFile = file - }; - } + private static string GetValidNuggetExampleChildrenTypes() + { + return string.Join(", ", _validNuggetExampleNodeMappingKeys); + } - private static string GetValidNuggetExampleChildrenTypes() - { - return string.Join(", ", _validNuggetExampleNodeMappingKeys); - } + private bool IsInvalidNuggetExampleChildNodeMappingKey(YamlNode child) + { + var key = (child as YamlScalarNode)?.Value; + return string.IsNullOrEmpty(key) || !_validNuggetExampleNodeMappingKeys.Contains(key); + } - private bool IsInvalidNuggetExampleChildNodeMappingKey(YamlNode child) - { - var key = (child as YamlScalarNode)?.Value; - return string.IsNullOrEmpty(key) || !_validNuggetExampleNodeMappingKeys.Contains(key); + private IExecutorCollectionYamlParser _executorsParser; + private static IEnumerable _validNuggetNodeMappingKeys = new string[] { "name", "description", "parameters", "instructions", "example", "examples", "execute", "output", "outputs" }; + private static IEnumerable _validNuggetExampleNodeMappingKeys = new string[] { "user", "assistant" }; } - - private IExecutorCollectionYamlParser _executorsParser; - private static IEnumerable _validNuggetNodeMappingKeys = new string[] { "name", "description", "parameters", "instructions", "example", "examples", "execute", "output", "outputs" }; - private static IEnumerable _validNuggetExampleNodeMappingKeys = new string[] { "user", "assistant" }; } \ No newline at end of file diff --git a/src/cs/Nuggets/NuggetExample.cs b/src/cs/Nuggets/NuggetExample.cs index 0a3f0f04..d597989d 100644 --- a/src/cs/Nuggets/NuggetExample.cs +++ b/src/cs/Nuggets/NuggetExample.cs @@ -1,22 +1,25 @@ -namespace macaroni; +using YamlDotNet.RepresentationModel; -internal class NuggetExample : INuggetExample, ILoadedFromYamlFile +namespace macaroni { - - public string? User { get; internal set; } - public string? Assistant { get; internal set; } + internal class NuggetExample : INuggetExample, ILoadedFromYamlFile + { - public YamlNode? Yaml { get; internal set; } - public string? YamlFile { get; internal set; } - public object? YamlParent { get; internal set; } + public string? User { get; internal set; } + public string? Assistant { get; internal set; } + public YamlNode? Yaml { get; internal set; } + public string? YamlFile { get; internal set; } + public object? YamlParent { get; internal set; } - public void LoadComplete(object parent) - { - YamlParent = parent; - } - public void Unload() - { + public void LoadComplete(object parent) + { + YamlParent = parent; + } + + public void Unload() + { + } } -} +} \ No newline at end of file diff --git a/src/cs/ScriptExecution/ScriptExecutionAndroidObjectModel.cs b/src/cs/ScriptExecution/ScriptExecutionAndroidObjectModel.cs index 45a602ab..125734e1 100644 --- a/src/cs/ScriptExecution/ScriptExecutionAndroidObjectModel.cs +++ b/src/cs/ScriptExecution/ScriptExecutionAndroidObjectModel.cs @@ -1,34 +1,54 @@ -using Microsoft.CognitiveServices.Speech; -using Microsoft.CognitiveServices.Speech.Audio; +using System; +using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; +/* Unmerged change from project 'macaroni_core (net6.0-windows)' +Before: using System.Diagnostics; using System.Text; using Newtonsoft.Json; +After: +using Newtonsoft.Json; +using System.Diagnostics; +using System.Text; +*/ + +/* Unmerged change from project 'macaroni_core (netstandard2.1)' +Before: +using System.Diagnostics; +using System.Text; +using Newtonsoft.Json; +After: +using Newtonsoft.Json; +using System.Diagnostics; +using System.Text; +*/ -namespace macaroni; -internal class ScriptExecutionAndroidObjectModel +namespace macaroni { - public ScriptExecutionAndroidObjectModel(IServiceProvider serviceProvider) + internal class ScriptExecutionAndroidObjectModel { - _serviceProvider = serviceProvider; - } + public ScriptExecutionAndroidObjectModel(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } - public void startActivity(string action) - { - startActivity(action, null, null); - } + public void startActivity(string action) + { + startActivity(action, null, null); + } - public void startActivity(string action, string uri) - { - startActivity(action, uri, null); - } + public void startActivity(string action, string uri) + { + startActivity(action, uri, null); + } - public void startActivity(string action, string? uri, IDictionary? extras) - { - var service = _serviceProvider.GetRequiredService(); - service.StartActivity(action, uri, extras); - } + public void startActivity(string action, string? uri, IDictionary? extras) + { + var service = _serviceProvider.GetRequiredService(); + service.StartActivity(action, uri, extras); + } - private readonly IServiceProvider _serviceProvider; -} + private readonly IServiceProvider _serviceProvider; + } +} \ No newline at end of file diff --git a/src/cs/ScriptExecution/ScriptExecutionClipboardObjectModel.cs b/src/cs/ScriptExecution/ScriptExecutionClipboardObjectModel.cs index 29787d99..953c74a7 100644 --- a/src/cs/ScriptExecution/ScriptExecutionClipboardObjectModel.cs +++ b/src/cs/ScriptExecution/ScriptExecutionClipboardObjectModel.cs @@ -1,30 +1,49 @@ -using Microsoft.CognitiveServices.Speech; -using Microsoft.CognitiveServices.Speech.Audio; +using System; using Microsoft.Extensions.DependencyInjection; +/* Unmerged change from project 'macaroni_core (net6.0-windows)' +Before: using System.Diagnostics; using System.Text; using Newtonsoft.Json; +After: +using Newtonsoft.Json; +using System.Diagnostics; +using System.Text; +*/ + +/* Unmerged change from project 'macaroni_core (netstandard2.1)' +Before: +using System.Diagnostics; +using System.Text; +using Newtonsoft.Json; +After: +using Newtonsoft.Json; +using System.Diagnostics; +using System.Text; +*/ -namespace macaroni; -internal class ScriptExecutionClipboardObjectModel +namespace macaroni { - public ScriptExecutionClipboardObjectModel(IServiceProvider serviceProvider) + internal class ScriptExecutionClipboardObjectModel { - _serviceProvider = serviceProvider; - } + public ScriptExecutionClipboardObjectModel(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } - public string? getText() - { - var clipboard = _serviceProvider.GetRequiredService(); - return clipboard.GetText(); - } + public string? getText() + { + var clipboard = _serviceProvider.GetRequiredService(); + return clipboard.GetText(); + } - public void setText(string text) - { - var clipboard = _serviceProvider.GetRequiredService(); - clipboard.Set(text, null); - } + public void setText(string text) + { + var clipboard = _serviceProvider.GetRequiredService(); + clipboard.Set(text, null); + } - private readonly IServiceProvider _serviceProvider; -} + private readonly IServiceProvider _serviceProvider; + } +} \ No newline at end of file diff --git a/src/cs/ScriptExecution/ScriptExecutionGlobalStateObjectModel.cs b/src/cs/ScriptExecution/ScriptExecutionGlobalStateObjectModel.cs index c5757eea..4c7b1b25 100644 --- a/src/cs/ScriptExecution/ScriptExecutionGlobalStateObjectModel.cs +++ b/src/cs/ScriptExecution/ScriptExecutionGlobalStateObjectModel.cs @@ -1,26 +1,27 @@ -namespace macaroni; - -internal class ScriptExecutionGlobalStateObjectModel +namespace macaroni { - public ScriptExecutionGlobalStateObjectModel(IGlobalNamedStateService namedStateService) + internal class ScriptExecutionGlobalStateObjectModel { - _namedStateService = namedStateService; - } + public ScriptExecutionGlobalStateObjectModel(IGlobalNamedStateService namedStateService) + { + _namedStateService = namedStateService; + } - public string? get(string name) - { - return _namedStateService.GetNamedState(name); - } + public string? get(string name) + { + return _namedStateService.GetNamedState(name); + } - public void set(string name, string? value) - { - _namedStateService.SetNamedState(name, value); - } + public void set(string name, string? value) + { + _namedStateService.SetNamedState(name, value); + } - public bool has(string name) - { - return _namedStateService.GetNamedState(name) != null; - } + public bool has(string name) + { + return _namedStateService.GetNamedState(name) != null; + } - private IGlobalNamedStateService _namedStateService; -} + private IGlobalNamedStateService _namedStateService; + } +} \ No newline at end of file diff --git a/src/cs/ScriptExecution/ScriptExecutionHostObjectModel.cs b/src/cs/ScriptExecution/ScriptExecutionHostObjectModel.cs index 7ccc5d06..690eb4f2 100644 --- a/src/cs/ScriptExecution/ScriptExecutionHostObjectModel.cs +++ b/src/cs/ScriptExecution/ScriptExecutionHostObjectModel.cs @@ -1,586 +1,586 @@ -using Microsoft.CognitiveServices.Speech; -using Microsoft.CognitiveServices.Speech.Audio; +using System; +using System.IO; +using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; -using System.Diagnostics; -using System.Text; -using Newtonsoft.Json; -using System.Collections.Generic; -namespace macaroni; -internal class ScriptExecutionHostObjectModel +namespace macaroni { - public ScriptExecutionHostObjectModel(IServiceProvider serviceProvider, IExecutionContext context) + internal class ScriptExecutionHostObjectModel { - _serviceProvider = serviceProvider; - _context = context; - } + public ScriptExecutionHostObjectModel(IServiceProvider serviceProvider, IExecutionContext context) + { + _serviceProvider = serviceProvider; + _context = context; + } - public string? get(string name) - { - return _context.Get(name, null) as string; - } + public string? get(string name) + { + return _context.Get(name, null) as string; + } - public void set(string name, string? value) - { - set(name, value, false); - } + public void set(string name, string? value) + { + set(name, value, false); + } - public void set(string name, string? value, bool pinned) - { - var kind = pinned ? SetValueKind.OverrideAllResolvers : SetValueKind.InterleavedWithResolvers; - _context.Set(name, value ?? "", kind); - } + public void set(string name, string? value, bool pinned) + { + var kind = pinned ? SetValueKind.OverrideAllResolvers : SetValueKind.InterleavedWithResolvers; + _context.Set(name, value ?? "", kind); + } - public bool has(string name) - { - return _context.Get(name, null) != null; - } + public bool has(string name) + { + return _context.Get(name, null) != null; + } - public string? resolve(string text) - { - return _context.Resolve(text, false); - } + public string? resolve(string text) + { + return _context.Resolve(text, false); + } - public string? resolve(string text, bool deleteUnresolved) - { - return _context.Resolve(text, deleteUnresolved); - } + public string? resolve(string text, bool deleteUnresolved) + { + return _context.Resolve(text, deleteUnresolved); + } - public void broadcast(string name) - { - broadcast(name, null, null); - } + public void broadcast(string name) + { + broadcast(name, null, null); + } - public void broadcast(string name, string? value) - { - broadcast(name, value, null); - } + public void broadcast(string name, string? value) + { + broadcast(name, value, null); + } - public void broadcast(string name, string? value, string? scope = null) - { - var broadcast = _serviceProvider.GetRequiredService(); - broadcast.BroadcastMessage(name, value, scope); - } + public void broadcast(string name, string? value, string? scope = null) + { + var broadcast = _serviceProvider.GetRequiredService(); + broadcast.BroadcastMessage(name, value, scope); + } - public void display(string message) - { - display(message, 0); - } + public void display(string message) + { + display(message, 0); + } - public void display(string message, int timeout) - { - var display = _serviceProvider.GetRequiredService(); - display.DisplayText(message, "", null, timeout); - } + public void display(string message, int timeout) + { + var display = _serviceProvider.GetRequiredService(); + display.DisplayText(message, "", null, timeout); + } - public void alert(string message) - { - alert(message, null); - } + public void alert(string message) + { + alert(message, null); + } - public void alert(string message, string? title) - { - var msgbox = _serviceProvider.GetRequiredService(); - msgbox.Show(message, title ?? "ALERT", null); - } + public void alert(string message, string? title) + { + var msgbox = _serviceProvider.GetRequiredService(); + msgbox.Show(message, title ?? "ALERT", null); + } - public bool confirm(string message) - { - return confirm(message, null); - } + public bool confirm(string message) + { + return confirm(message, null); + } - public bool confirm(string message, string? title) - { - var msgbox = _serviceProvider.GetRequiredService(); - return msgbox.Confirm(message, title, null); - } + public bool confirm(string message, string? title) + { + var msgbox = _serviceProvider.GetRequiredService(); + return msgbox.Confirm(message, title, null); + } - public string? prompt(string message) - { - return prompt(message, null, null); - } + public string? prompt(string message) + { + return prompt(message, null, null); + } - public string? prompt(string message, string? title) - { - return prompt(message, title, null); - } + public string? prompt(string message, string? title) + { + return prompt(message, title, null); + } - public string? prompt(string message, string? title, string? text) - { - var msgbox = _serviceProvider.GetRequiredService(); - var text2 = text ?? string.Empty; - return msgbox.Prompt(message, title, null, ref text2) - ? text2 : null; - } + public string? prompt(string message, string? title, string? text) + { + var msgbox = _serviceProvider.GetRequiredService(); + var text2 = text ?? string.Empty; + return msgbox.Prompt(message, title, null, ref text2) + ? text2 : null; + } - public string? pick(string message, string? title, string[] choices) - { - return pick(message, title, choices, null); - } + public string? pick(string message, string? title, string[] choices) + { + return pick(message, title, choices, null); + } - public string? pick(string message, string? title, string[] choices, string? defaultChoice) - { - var msgbox = _serviceProvider.GetRequiredService(); - var choice = defaultChoice; - return msgbox.Pick(choices, message, title, null, ref choice) - ? choice : null; - } + public string? pick(string message, string? title, string[] choices, string? defaultChoice) + { + var msgbox = _serviceProvider.GetRequiredService(); + var choice = defaultChoice; + return msgbox.Pick(choices, message, title, null, ref choice) + ? choice : null; + } - public void run(string processOrCommand) - { - var app = _serviceProvider.GetRequiredService(); - app.Run(processOrCommand, null); - } + public void run(string processOrCommand) + { + var app = _serviceProvider.GetRequiredService(); + app.Run(processOrCommand, null); + } - public void run(string processOrCommand, string? arguments) - { - var app = _serviceProvider.GetRequiredService(); - app.Run(processOrCommand, arguments); - } + public void run(string processOrCommand, string? arguments) + { + var app = _serviceProvider.GetRequiredService(); + app.Run(processOrCommand, arguments); + } - public bool switchTo(string? titleOrProcess) - { - return switchTo(null, null, titleOrProcess); - } + public bool switchTo(string? titleOrProcess) + { + return switchTo(null, null, titleOrProcess); + } - public bool switchTo(string? title, string? process) - { - return switchTo(title, process, null); - } + public bool switchTo(string? title, string? process) + { + return switchTo(title, process, null); + } - public bool switchTo(string? title, string? process, string? titleOrProcess) - { - var app = _serviceProvider.GetRequiredService(); - return app.SwitchTo(title, process, titleOrProcess, null); - } + public bool switchTo(string? title, string? process, string? titleOrProcess) + { + var app = _serviceProvider.GetRequiredService(); + return app.SwitchTo(title, process, titleOrProcess, null); + } - public bool switchTo(string? title, string? process, string? titleOrProcess, string? exclude) - { - var app = _serviceProvider.GetRequiredService(); - return app.SwitchTo(title, process, titleOrProcess, exclude); - } + public bool switchTo(string? title, string? process, string? titleOrProcess, string? exclude) + { + var app = _serviceProvider.GetRequiredService(); + return app.SwitchTo(title, process, titleOrProcess, exclude); + } - public bool minimize(string? titleOrProcess) - { - return minimize(null, null, titleOrProcess); - } + public bool minimize(string? titleOrProcess) + { + return minimize(null, null, titleOrProcess); + } - public bool minimize(string? title, string? process) - { - return minimize(title, process, null); - } + public bool minimize(string? title, string? process) + { + return minimize(title, process, null); + } - public bool minimize(string? title, string? process, string? titleOrProcess) - { - var app = _serviceProvider.GetRequiredService(); - return app.Minimize(title, process, titleOrProcess, null); - } + public bool minimize(string? title, string? process, string? titleOrProcess) + { + var app = _serviceProvider.GetRequiredService(); + return app.Minimize(title, process, titleOrProcess, null); + } - public bool minimize(string? title, string? process, string? titleOrProcess, string? exclude) - { - var app = _serviceProvider.GetRequiredService(); - return app.Minimize(title, process, titleOrProcess, exclude); - } + public bool minimize(string? title, string? process, string? titleOrProcess, string? exclude) + { + var app = _serviceProvider.GetRequiredService(); + return app.Minimize(title, process, titleOrProcess, exclude); + } - public bool minimize(string? title, string? process, string? titleOrProcess, string? exclude, bool all) - { - var app = _serviceProvider.GetRequiredService(); - return app.Minimize(title, process, titleOrProcess, exclude, all); - } + public bool minimize(string? title, string? process, string? titleOrProcess, string? exclude, bool all) + { + var app = _serviceProvider.GetRequiredService(); + return app.Minimize(title, process, titleOrProcess, exclude, all); + } - public bool maximize(string? titleOrProcess) - { - return maximize(null, null, titleOrProcess); - } + public bool maximize(string? titleOrProcess) + { + return maximize(null, null, titleOrProcess); + } - public bool maximize(string? title, string? process) - { - return maximize(title, process, null); - } + public bool maximize(string? title, string? process) + { + return maximize(title, process, null); + } - public bool maximize(string? title, string? process, string? titleOrProcess) - { - var app = _serviceProvider.GetRequiredService(); - return app.Maximize(title, process, titleOrProcess, null); - } + public bool maximize(string? title, string? process, string? titleOrProcess) + { + var app = _serviceProvider.GetRequiredService(); + return app.Maximize(title, process, titleOrProcess, null); + } - public bool maximize(string? title, string? process, string? titleOrProcess, string? exclude) - { - var app = _serviceProvider.GetRequiredService(); - return app.Maximize(title, process, titleOrProcess, exclude); - } + public bool maximize(string? title, string? process, string? titleOrProcess, string? exclude) + { + var app = _serviceProvider.GetRequiredService(); + return app.Maximize(title, process, titleOrProcess, exclude); + } - public bool maximize(string? title, string? process, string? titleOrProcess, string? exclude, bool all) - { - var app = _serviceProvider.GetRequiredService(); - return app.Maximize(title, process, titleOrProcess, exclude, all); - } + public bool maximize(string? title, string? process, string? titleOrProcess, string? exclude, bool all) + { + var app = _serviceProvider.GetRequiredService(); + return app.Maximize(title, process, titleOrProcess, exclude, all); + } - public bool restore(string? titleOrProcess) - { - return restore(null, null, titleOrProcess); - } + public bool restore(string? titleOrProcess) + { + return restore(null, null, titleOrProcess); + } - public bool restore(string? title, string? process) - { - return restore(title, process, null); - } + public bool restore(string? title, string? process) + { + return restore(title, process, null); + } - public bool restore(string? title, string? process, string? titleOrProcess) - { - var app = _serviceProvider.GetRequiredService(); - return app.Restore(title, process, titleOrProcess, null); - } + public bool restore(string? title, string? process, string? titleOrProcess) + { + var app = _serviceProvider.GetRequiredService(); + return app.Restore(title, process, titleOrProcess, null); + } - public bool restore(string? title, string? process, string? titleOrProcess, string? exclude) - { - var app = _serviceProvider.GetRequiredService(); - return app.Restore(title, process, titleOrProcess, exclude); - } + public bool restore(string? title, string? process, string? titleOrProcess, string? exclude) + { + var app = _serviceProvider.GetRequiredService(); + return app.Restore(title, process, titleOrProcess, exclude); + } - public bool restore(string? title, string? process, string? titleOrProcess, string? exclude, bool all) - { - var app = _serviceProvider.GetRequiredService(); - return app.Restore(title, process, titleOrProcess, exclude, all); - } + public bool restore(string? title, string? process, string? titleOrProcess, string? exclude, bool all) + { + var app = _serviceProvider.GetRequiredService(); + return app.Restore(title, process, titleOrProcess, exclude, all); + } - public bool close(string? titleOrProcess) - { - return close(null, null, titleOrProcess); - } + public bool close(string? titleOrProcess) + { + return close(null, null, titleOrProcess); + } - public bool close(string? title, string? process) - { - return close(title, process, null); - } + public bool close(string? title, string? process) + { + return close(title, process, null); + } - public bool close(string? title, string? process, string? titleOrProcess) - { - var app = _serviceProvider.GetRequiredService(); - return app.Close(title, process, titleOrProcess, null); - } + public bool close(string? title, string? process, string? titleOrProcess) + { + var app = _serviceProvider.GetRequiredService(); + return app.Close(title, process, titleOrProcess, null); + } - public bool close(string? title, string? process, string? titleOrProcess, string? exclude) - { - var app = _serviceProvider.GetRequiredService(); - return app.Close(title, process, titleOrProcess, exclude); - } + public bool close(string? title, string? process, string? titleOrProcess, string? exclude) + { + var app = _serviceProvider.GetRequiredService(); + return app.Close(title, process, titleOrProcess, exclude); + } - public bool close(string? title, string? process, string? titleOrProcess, string? exclude, bool all) - { - var app = _serviceProvider.GetRequiredService(); - return app.Close(title, process, titleOrProcess, exclude, all); - } + public bool close(string? title, string? process, string? titleOrProcess, string? exclude, bool all) + { + var app = _serviceProvider.GetRequiredService(); + return app.Close(title, process, titleOrProcess, exclude, all); + } - public string? readTextFile(string fileName) - { - return File.ReadAllText(fileName); - } + public string? readTextFile(string fileName) + { + return File.ReadAllText(fileName); + } - public void writeTextFile(string fileName, string content) - { - File.WriteAllText(fileName, content); - } + public void writeTextFile(string fileName, string content) + { + File.WriteAllText(fileName, content); + } - public void appendTextFile(string fileName, string content) - { - File.AppendAllText(fileName, content); - } + public void appendTextFile(string fileName, string content) + { + File.AppendAllText(fileName, content); + } - public void log(string message) - { - log("info", message); - } + public void log(string message) + { + log("info", message); + } - public void log(string level, string message) - { - switch (level) + public void log(string level, string message) { - case "error": - MR.DBG_TRACE_ERROR(message); - break; + switch (level) + { + case "error": + MR.DBG_TRACE_ERROR(message); + break; + + case "warning": + MR.DBG_TRACE_WARNING(message); + break; + + case "verbose": + MR.DBG_TRACE_VERBOSE(message); + break; + + default: + MR.DBG_TRACE_INFO(message); + break; + } + } - case "warning": - MR.DBG_TRACE_WARNING(message); - break; + public string httpGet(string uri) + { + var httpClient = _serviceProvider.GetRequiredService(); + var send = httpClient.SendRequestAsync(uri, "GET", null, null); + send.Wait(); - case "verbose": - MR.DBG_TRACE_VERBOSE(message); - break; + var response = send.Result; + var read = response.Content.ReadAsStringAsync(); + read.Wait(); - default: - MR.DBG_TRACE_INFO(message); - break; + return read.Result; } - } - - public string httpGet(string uri) - { - var httpClient = _serviceProvider.GetRequiredService(); - var send = httpClient.SendRequestAsync(uri, "GET", null, null); - send.Wait(); - - var response = send.Result; - var read = response.Content.ReadAsStringAsync(); - read.Wait(); - return read.Result; - } + public string httpPost(string uri, string content) + { + var httpClient = _serviceProvider.GetRequiredService(); + var send = httpClient.SendRequestAsync(uri, "POST", content, null); + send.Wait(); - public string httpPost(string uri, string content) - { - var httpClient = _serviceProvider.GetRequiredService(); - var send = httpClient.SendRequestAsync(uri, "POST", content, null); - send.Wait(); + var response = send.Result; + var read = response.Content.ReadAsStringAsync(); + read.Wait(); - var response = send.Result; - var read = response.Content.ReadAsStringAsync(); - read.Wait(); + return read.Result; + } - return read.Result; - } + public void insertText(string text) + { + var sendKeys = _serviceProvider.GetRequiredService(); + sendKeys.InsertText(text); + } - public void insertText(string text) - { - var sendKeys = _serviceProvider.GetRequiredService(); - sendKeys.InsertText(text); - } + public void sendKeys(string keys) + { + sendKeys(keys, 1); + } - public void sendKeys(string keys) - { - sendKeys(keys, 1); - } + public void sendKeys(string keys, int times) + { + var sendKeys = _serviceProvider.GetRequiredService(); + sendKeys.SendKeys(keys, times); + } - public void sendKeys(string keys, int times) - { - var sendKeys = _serviceProvider.GetRequiredService(); - sendKeys.SendKeys(keys, times); - } + public void mouseClick(int x, int y) + { + var mouse = _serviceProvider.GetRequiredService(); + mouse.ClickButton($"{x},{y}", null, null); + } - public void mouseClick(int x, int y) - { - var mouse = _serviceProvider.GetRequiredService(); - mouse.ClickButton($"{x},{y}", null, null); - } + public void mouseClick(int x, int y, string button) + { + var mouse = _serviceProvider.GetRequiredService(); + mouse.ClickButton($"{x},{y}", null, button); + } - public void mouseClick(int x, int y, string button) - { - var mouse = _serviceProvider.GetRequiredService(); - mouse.ClickButton($"{x},{y}", null, button); - } + public void mouseMove(int x, int y) + { + var mouse = _serviceProvider.GetRequiredService(); + mouse.Move($"{x},{y}", null); + } - public void mouseMove(int x, int y) - { - var mouse = _serviceProvider.GetRequiredService(); - mouse.Move($"{x},{y}", null); - } + public void mousePress(int x, int y) + { + var mouse = _serviceProvider.GetRequiredService(); + mouse.PressButton($"{x},{y}", null, null); + } - public void mousePress(int x, int y) - { - var mouse = _serviceProvider.GetRequiredService(); - mouse.PressButton($"{x},{y}", null, null); - } + public void mousePress(int x, int y, string button) + { + var mouse = _serviceProvider.GetRequiredService(); + mouse.PressButton($"{x},{y}", null, button); + } - public void mousePress(int x, int y, string button) - { - var mouse = _serviceProvider.GetRequiredService(); - mouse.PressButton($"{x},{y}", null, button); - } + public void mouseRelease(int x, int y) + { + var mouse = _serviceProvider.GetRequiredService(); + mouse.ReleaseButton($"{x},{y}", null, null); + } - public void mouseRelease(int x, int y) - { - var mouse = _serviceProvider.GetRequiredService(); - mouse.ReleaseButton($"{x},{y}", null, null); - } + public void mouseRelease(int x, int y, string button) + { + var mouse = _serviceProvider.GetRequiredService(); + mouse.ReleaseButton($"{x},{y}", null, button); + } - public void mouseRelease(int x, int y, string button) - { - var mouse = _serviceProvider.GetRequiredService(); - mouse.ReleaseButton($"{x},{y}", null, button); - } + public UInt64 listen(string state) + { + var intent = _serviceProvider.GetRequiredService(); + return intent.SetState(state.ToLower() == "toggle" + ? ListeningStateHelpers.ToggleState(intent.GetState()) + : ListeningStateHelpers.Parse(state)); + } - public UInt64 listen(string state) - { - var intent = _serviceProvider.GetRequiredService(); - return intent.SetState(state.ToLower() == "toggle" - ? ListeningStateHelpers.ToggleState(intent.GetState()) - : ListeningStateHelpers.Parse(state)); - } + public UInt64 listenOnce() + { + return listen("once"); + } - public UInt64 listenOnce() - { - return listen("once"); - } + public UInt64 listenOn() + { + return listen("on"); + } - public UInt64 listenOn() - { - return listen("on"); - } + public UInt64 listenOff() + { + return listen("off"); + } - public UInt64 listenOff() - { - return listen("off"); - } + public UInt64 listenSleep() + { + return listen("sleep"); + } - public UInt64 listenSleep() - { - return listen("sleep"); - } + public UInt64 listenToggle() + { + return listen("toggle"); + } - public UInt64 listenToggle() - { - return listen("toggle"); - } + public void listenRestore(UInt64 state) + { + var intent = _serviceProvider.GetRequiredService(); + intent.RestoreState(state); + } - public void listenRestore(UInt64 state) - { - var intent = _serviceProvider.GetRequiredService(); - intent.RestoreState(state); - } + public void emulate(string text) + { + var service = _serviceProvider?.GetRequiredService(); + service?.Emulate(text); + } - public void emulate(string text) - { - var service = _serviceProvider?.GetRequiredService(); - service?.Emulate(text); - } + public void beep() + { + var playMedia = _serviceProvider.GetRequiredService(); + playMedia.Beep(); + } - public void beep() - { - var playMedia = _serviceProvider.GetRequiredService(); - playMedia.Beep(); - } + public void beep(int frequency, int duration) + { + var playMedia = _serviceProvider.GetRequiredService(); + playMedia.Beep(frequency, duration); + } - public void beep(int frequency, int duration) - { - var playMedia = _serviceProvider.GetRequiredService(); - playMedia.Beep(frequency, duration); - } + public void playAudio(string audio) + { + var playMedia = _serviceProvider.GetRequiredService(); + playMedia.Play(audio); + } - public void playAudio(string audio) - { - var playMedia = _serviceProvider.GetRequiredService(); - playMedia.Play(audio); - } + public void pauseAudio() + { + var playMedia = _serviceProvider.GetRequiredService(); + playMedia.Pause(); + } - public void pauseAudio() - { - var playMedia = _serviceProvider.GetRequiredService(); - playMedia.Pause(); - } + public void resumeAudio() + { + var playMedia = _serviceProvider.GetRequiredService(); + playMedia.Resume(); + } - public void resumeAudio() - { - var playMedia = _serviceProvider.GetRequiredService(); - playMedia.Resume(); - } + public void stopAudio() + { + var playMedia = _serviceProvider.GetRequiredService(); + playMedia.Stop(); + } - public void stopAudio() - { - var playMedia = _serviceProvider.GetRequiredService(); - playMedia.Stop(); - } + public string pickRandom(string[] values) + { + var random = _serviceProvider.GetRequiredService(); + return random.PickRandom(values); + } - public string pickRandom(string[] values) - { - var random = _serviceProvider.GetRequiredService(); - return random.PickRandom(values); - } + public void speakText(string text) + { + speakText(text, null, null, null); + } - public void speakText(string text) - { - speakText(text, null, null, null); - } + public void speakText(string text, string? voice, string? output, string? bargeIn) + { + var speak = _serviceProvider.GetRequiredService(); + speak.SpeakText(text, voice, output, bargeIn).Wait(); + } - public void speakText(string text, string? voice, string? output, string? bargeIn) - { - var speak = _serviceProvider.GetRequiredService(); - speak.SpeakText(text, voice, output, bargeIn).Wait(); - } + public void speakSsml(string ssml) + { + speakSsml(ssml, null, null, null); + } - public void speakSsml(string ssml) - { - speakSsml(ssml, null, null, null); - } + public void speakSsml(string ssml, string? voice, string? output, string? bargeIn) + { + var speak = _serviceProvider.GetRequiredService(); + speak.SpeakSsml(ssml, voice, output, bargeIn).Wait(); + } - public void speakSsml(string ssml, string? voice, string? output, string? bargeIn) - { - var speak = _serviceProvider.GetRequiredService(); - speak.SpeakSsml(ssml, voice, output, bargeIn).Wait(); - } + public string translate(string text) + { + return translate(text, null, null); + } - public string translate(string text) - { - return translate(text, null, null); - } + public string translate(string text, string from) + { + return translate(text, from, null); + } - public string translate(string text, string from) - { - return translate(text, from, null); - } + public string translate(string text, string? from, string? to) + { + var translate = _serviceProvider.GetRequiredService(); + return translate.Translate(text, from, to); + } - public string translate(string text, string? from, string? to) - { - var translate = _serviceProvider.GetRequiredService(); - return translate.Translate(text, from, to); - } + public void wait(int timeInMs) + { + if (timeInMs < 1000) + { + var stop = DateTime.Now.AddMilliseconds(timeInMs); + while (DateTime.Now < stop) { } + } + else + { + Task.Delay(timeInMs).Wait(); + } + } - public void wait(int timeInMs) - { - if (timeInMs < 1000) + public string complete(string prompt) { - var stop = DateTime.Now.AddMilliseconds(timeInMs); - while (DateTime.Now < stop) { } + return complete(prompt, null, null, null); } - else + + public string complete(string prompt, string? maxTokens, string? temperature) { - Task.Delay(timeInMs).Wait(); + return complete(prompt, null, null, null, maxTokens, temperature); } - } - public string complete(string prompt) - { - return complete(prompt, null, null, null); - } + public string complete(string prompt, + string? key = null, + string? endpoint = null, + string? deployment = null, + string? maxTokens = null, + string? temperature = null, + string? frequencyPenalty = null, + string? presencePenalty = null, + string? topP = null, + string? stop = null) + { + var completed = string.Empty; - public string complete(string prompt, string? maxTokens, string? temperature) - { - return complete(prompt, null, null, null, maxTokens, temperature); - } + Task.Run(async () => + { + var service = _serviceProvider.GetRequiredService(); + var response = await service.Complete(prompt, key, endpoint, deployment, maxTokens, temperature, frequencyPenalty, presencePenalty, topP, stop); + completed = response.Replace("\n", "\r\n").Replace(" .", ".").Trim(); + }).Wait(); - public string complete(string prompt, - string? key = null, - string? endpoint = null, - string? deployment = null, - string? maxTokens = null, - string? temperature = null, - string? frequencyPenalty = null, - string? presencePenalty = null, - string? topP = null, - string? stop = null) - { - var completed = string.Empty; + return completed; + } - Task.Run(async () => { - var service = _serviceProvider.GetRequiredService(); - var response = await service.Complete(prompt, key, endpoint, deployment, maxTokens, temperature, frequencyPenalty, presencePenalty, topP, stop); - completed = response.Replace("\n", "\r\n").Replace(" .", ".").Trim(); - }).Wait(); + public void quit() + { + var host = _serviceProvider.GetRequiredService(); + host.Quit(); + } - return completed; - } + // public void imageAnalyze(); + // public void triggersExpect(); + // public void scriptEval(); - public void quit() - { - var host = _serviceProvider.GetRequiredService(); - host.Quit(); + private readonly IServiceProvider _serviceProvider; + private readonly IExecutionContext _context; } - - // public void imageAnalyze(); - // public void triggersExpect(); - // public void scriptEval(); - - private readonly IServiceProvider _serviceProvider; - private readonly IExecutionContext _context; -} +} \ No newline at end of file diff --git a/src/cs/ScriptExecution/ScriptExecutionService.cs b/src/cs/ScriptExecution/ScriptExecutionService.cs index 0fc83f8e..fb60fd03 100644 --- a/src/cs/ScriptExecution/ScriptExecutionService.cs +++ b/src/cs/ScriptExecution/ScriptExecutionService.cs @@ -1,51 +1,70 @@ -using Microsoft.CognitiveServices.Speech; -using Microsoft.CognitiveServices.Speech.Audio; +using System; using Microsoft.Extensions.DependencyInjection; +/* Unmerged change from project 'macaroni_core (net6.0-windows)' +Before: using System.Diagnostics; using System.Text; using Newtonsoft.Json; +After: +using Newtonsoft.Json; +using System.Diagnostics; +using System.Text; +*/ -namespace macaroni; +/* Unmerged change from project 'macaroni_core (netstandard2.1)' +Before: +using System.Diagnostics; +using System.Text; +using Newtonsoft.Json; +After: +using Newtonsoft.Json; +using System.Diagnostics; +using System.Text; +*/ -internal partial class ScriptExecutionService : IScriptExecutionService -{ - public ScriptExecutionService(IServiceProvider services) - { - _serviceProvider = services; - } - public void Execute(IExecutionContext context, string code, string? language) +namespace macaroni +{ + internal partial class ScriptExecutionService : IScriptExecutionService { - MR.DBG_TRACE_INFO($"-- ScriptExecutionService: Execute({code}, {language})"); - - // - // JInt is similar to Microsoft.ClearScript, but instead of wrapping V8 javascript engine, - // JInt is a ground up implementation of javascript in .NET/C# (maintained by MSFT employee, not MS itself) - - var engine = new Jint.Engine(); - engine.SetValue("global", new ScriptExecutionGlobalStateObjectModel(_serviceProvider.GetRequiredService())); - engine.SetValue("command", new ScriptExecutionHostObjectModel(_serviceProvider, context)); - engine.SetValue("android", new ScriptExecutionAndroidObjectModel(_serviceProvider)); - engine.SetValue("clipboard", new ScriptExecutionClipboardObjectModel(_serviceProvider)); - engine.Execute(code); - } + public ScriptExecutionService(IServiceProvider services) + { + _serviceProvider = services; + } - public object? Evaluate(string code, string? language) - { - try + public void Execute(IExecutionContext context, string code, string? language) { + MR.DBG_TRACE_INFO($"-- ScriptExecutionService: Execute({code}, {language})"); + + // + // JInt is similar to Microsoft.ClearScript, but instead of wrapping V8 javascript engine, + // JInt is a ground up implementation of javascript in .NET/C# (maintained by MSFT employee, not MS itself) + var engine = new Jint.Engine(); + engine.SetValue("global", new ScriptExecutionGlobalStateObjectModel(_serviceProvider.GetRequiredService())); + engine.SetValue("command", new ScriptExecutionHostObjectModel(_serviceProvider, context)); + engine.SetValue("android", new ScriptExecutionAndroidObjectModel(_serviceProvider)); engine.SetValue("clipboard", new ScriptExecutionClipboardObjectModel(_serviceProvider)); - - var result = engine.Evaluate(code); - return result.ToObject(); + engine.Execute(code); } - catch (Exception ex) + + public object? Evaluate(string code, string? language) { - MR.DBG_TRACE_INFO($"EXCEPTION: {ex}"); - return ex; + try + { + var engine = new Jint.Engine(); + engine.SetValue("clipboard", new ScriptExecutionClipboardObjectModel(_serviceProvider)); + + var result = engine.Evaluate(code); + return result.ToObject(); + } + catch (Exception ex) + { + MR.DBG_TRACE_INFO($"EXCEPTION: {ex}"); + return ex; + } } - } - private readonly IServiceProvider _serviceProvider; -} + private readonly IServiceProvider _serviceProvider; + } +} \ No newline at end of file diff --git a/src/cs/Ui/interop_win32.cs b/src/cs/Ui/interop_win32.cs index ccd2b93e..e3c143d9 100644 --- a/src/cs/Ui/interop_win32.cs +++ b/src/cs/Ui/interop_win32.cs @@ -1,60 +1,61 @@ +using System; using System.Runtime.InteropServices; -namespace macaroni.interop; - -internal partial class Win32 +namespace macaroni.interop { - [StructLayout(LayoutKind.Sequential)] - internal struct Size + internal partial class Win32 { - internal Int32 cx; - internal Int32 cy; - internal Size(Int32 cx, Int32 cy) { this.cx = cx; this.cy = cy; } - } - - [StructLayout(LayoutKind.Sequential)] - internal struct Point - { - internal Int32 x; - internal Int32 y; - - internal Point(Int32 x, Int32 y) { this.x = x; this.y = y; } + [StructLayout(LayoutKind.Sequential)] + internal struct Size + { + internal Int32 cx; + internal Int32 cy; + internal Size(Int32 cx, Int32 cy) { this.cx = cx; this.cy = cy; } + } + + [StructLayout(LayoutKind.Sequential)] + internal struct Point + { + internal Int32 x; + internal Int32 y; + + internal Point(Int32 x, Int32 y) { this.x = x; this.y = y; } + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct BLENDFUNCTION + { + internal byte BlendOp; + internal byte BlendFlags; + internal byte SourceConstantAlpha; + internal byte AlphaFormat; + } + + internal const byte AC_SRC_OVER = 0x00; + internal const byte AC_SRC_ALPHA = 0x01; + internal const Int32 ULW_COLORKEY = 0x00000001; + internal const Int32 ULW_ALPHA = 0x00000002; + internal const Int32 ULW_OPAQUE = 0x00000004; + + [DllImport("user32.dll")] + internal static extern IntPtr GetDC(IntPtr hWnd); + + [DllImport("user32.dll", ExactSpelling = true)] + internal static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC); + + [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] + internal static extern IntPtr CreateCompatibleDC(IntPtr hDC); + + [DllImport("gdi32.dll", ExactSpelling = true)] + internal static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject); + + [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)] + internal static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, ref Point pptDst, ref Size psize, IntPtr hdcSrc, ref Point pprSrc, Int32 crKey, ref BLENDFUNCTION pblend, Int32 dwFlags); + + [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] + internal static extern bool DeleteObject(IntPtr hObject); + + [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] + internal static extern bool DeleteDC(IntPtr hdc); } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - internal struct BLENDFUNCTION - { - internal byte BlendOp; - internal byte BlendFlags; - internal byte SourceConstantAlpha; - internal byte AlphaFormat; - } - - internal const byte AC_SRC_OVER = 0x00; - internal const byte AC_SRC_ALPHA = 0x01; - internal const Int32 ULW_COLORKEY = 0x00000001; - internal const Int32 ULW_ALPHA = 0x00000002; - internal const Int32 ULW_OPAQUE = 0x00000004; - - [DllImport("user32.dll")] - internal static extern IntPtr GetDC(IntPtr hWnd); - - [DllImport("user32.dll", ExactSpelling = true)] - internal static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC); - - [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] - internal static extern IntPtr CreateCompatibleDC(IntPtr hDC); - - [DllImport("gdi32.dll", ExactSpelling = true)] - internal static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject); - - [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)] - internal static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, ref Point pptDst, ref Size psize, IntPtr hdcSrc, ref Point pprSrc, Int32 crKey, ref BLENDFUNCTION pblend, Int32 dwFlags); - - [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] - internal static extern bool DeleteObject(IntPtr hObject); - - [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] - internal static extern bool DeleteDC(IntPtr hdc); -} - +} \ No newline at end of file diff --git a/src/cs/macaroni_core.csproj b/src/cs/macaroni_core.csproj index 0fcea2c8..c5910f7a 100644 --- a/src/cs/macaroni_core.csproj +++ b/src/cs/macaroni_core.csproj @@ -5,17 +5,18 @@ 1.29 false - net6.0;net6.0-windows + net6.0;net6.0-windows;netstandard2.1 false false true true Library macaroni - enable + disable enable 1.0.472.0 1.0.472.0 + 8 True 1.0.472.0-pre @@ -32,6 +33,12 @@ Platform_NoIcon_Todo;Platform_NoImage_Todo;Platform_NoApplicationExit_Todo + + + + + + @@ -132,8 +139,4 @@ - - - - \ No newline at end of file diff --git a/src/macaroni_api_c/DisposableBase.cs b/src/macaroni_api_c/DisposableBase.cs index b9fb2837..139ee15a 100644 --- a/src/macaroni_api_c/DisposableBase.cs +++ b/src/macaroni_api_c/DisposableBase.cs @@ -1,7 +1,4 @@ -using System; -using System.Threading; - -namespace macaroni_api_c.Internal +namespace macaroni_api_c.Internal { /// /// Base class that implements IDisposable. diff --git a/src/macaroni_api_c/InteropFunctions.cs b/src/macaroni_api_c/InteropFunctions.cs index 2264a0fe..6993e1bb 100644 --- a/src/macaroni_api_c/InteropFunctions.cs +++ b/src/macaroni_api_c/InteropFunctions.cs @@ -1,670 +1,670 @@ - -using Jint.Runtime; -using Microsoft.Identity.Client; -using Microsoft.VisualBasic; -using System; -using System.Runtime.InteropServices; -using System.Text; - -namespace macaroni_api_c.Internal -{ - internal static class InteropFunctions - { - private unsafe delegate UInt32 nativeVoidFunction(IntPtr* context); - private unsafe delegate UInt32 nativeVoidFunctionOneParam(IntPtr* context, IntPtr param); - private unsafe delegate UInt32 nativeVoidFunctionTwoParam(IntPtr* context, IntPtr param1, IntPtr param2); - private unsafe delegate UInt32 nativeVoidFunctionThreeParam(IntPtr* context, IntPtr param1, IntPtr param2, IntPtr param3); - private unsafe delegate UInt32 nativeVoidFunctionFourParam(IntPtr* context, IntPtr param1, IntPtr param2, IntPtr param3, IntPtr param4); - - private unsafe delegate UInt32 nativeIntFunction_In_Zero_Out_One(IntPtr* context, IntPtr * outParam); - private unsafe delegate UInt32 nativeIntFunction_In_One_Out_One(IntPtr* context, IntPtr inParam, IntPtr* outParam); - private unsafe delegate UInt32 nativeIntFunction_In_Two_Out_One(IntPtr* context, IntPtr inParam1, IntPtr inParam2, IntPtr outParam); - private unsafe delegate UInt32 nativeIntFunction_In_Three_Out_One(IntPtr* context, IntPtr inParam1, IntPtr inParam2, IntPtr inParam3, IntPtr* outParam); - private unsafe delegate UInt32 nativeIntFunction_In_Four_Out_One(IntPtr* context, IntPtr inParam1, IntPtr inParam2, IntPtr inParam3, IntPtr inParam4, IntPtr* outParam); - private unsafe delegate UInt32 nativeIntFunction_In_Six_Out_One(IntPtr* context, IntPtr inParam1, IntPtr inParam2, IntPtr inParam3, IntPtr inParam4, IntPtr inParam5, IntPtr inParam6, IntPtr* outParam); - - private unsafe delegate UInt32 nativeFreeFunction(IntPtr nativeMemToFree); - - /// - /// Calls the native function with the context and expects no result. - /// - /// Function signature should be void Func(IntPtr*) - /// - /// - /// - public unsafe static void CallNativeVoidFunction(IntPtr nativeFunction, IntPtr* nativeContext) - { - var nativeFunc = Marshal.GetDelegateForFunctionPointer(nativeFunction); - nativeFunc(nativeContext); - } - - /// - /// Calls the native function with the context, a null terminated char[], and expects no result. - /// - /// Function signature should be void Func(IntPtr*, IntPtr) - /// - /// Native function must be synchronous or corruption could occur. - /// - /// - /// - /// - public unsafe static void CallNativeVoidFunctionWithStringParameter(IntPtr nativeFunction, IntPtr* nativeContext, string? stringParam) - { - var nativeFunc = Marshal.GetDelegateForFunctionPointer(nativeFunction); - var nativeHandle = Utf8StringMarshaler.MarshalManagedToNative(stringParam ?? ""); - try - { - var result = nativeFunc(nativeContext, nativeHandle); - if (result != 0) - { - throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); - } - } - finally - { - Marshal.FreeHGlobal(nativeHandle); - } - } - - /// - /// Calls the native function with the context, a null terminated char[], a null terminated char[], and expects no result. - /// - /// Function signature should be void Func(IntPtr*, IntPtr, IntPtr) - /// - /// Native function must be synchronous or corruption could occur. - /// - /// - /// - /// - /// - public unsafe static void CallNativeVoidFunctionWithStringNullStringParameter(IntPtr nativeFunction, IntPtr* nativeContext, string stringParam1, string? stringParam2) - { - var nativeFunc = Marshal.GetDelegateForFunctionPointer(nativeFunction); - var nativeString1 = Utf8StringMarshaler.MarshalManagedToNative(stringParam1); - var nativeString2 = stringParam2 != null ? Utf8StringMarshaler.MarshalManagedToNative(stringParam2) : IntPtr.Zero; - try - { - var result = nativeFunc(nativeContext, nativeString1, nativeString2); - if (result != 0) - { - throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); - } - } - finally - { - Marshal.FreeHGlobal(nativeString1); - Marshal.FreeHGlobal(nativeString2); - } - } - - /// - /// Calls the native function with the context, a null terminated char[], int, and expects no result. - /// - /// Function signature should be void Func(IntPtr*, IntPtr, int) - /// - /// Native function must be synchronous or corruption could occur. - /// - /// - /// - /// - /// - public unsafe static void CallNativeVoidFunctionWithStringIntParameter(IntPtr nativeFunction, IntPtr* nativeContext, string stringParam1, int intParam2) - { - var nativeFunc = Marshal.GetDelegateForFunctionPointer(nativeFunction); - var nativeString1 = Utf8StringMarshaler.MarshalManagedToNative(stringParam1); - try - { - var result = nativeFunc(nativeContext, nativeString1, (IntPtr)intParam2); - if (result != 0) - { - throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); - } - } - finally - { - Marshal.FreeHGlobal(nativeString1); - } - } - - /// - /// Calls the native function with the context, int and expects no result. - /// - /// Function signature should be void Func(IntPtr*, int) - /// - /// Native function must be synchronous or corruption could occur. - /// - /// - /// - /// - internal static unsafe void CallNativeVoidFunctionWithIntParameter(IntPtr nativeFunction, IntPtr* nativeContext, int intParam1) - { - var nativeFunc = Marshal.GetDelegateForFunctionPointer(nativeFunction); - try - { - var result = nativeFunc(nativeContext, (IntPtr)intParam1); - if (result != 0) - { - throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); - } - } - finally - { - } - } - - /// - /// Calls the native function with the context, int, int, and expects no result. - /// - /// Function signature should be void Func(IntPtr*, int, int) - /// - /// Native function must be synchronous or corruption could occur. - /// - /// - /// - /// - /// - public unsafe static void CallNativeVoidFunctionWithIntIntParameter(IntPtr nativeFunction, IntPtr* nativeContext, int intParam1, int intParam2) - { - var nativeFunc = Marshal.GetDelegateForFunctionPointer(nativeFunction); - try - { - var result = nativeFunc(nativeContext, (IntPtr)intParam1, (IntPtr)intParam2); - if (result != 0) - { - throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); - } - } - finally - { - } - } - - /// - /// Calls the native function with the context, a null terminated char[], a null terminated char[], int, and expects no result. - /// - /// Function signature should be void Func(IntPtr*, IntPtr, IntPtr, int) - /// - /// Native function must be synchronous or corruption could occur. - /// - /// - /// - /// - /// - /// - public unsafe static void CallNativeVoidFunctionWithStringNullStringNullIntParameter( - IntPtr nativeFunction, - IntPtr* nativeContext, - string stringParam1, - string? stringParam2, - int? intParam3 - ) - { - var nativeFunc = Marshal.GetDelegateForFunctionPointer(nativeFunction); - var nativeString1 = Utf8StringMarshaler.MarshalManagedToNative(stringParam1); - var nativeString2 = stringParam2 != null ? Utf8StringMarshaler.MarshalManagedToNative(stringParam2) : IntPtr.Zero; - IntPtr intPtr = IntPtr.Zero; - if (intParam3 != null) - { - intPtr = Marshal.AllocHGlobal(sizeof(int)); - Marshal.WriteInt32(intPtr, (int)intParam3); - } - try - { - var result = nativeFunc(nativeContext, nativeString1, nativeString2, intPtr); - if (result != 0) - { - throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); - } - } - finally - { - Marshal.FreeHGlobal(nativeString1); - Marshal.FreeHGlobal(nativeString2); - if (intPtr != IntPtr.Zero) - { - Marshal.FreeHGlobal(intPtr); - } - } - } - - /// - /// Calls the native function with the context, a null terminated char[], a null terminated char[], int, and expects no result. - /// - /// Function signature should be void Func(IntPtr*, IntPtr, IntPtr, int) - /// - /// Native function must be synchronous or corruption could occur. - /// - /// We don't need a free function since Bool is stored in the IntPtr itself. - /// - /// - /// - /// - /// - /// - public unsafe static bool CallNativeBoolFunctionWithStringNullStringNullIntParameter( - IntPtr nativeFunction, - IntPtr* nativeContext, - string stringParam1, - string? stringParam2, - int? intParam3 - ) - { - var nativeFunc = Marshal.GetDelegateForFunctionPointer(nativeFunction); - UInt32 result = 0; - IntPtr nativeBoolOut = IntPtr.Zero; - bool marshaledBool = false; - var nativeString1 = Utf8StringMarshaler.MarshalManagedToNative(stringParam1); - var nativeString2 = stringParam2 != null ? Utf8StringMarshaler.MarshalManagedToNative(stringParam2) : IntPtr.Zero; - IntPtr intPtr = IntPtr.Zero; - if (intParam3 != null) - { - intPtr = Marshal.AllocHGlobal(sizeof(int)); - Marshal.WriteInt32(intPtr, (int)intParam3); - } - try - { - - result = nativeFunc(nativeContext, nativeString1, nativeString2, intPtr, &nativeBoolOut); - if (result != 0) - { - throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); - } - } - finally - { - Marshal.FreeHGlobal(nativeString1); - Marshal.FreeHGlobal(nativeString2); - if (intPtr != IntPtr.Zero) - { - Marshal.FreeHGlobal(intPtr); - } - } - return marshaledBool; - } - - /// - /// Calls the native function with the context, a null terminated char[], a null terminated char[], a null terminated char[], - /// int, and expects no result. - /// - /// Function signature should be void Func(IntPtr*, IntPtr, IntPtr, IntPtr, int) - /// - /// Native function must be synchronous or corruption could occur. - /// - /// - /// - /// - /// - /// - /// - public unsafe static void CallNativeVoidFunctionWithStringStringNullBoolIntParameter( - IntPtr nativeFunction, - IntPtr* nativeContext, - string stringParam1, - string stringParam2, - bool? boolParam3, - int intParam4 - ) - { - var nativeFunc = Marshal.GetDelegateForFunctionPointer(nativeFunction); - var nativeString1 = Utf8StringMarshaler.MarshalManagedToNative(stringParam1); - var nativeString2 = Utf8StringMarshaler.MarshalManagedToNative(stringParam2); - IntPtr boolPtr = IntPtr.Zero; - if (boolParam3!= null) - { - boolPtr = Marshal.AllocHGlobal(1); - Marshal.WriteByte(boolPtr, (byte)((bool)boolParam3 ? 1 : 0)); - } - try - { - nativeFunc(nativeContext, nativeString1, nativeString2, boolPtr, (IntPtr)(intParam4)); - } - finally - { - Marshal.FreeHGlobal(nativeString1); - Marshal.FreeHGlobal(nativeString2); - if (boolPtr != IntPtr.Zero) - { - Marshal.FreeHGlobal(boolPtr); - } - } - } - - /// - /// Calls the native function with the context and expects a null terminated char[] to be assigned to the second parameter. - /// - /// A UInt32 as a result. - /// - /// The nativeFunction signature should be UInt32_t Func(IntPtr*, IntPtr**) - /// - /// The nativeFreeFunction signature should be UInt32_t Func(IntPtr*) - /// The nativeFreeFunction will be called to let the native layer know it can free the memory allocated to the parameter. - /// - /// This function makes a copy of the returned string before using it. - /// - /// - /// - /// - /// - public unsafe static string? CallNativeNullStringFunction(IntPtr nativeFunction, IntPtr* nativeContext, IntPtr nativeFreeFunction) - { - // This free frees up the memory created in native callback. - var nativeFreeFunc = Marshal.GetDelegateForFunctionPointer(nativeFreeFunction); - UInt32 result = 0; - IntPtr nativeString = IntPtr.Zero; - String? marshaledString = null; - try - { - var nativeFunc = Marshal.GetDelegateForFunctionPointer(nativeFunction); - - result = nativeFunc(nativeContext, &nativeString); - if (result != 0) - { - throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); - } - - marshaledString = Marshal.PtrToStringUTF8(nativeString); - - } - finally - { - if (nativeString != IntPtr.Zero) - { - result = nativeFreeFunc(nativeString); - if (result != 0) - { - throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); - } - } - } - - return marshaledString; - } - - /// - /// Calls the native function with the context and expects a null terminated char[] to be assigned to the third parameter. - /// - /// A UInt32 as a result. - /// - /// The nativeFunction signature should be UInt32_t Func(IntPtr*, IntPtr*, IntPtr**) - /// - /// The nativeFreeFunction signature should be UInt32_t Func(IntPtr*) - /// The nativeFreeFunction will be called to let the native layer know it can free the memory allocated to the parameter. - /// - /// This function makes a copy of the returned string before using it. - /// - /// - /// - /// - /// A String to pass to the native function. - /// - public unsafe static string? CallNativeNullStringFunctionWithStringParameter( - IntPtr nativeFunction, IntPtr* nativeContext, IntPtr nativeFreeFunction, string param) - { - // This free frees up the memory created in native callback. - var nativeFreeFunc = Marshal.GetDelegateForFunctionPointer(nativeFreeFunction); - UInt32 result = 0; - IntPtr nativeStringOut = IntPtr.Zero; - String? marshaledString = null; - try - { - var nativeFunc = Marshal.GetDelegateForFunctionPointer(nativeFunction); - var nativeString1 = Utf8StringMarshaler.MarshalManagedToNative(param ?? ""); - result = nativeFunc(nativeContext, nativeString1, &nativeStringOut); - if (result != 0) - { - throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); - } - - marshaledString = Marshal.PtrToStringUTF8(nativeStringOut); - Marshal.FreeHGlobal(nativeString1); - - } - finally - { - if (nativeStringOut != IntPtr.Zero) - { - result = nativeFreeFunc(nativeStringOut); - if (result != 0) - { - throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); - } - } - } - - return marshaledString; - } - - /// - /// Calls the native function with the context, null terminated char [], null terminated char [], null terminated char [], - /// int, and expects a null terminated char[] as a result. - /// - /// Function signature should be char * Func(IntPtr*, IntPtr, IntPtr, IntPtr, int) - /// - /// This function makes a copy of the returned string before using it. - /// - /// The nativeFreeFunction signature should be UInt32_t Func(IntPtr*) - /// The nativeFreeFunction will be called to let the native layer know it can free the memory allocated to the parameter. - /// - /// - /// - /// - /// - /// - /// - /// - public unsafe static string CallNativeNullStringFunctionWithStringNullStringNullStringNullIntParameter( - IntPtr nativeFunction, - IntPtr* nativeContext, - string stringParam1, - string? stringParam2, - string? stringParam3, - int? intParam4, - IntPtr nativeFreeFunction - ) - { - // This free frees up the memory created in native callback. - var nativeFreeFunc = Marshal.GetDelegateForFunctionPointer(nativeFreeFunction); - UInt32 result = 0; - IntPtr nativeStringOut = IntPtr.Zero; - String? marshaledString = null; - try - { - var nativeFunc = Marshal.GetDelegateForFunctionPointer(nativeFunction); - var nativeString1 = Utf8StringMarshaler.MarshalManagedToNative(stringParam1); - var nativeString2 = stringParam2 != null ? Utf8StringMarshaler.MarshalManagedToNative(stringParam2) : IntPtr.Zero; - var nativeString3 = stringParam3 != null ? Utf8StringMarshaler.MarshalManagedToNative(stringParam3) : IntPtr.Zero; - IntPtr intPtr = IntPtr.Zero; - if (intParam4 != null) - { - intPtr = Marshal.AllocHGlobal(sizeof(int)); - Marshal.WriteInt32(intPtr, (int)intParam4); - } - result = nativeFunc(nativeContext, nativeString1, nativeString2, nativeString3, intPtr, &nativeStringOut); - - if (result != 0) - { - throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); - } - marshaledString = Marshal.PtrToStringUTF8(nativeStringOut); - - Marshal.FreeHGlobal(nativeString1); - Marshal.FreeHGlobal(nativeString2); - Marshal.FreeHGlobal(nativeString3); - } - finally - { - if (nativeStringOut != IntPtr.Zero) - { - result = nativeFreeFunc(nativeStringOut); - if (result != 0) - { - throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); - } - } - } - return marshaledString ?? ""; - } - - /// - /// Calls the native function with the context, null terminated char [], null terminated char [], a nullable int, - /// an array of null terminated char [], number of entries in the array, a null terminated char [] - /// and expects a null terminated char[] as a result. - /// - /// Function signature should be char * Func(IntPtr*, IntPtr param1,IntPtr param2, IntPtr param3, - /// IntPtr* param4, int32_t param4Size, IntPtr param5, intptr_t**) - /// - /// This function makes a copy of the returned string before using it. - /// - /// The nativeFreeFunction signature should be UInt32_t Func(IntPtr*) - /// The nativeFreeFunction will be called to let the native layer know it can free the memory allocated to the parameter. - /// - /// - /// - /// - /// - /// - /// - /// - /// - public unsafe static string CallNative_NStringFunction_Parameter_NString_NString_NInt_ArrayString_Int_NString( - IntPtr nativeFunction, - IntPtr* nativeContext, - string? stringParam1, - string? stringParam2, - int? intParam3, - IEnumerable enumerableParam4, - string? stringParam5, - IntPtr nativeFreeFunction - ) - { - // This free frees up the memory created in native callback. - var nativeFreeFunc = Marshal.GetDelegateForFunctionPointer(nativeFreeFunction); - UInt32 result = 0; - IntPtr nativeStringOut = IntPtr.Zero; - String? marshaledString = null; - try - { - var nativeFunc = Marshal.GetDelegateForFunctionPointer(nativeFunction); - var nativeString1 = stringParam1 != null ? Utf8StringMarshaler.MarshalManagedToNative(stringParam1) : IntPtr.Zero; - var nativeString2 = stringParam2 != null ? Utf8StringMarshaler.MarshalManagedToNative(stringParam2) : IntPtr.Zero; - var nativeString5 = stringParam5 != null ? Utf8StringMarshaler.MarshalManagedToNative(stringParam5) : IntPtr.Zero; - IntPtr intPtr = IntPtr.Zero; - if (intParam3 != null) - { - intPtr = Marshal.AllocHGlobal(sizeof(int)); - Marshal.WriteInt32(intPtr, (int)intParam3); - } - - Int32 arrayCount = enumerableParam4.Count(); - - // Calculate the size of the pointer array - int pointerArraySize = arrayCount * Marshal.SizeOf(typeof(IntPtr)); - - // Calculate the size of the string data - int stringDataSize = 0; - foreach (string str in enumerableParam4) - { - // Add the size of the string plus one for the null terminator - stringDataSize += Encoding.UTF8.GetByteCount(str) + 1; - } - - // Calculate the total size - int totalSize = pointerArraySize + stringDataSize; - - // Allocate the memory - IntPtr arrayPtr = Marshal.AllocHGlobal(totalSize); - // Write the string data and pointers - int offset = 0; - var arrayParamArray = enumerableParam4.ToArray(); - for (int i = 0; i < arrayCount; i++) - { - // Write the pointer to the current string - IntPtr stringPtr = IntPtr.Add(arrayPtr, pointerArraySize + offset); - Marshal.WriteIntPtr(arrayPtr, i * Marshal.SizeOf(typeof(IntPtr)), stringPtr); - - // Write the string data - byte[] stringData = Encoding.UTF8.GetBytes(arrayParamArray[i]); - Marshal.Copy(stringData, 0, stringPtr, stringData.Length); - offset += stringData.Length; - - // Write the null terminator - Marshal.WriteByte(IntPtr.Add(stringPtr, stringData.Length), 0); - offset += 1; - } - result = nativeFunc(nativeContext, nativeString1, nativeString2, intPtr, arrayPtr, (IntPtr)arrayCount, nativeString5, & nativeStringOut); - - if (result != 0) - { - throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); - } - marshaledString = Marshal.PtrToStringUTF8(nativeStringOut); - - Marshal.FreeHGlobal(nativeString1); - Marshal.FreeHGlobal(nativeString2); - Marshal.FreeHGlobal(nativeString5); - Marshal.FreeHGlobal(arrayPtr); - if (intPtr != IntPtr.Zero) - { - Marshal.FreeHGlobal(intPtr); - } - } - finally - { - if (nativeStringOut != IntPtr.Zero) - { - result = nativeFreeFunc(nativeStringOut); - if (result != 0) - { - throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); - } - } - } - return marshaledString ?? ""; - } - - /// - /// Calls the native function with the context,byte [], size of buffer - /// and expects an int as a result. - /// - /// Function signature should be char * Func(IntPtr*, IntPtr param1,IntPtr param2) - /// - /// - /// - /// - /// A buffer allocated in managed code. - /// - internal unsafe static int CallNativeIntFunctionWithByteArrayIntParameter(IntPtr nativeFunction, IntPtr* nativeContext, byte[] buffer, uint size) - { - UInt32 result = 0; - IntPtr nativeIntOut = Marshal.AllocHGlobal(sizeof(int)); - int toReturn = 0; - GCHandle nativeBufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned); - IntPtr nativeBufferPtr = nativeBufferHandle.AddrOfPinnedObject(); - IntPtr inIntPtr = Marshal.AllocHGlobal(sizeof(uint)); - try - { - Marshal.WriteInt32(inIntPtr, (int)size); - var nativeFunc = Marshal.GetDelegateForFunctionPointer(nativeFunction); - result = nativeFunc(nativeContext, nativeBufferPtr, inIntPtr, nativeIntOut); - if (result != 0) - { - throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); - } - if (nativeIntOut != IntPtr.Zero) - { - toReturn = Marshal.ReadInt32(nativeIntOut); - } - } - finally - { - if (nativeIntOut != IntPtr.Zero) - { - Marshal.FreeHGlobal(nativeIntOut); - } - Marshal.FreeHGlobal(inIntPtr); - nativeBufferHandle.Free(); - } - return toReturn; - } - } -} + +using Jint.Runtime; +using Microsoft.Identity.Client; +using Microsoft.VisualBasic; +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace macaroni_api_c.Internal +{ + internal static class InteropFunctions + { + private unsafe delegate UInt32 nativeVoidFunction(IntPtr* context); + private unsafe delegate UInt32 nativeVoidFunctionOneParam(IntPtr* context, IntPtr param); + private unsafe delegate UInt32 nativeVoidFunctionTwoParam(IntPtr* context, IntPtr param1, IntPtr param2); + private unsafe delegate UInt32 nativeVoidFunctionThreeParam(IntPtr* context, IntPtr param1, IntPtr param2, IntPtr param3); + private unsafe delegate UInt32 nativeVoidFunctionFourParam(IntPtr* context, IntPtr param1, IntPtr param2, IntPtr param3, IntPtr param4); + + private unsafe delegate UInt32 nativeIntFunction_In_Zero_Out_One(IntPtr* context, IntPtr * outParam); + private unsafe delegate UInt32 nativeIntFunction_In_One_Out_One(IntPtr* context, IntPtr inParam, IntPtr* outParam); + private unsafe delegate UInt32 nativeIntFunction_In_Two_Out_One(IntPtr* context, IntPtr inParam1, IntPtr inParam2, IntPtr outParam); + private unsafe delegate UInt32 nativeIntFunction_In_Three_Out_One(IntPtr* context, IntPtr inParam1, IntPtr inParam2, IntPtr inParam3, IntPtr* outParam); + private unsafe delegate UInt32 nativeIntFunction_In_Four_Out_One(IntPtr* context, IntPtr inParam1, IntPtr inParam2, IntPtr inParam3, IntPtr inParam4, IntPtr* outParam); + private unsafe delegate UInt32 nativeIntFunction_In_Six_Out_One(IntPtr* context, IntPtr inParam1, IntPtr inParam2, IntPtr inParam3, IntPtr inParam4, IntPtr inParam5, IntPtr inParam6, IntPtr* outParam); + + private unsafe delegate UInt32 nativeFreeFunction(IntPtr nativeMemToFree); + + /// + /// Calls the native function with the context and expects no result. + /// + /// Function signature should be void Func(IntPtr*) + /// + /// + /// + public unsafe static void CallNativeVoidFunction(IntPtr nativeFunction, IntPtr* nativeContext) + { + var nativeFunc = Marshal.GetDelegateForFunctionPointer(nativeFunction); + nativeFunc(nativeContext); + } + + /// + /// Calls the native function with the context, a null terminated char[], and expects no result. + /// + /// Function signature should be void Func(IntPtr*, IntPtr) + /// + /// Native function must be synchronous or corruption could occur. + /// + /// + /// + /// + public unsafe static void CallNativeVoidFunctionWithStringParameter(IntPtr nativeFunction, IntPtr* nativeContext, string? stringParam) + { + var nativeFunc = Marshal.GetDelegateForFunctionPointer(nativeFunction); + var nativeHandle = Utf8StringMarshaler.MarshalManagedToNative(stringParam ?? ""); + try + { + var result = nativeFunc(nativeContext, nativeHandle); + if (result != 0) + { + throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); + } + } + finally + { + Marshal.FreeHGlobal(nativeHandle); + } + } + + /// + /// Calls the native function with the context, a null terminated char[], a null terminated char[], and expects no result. + /// + /// Function signature should be void Func(IntPtr*, IntPtr, IntPtr) + /// + /// Native function must be synchronous or corruption could occur. + /// + /// + /// + /// + /// + public unsafe static void CallNativeVoidFunctionWithStringNullStringParameter(IntPtr nativeFunction, IntPtr* nativeContext, string stringParam1, string? stringParam2) + { + var nativeFunc = Marshal.GetDelegateForFunctionPointer(nativeFunction); + var nativeString1 = Utf8StringMarshaler.MarshalManagedToNative(stringParam1); + var nativeString2 = stringParam2 != null ? Utf8StringMarshaler.MarshalManagedToNative(stringParam2) : IntPtr.Zero; + try + { + var result = nativeFunc(nativeContext, nativeString1, nativeString2); + if (result != 0) + { + throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); + } + } + finally + { + Marshal.FreeHGlobal(nativeString1); + Marshal.FreeHGlobal(nativeString2); + } + } + + /// + /// Calls the native function with the context, a null terminated char[], int, and expects no result. + /// + /// Function signature should be void Func(IntPtr*, IntPtr, int) + /// + /// Native function must be synchronous or corruption could occur. + /// + /// + /// + /// + /// + public unsafe static void CallNativeVoidFunctionWithStringIntParameter(IntPtr nativeFunction, IntPtr* nativeContext, string stringParam1, int intParam2) + { + var nativeFunc = Marshal.GetDelegateForFunctionPointer(nativeFunction); + var nativeString1 = Utf8StringMarshaler.MarshalManagedToNative(stringParam1); + try + { + var result = nativeFunc(nativeContext, nativeString1, (IntPtr)intParam2); + if (result != 0) + { + throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); + } + } + finally + { + Marshal.FreeHGlobal(nativeString1); + } + } + + /// + /// Calls the native function with the context, int and expects no result. + /// + /// Function signature should be void Func(IntPtr*, int) + /// + /// Native function must be synchronous or corruption could occur. + /// + /// + /// + /// + internal static unsafe void CallNativeVoidFunctionWithIntParameter(IntPtr nativeFunction, IntPtr* nativeContext, int intParam1) + { + var nativeFunc = Marshal.GetDelegateForFunctionPointer(nativeFunction); + try + { + var result = nativeFunc(nativeContext, (IntPtr)intParam1); + if (result != 0) + { + throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); + } + } + finally + { + } + } + + /// + /// Calls the native function with the context, int, int, and expects no result. + /// + /// Function signature should be void Func(IntPtr*, int, int) + /// + /// Native function must be synchronous or corruption could occur. + /// + /// + /// + /// + /// + public unsafe static void CallNativeVoidFunctionWithIntIntParameter(IntPtr nativeFunction, IntPtr* nativeContext, int intParam1, int intParam2) + { + var nativeFunc = Marshal.GetDelegateForFunctionPointer(nativeFunction); + try + { + var result = nativeFunc(nativeContext, (IntPtr)intParam1, (IntPtr)intParam2); + if (result != 0) + { + throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); + } + } + finally + { + } + } + + /// + /// Calls the native function with the context, a null terminated char[], a null terminated char[], int, and expects no result. + /// + /// Function signature should be void Func(IntPtr*, IntPtr, IntPtr, int) + /// + /// Native function must be synchronous or corruption could occur. + /// + /// + /// + /// + /// + /// + public unsafe static void CallNativeVoidFunctionWithStringNullStringNullIntParameter( + IntPtr nativeFunction, + IntPtr* nativeContext, + string stringParam1, + string? stringParam2, + int? intParam3 + ) + { + var nativeFunc = Marshal.GetDelegateForFunctionPointer(nativeFunction); + var nativeString1 = Utf8StringMarshaler.MarshalManagedToNative(stringParam1); + var nativeString2 = stringParam2 != null ? Utf8StringMarshaler.MarshalManagedToNative(stringParam2) : IntPtr.Zero; + IntPtr intPtr = IntPtr.Zero; + if (intParam3 != null) + { + intPtr = Marshal.AllocHGlobal(sizeof(int)); + Marshal.WriteInt32(intPtr, (int)intParam3); + } + try + { + var result = nativeFunc(nativeContext, nativeString1, nativeString2, intPtr); + if (result != 0) + { + throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); + } + } + finally + { + Marshal.FreeHGlobal(nativeString1); + Marshal.FreeHGlobal(nativeString2); + if (intPtr != IntPtr.Zero) + { + Marshal.FreeHGlobal(intPtr); + } + } + } + + /// + /// Calls the native function with the context, a null terminated char[], a null terminated char[], int, and expects no result. + /// + /// Function signature should be void Func(IntPtr*, IntPtr, IntPtr, int) + /// + /// Native function must be synchronous or corruption could occur. + /// + /// We don't need a free function since Bool is stored in the IntPtr itself. + /// + /// + /// + /// + /// + /// + public unsafe static bool CallNativeBoolFunctionWithStringNullStringNullIntParameter( + IntPtr nativeFunction, + IntPtr* nativeContext, + string stringParam1, + string? stringParam2, + int? intParam3 + ) + { + var nativeFunc = Marshal.GetDelegateForFunctionPointer(nativeFunction); + UInt32 result = 0; + IntPtr nativeBoolOut = IntPtr.Zero; + bool marshaledBool = false; + var nativeString1 = Utf8StringMarshaler.MarshalManagedToNative(stringParam1); + var nativeString2 = stringParam2 != null ? Utf8StringMarshaler.MarshalManagedToNative(stringParam2) : IntPtr.Zero; + IntPtr intPtr = IntPtr.Zero; + if (intParam3 != null) + { + intPtr = Marshal.AllocHGlobal(sizeof(int)); + Marshal.WriteInt32(intPtr, (int)intParam3); + } + try + { + + result = nativeFunc(nativeContext, nativeString1, nativeString2, intPtr, &nativeBoolOut); + if (result != 0) + { + throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); + } + } + finally + { + Marshal.FreeHGlobal(nativeString1); + Marshal.FreeHGlobal(nativeString2); + if (intPtr != IntPtr.Zero) + { + Marshal.FreeHGlobal(intPtr); + } + } + return marshaledBool; + } + + /// + /// Calls the native function with the context, a null terminated char[], a null terminated char[], a null terminated char[], + /// int, and expects no result. + /// + /// Function signature should be void Func(IntPtr*, IntPtr, IntPtr, IntPtr, int) + /// + /// Native function must be synchronous or corruption could occur. + /// + /// + /// + /// + /// + /// + /// + public unsafe static void CallNativeVoidFunctionWithStringStringNullBoolIntParameter( + IntPtr nativeFunction, + IntPtr* nativeContext, + string stringParam1, + string stringParam2, + bool? boolParam3, + int intParam4 + ) + { + var nativeFunc = Marshal.GetDelegateForFunctionPointer(nativeFunction); + var nativeString1 = Utf8StringMarshaler.MarshalManagedToNative(stringParam1); + var nativeString2 = Utf8StringMarshaler.MarshalManagedToNative(stringParam2); + IntPtr boolPtr = IntPtr.Zero; + if (boolParam3!= null) + { + boolPtr = Marshal.AllocHGlobal(1); + Marshal.WriteByte(boolPtr, (byte)((bool)boolParam3 ? 1 : 0)); + } + try + { + nativeFunc(nativeContext, nativeString1, nativeString2, boolPtr, (IntPtr)(intParam4)); + } + finally + { + Marshal.FreeHGlobal(nativeString1); + Marshal.FreeHGlobal(nativeString2); + if (boolPtr != IntPtr.Zero) + { + Marshal.FreeHGlobal(boolPtr); + } + } + } + + /// + /// Calls the native function with the context and expects a null terminated char[] to be assigned to the second parameter. + /// + /// A UInt32 as a result. + /// + /// The nativeFunction signature should be UInt32_t Func(IntPtr*, IntPtr**) + /// + /// The nativeFreeFunction signature should be UInt32_t Func(IntPtr*) + /// The nativeFreeFunction will be called to let the native layer know it can free the memory allocated to the parameter. + /// + /// This function makes a copy of the returned string before using it. + /// + /// + /// + /// + /// + public unsafe static string? CallNativeNullStringFunction(IntPtr nativeFunction, IntPtr* nativeContext, IntPtr nativeFreeFunction) + { + // This free frees up the memory created in native callback. + var nativeFreeFunc = Marshal.GetDelegateForFunctionPointer(nativeFreeFunction); + UInt32 result = 0; + IntPtr nativeString = IntPtr.Zero; + String? marshaledString = null; + try + { + var nativeFunc = Marshal.GetDelegateForFunctionPointer(nativeFunction); + + result = nativeFunc(nativeContext, &nativeString); + if (result != 0) + { + throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); + } + + marshaledString = Marshal.PtrToStringUTF8(nativeString); + + } + finally + { + if (nativeString != IntPtr.Zero) + { + result = nativeFreeFunc(nativeString); + if (result != 0) + { + throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); + } + } + } + + return marshaledString; + } + + /// + /// Calls the native function with the context and expects a null terminated char[] to be assigned to the third parameter. + /// + /// A UInt32 as a result. + /// + /// The nativeFunction signature should be UInt32_t Func(IntPtr*, IntPtr*, IntPtr**) + /// + /// The nativeFreeFunction signature should be UInt32_t Func(IntPtr*) + /// The nativeFreeFunction will be called to let the native layer know it can free the memory allocated to the parameter. + /// + /// This function makes a copy of the returned string before using it. + /// + /// + /// + /// + /// A String to pass to the native function. + /// + public unsafe static string? CallNativeNullStringFunctionWithStringParameter( + IntPtr nativeFunction, IntPtr* nativeContext, IntPtr nativeFreeFunction, string param) + { + // This free frees up the memory created in native callback. + var nativeFreeFunc = Marshal.GetDelegateForFunctionPointer(nativeFreeFunction); + UInt32 result = 0; + IntPtr nativeStringOut = IntPtr.Zero; + String? marshaledString = null; + try + { + var nativeFunc = Marshal.GetDelegateForFunctionPointer(nativeFunction); + var nativeString1 = Utf8StringMarshaler.MarshalManagedToNative(param ?? ""); + result = nativeFunc(nativeContext, nativeString1, &nativeStringOut); + if (result != 0) + { + throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); + } + + marshaledString = Marshal.PtrToStringUTF8(nativeStringOut); + Marshal.FreeHGlobal(nativeString1); + + } + finally + { + if (nativeStringOut != IntPtr.Zero) + { + result = nativeFreeFunc(nativeStringOut); + if (result != 0) + { + throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); + } + } + } + + return marshaledString; + } + + /// + /// Calls the native function with the context, null terminated char [], null terminated char [], null terminated char [], + /// int, and expects a null terminated char[] as a result. + /// + /// Function signature should be char * Func(IntPtr*, IntPtr, IntPtr, IntPtr, int) + /// + /// This function makes a copy of the returned string before using it. + /// + /// The nativeFreeFunction signature should be UInt32_t Func(IntPtr*) + /// The nativeFreeFunction will be called to let the native layer know it can free the memory allocated to the parameter. + /// + /// + /// + /// + /// + /// + /// + /// + public unsafe static string CallNativeNullStringFunctionWithStringNullStringNullStringNullIntParameter( + IntPtr nativeFunction, + IntPtr* nativeContext, + string stringParam1, + string? stringParam2, + string? stringParam3, + int? intParam4, + IntPtr nativeFreeFunction + ) + { + // This free frees up the memory created in native callback. + var nativeFreeFunc = Marshal.GetDelegateForFunctionPointer(nativeFreeFunction); + UInt32 result = 0; + IntPtr nativeStringOut = IntPtr.Zero; + String? marshaledString = null; + try + { + var nativeFunc = Marshal.GetDelegateForFunctionPointer(nativeFunction); + var nativeString1 = Utf8StringMarshaler.MarshalManagedToNative(stringParam1); + var nativeString2 = stringParam2 != null ? Utf8StringMarshaler.MarshalManagedToNative(stringParam2) : IntPtr.Zero; + var nativeString3 = stringParam3 != null ? Utf8StringMarshaler.MarshalManagedToNative(stringParam3) : IntPtr.Zero; + IntPtr intPtr = IntPtr.Zero; + if (intParam4 != null) + { + intPtr = Marshal.AllocHGlobal(sizeof(int)); + Marshal.WriteInt32(intPtr, (int)intParam4); + } + result = nativeFunc(nativeContext, nativeString1, nativeString2, nativeString3, intPtr, &nativeStringOut); + + if (result != 0) + { + throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); + } + marshaledString = Marshal.PtrToStringUTF8(nativeStringOut); + + Marshal.FreeHGlobal(nativeString1); + Marshal.FreeHGlobal(nativeString2); + Marshal.FreeHGlobal(nativeString3); + } + finally + { + if (nativeStringOut != IntPtr.Zero) + { + result = nativeFreeFunc(nativeStringOut); + if (result != 0) + { + throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); + } + } + } + return marshaledString ?? ""; + } + + /// + /// Calls the native function with the context, null terminated char [], null terminated char [], a nullable int, + /// an array of null terminated char [], number of entries in the array, a null terminated char [] + /// and expects a null terminated char[] as a result. + /// + /// Function signature should be char * Func(IntPtr*, IntPtr param1,IntPtr param2, IntPtr param3, + /// IntPtr* param4, int32_t param4Size, IntPtr param5, intptr_t**) + /// + /// This function makes a copy of the returned string before using it. + /// + /// The nativeFreeFunction signature should be UInt32_t Func(IntPtr*) + /// The nativeFreeFunction will be called to let the native layer know it can free the memory allocated to the parameter. + /// + /// + /// + /// + /// + /// + /// + /// + /// + public unsafe static string CallNative_NStringFunction_Parameter_NString_NString_NInt_ArrayString_Int_NString( + IntPtr nativeFunction, + IntPtr* nativeContext, + string? stringParam1, + string? stringParam2, + int? intParam3, + IEnumerable enumerableParam4, + string? stringParam5, + IntPtr nativeFreeFunction + ) + { + // This free frees up the memory created in native callback. + var nativeFreeFunc = Marshal.GetDelegateForFunctionPointer(nativeFreeFunction); + UInt32 result = 0; + IntPtr nativeStringOut = IntPtr.Zero; + String? marshaledString = null; + try + { + var nativeFunc = Marshal.GetDelegateForFunctionPointer(nativeFunction); + var nativeString1 = stringParam1 != null ? Utf8StringMarshaler.MarshalManagedToNative(stringParam1) : IntPtr.Zero; + var nativeString2 = stringParam2 != null ? Utf8StringMarshaler.MarshalManagedToNative(stringParam2) : IntPtr.Zero; + var nativeString5 = stringParam5 != null ? Utf8StringMarshaler.MarshalManagedToNative(stringParam5) : IntPtr.Zero; + IntPtr intPtr = IntPtr.Zero; + if (intParam3 != null) + { + intPtr = Marshal.AllocHGlobal(sizeof(int)); + Marshal.WriteInt32(intPtr, (int)intParam3); + } + + Int32 arrayCount = enumerableParam4.Count(); + + // Calculate the size of the pointer array + int pointerArraySize = arrayCount * Marshal.SizeOf(typeof(IntPtr)); + + // Calculate the size of the string data + int stringDataSize = 0; + foreach (string str in enumerableParam4) + { + // Add the size of the string plus one for the null terminator + stringDataSize += Encoding.UTF8.GetByteCount(str) + 1; + } + + // Calculate the total size + int totalSize = pointerArraySize + stringDataSize; + + // Allocate the memory + IntPtr arrayPtr = Marshal.AllocHGlobal(totalSize); + // Write the string data and pointers + int offset = 0; + var arrayParamArray = enumerableParam4.ToArray(); + for (int i = 0; i < arrayCount; i++) + { + // Write the pointer to the current string + IntPtr stringPtr = IntPtr.Add(arrayPtr, pointerArraySize + offset); + Marshal.WriteIntPtr(arrayPtr, i * Marshal.SizeOf(typeof(IntPtr)), stringPtr); + + // Write the string data + byte[] stringData = Encoding.UTF8.GetBytes(arrayParamArray[i]); + Marshal.Copy(stringData, 0, stringPtr, stringData.Length); + offset += stringData.Length; + + // Write the null terminator + Marshal.WriteByte(IntPtr.Add(stringPtr, stringData.Length), 0); + offset += 1; + } + result = nativeFunc(nativeContext, nativeString1, nativeString2, intPtr, arrayPtr, (IntPtr)arrayCount, nativeString5, & nativeStringOut); + + if (result != 0) + { + throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); + } + marshaledString = Marshal.PtrToStringUTF8(nativeStringOut); + + Marshal.FreeHGlobal(nativeString1); + Marshal.FreeHGlobal(nativeString2); + Marshal.FreeHGlobal(nativeString5); + Marshal.FreeHGlobal(arrayPtr); + if (intPtr != IntPtr.Zero) + { + Marshal.FreeHGlobal(intPtr); + } + } + finally + { + if (nativeStringOut != IntPtr.Zero) + { + result = nativeFreeFunc(nativeStringOut); + if (result != 0) + { + throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); + } + } + } + return marshaledString ?? ""; + } + + /// + /// Calls the native function with the context,byte [], size of buffer + /// and expects an int as a result. + /// + /// Function signature should be char * Func(IntPtr*, IntPtr param1,IntPtr param2) + /// + /// + /// + /// + /// A buffer allocated in managed code. + /// + internal unsafe static int CallNativeIntFunctionWithByteArrayIntParameter(IntPtr nativeFunction, IntPtr* nativeContext, byte[] buffer, uint size) + { + UInt32 result = 0; + IntPtr nativeIntOut = Marshal.AllocHGlobal(sizeof(int)); + int toReturn = 0; + GCHandle nativeBufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned); + IntPtr nativeBufferPtr = nativeBufferHandle.AddrOfPinnedObject(); + IntPtr inIntPtr = Marshal.AllocHGlobal(sizeof(uint)); + try + { + Marshal.WriteInt32(inIntPtr, (int)size); + var nativeFunc = Marshal.GetDelegateForFunctionPointer(nativeFunction); + result = nativeFunc(nativeContext, nativeBufferPtr, inIntPtr, nativeIntOut); + if (result != 0) + { + throw new Exception($"NativeException: {result} {((MAPICodes)result).ToString()}"); + } + if (nativeIntOut != IntPtr.Zero) + { + toReturn = Marshal.ReadInt32(nativeIntOut); + } + } + finally + { + if (nativeIntOut != IntPtr.Zero) + { + Marshal.FreeHGlobal(nativeIntOut); + } + Marshal.FreeHGlobal(inIntPtr); + nativeBufferHandle.Free(); + } + return toReturn; + } + } +} diff --git a/src/macaroni_api_c/InteropUTF8StringMarshaler.cs b/src/macaroni_api_c/InteropUTF8StringMarshaler.cs index 2a4eeedb..067a044b 100644 --- a/src/macaroni_api_c/InteropUTF8StringMarshaler.cs +++ b/src/macaroni_api_c/InteropUTF8StringMarshaler.cs @@ -3,8 +3,8 @@ // Licensed under the MIT license. See LICENSE.md file in the project root for full license information. // -using System.Text; using System.Runtime.InteropServices; +using System.Text; namespace macaroni_api_c { diff --git a/src/macaroni_api_c/MAPICodes.cs b/src/macaroni_api_c/MAPICodes.cs index 2812d715..c559292d 100644 --- a/src/macaroni_api_c/MAPICodes.cs +++ b/src/macaroni_api_c/MAPICodes.cs @@ -15,87 +15,87 @@ public enum MAPICodes /// /// The function is not implemented. /// - AZAC_ERR_NOT_IMPL = 0xFFF, + AZAC_ERR_NOT_IMPL = 0xFFF, /// /// The object has not been properly initialized. /// - AZAC_ERR_UNINITIALIZED = 0x001, + AZAC_ERR_UNINITIALIZED = 0x001, /// /// The object has already been initialized. /// - AZAC_ERR_ALREADY_INITIALIZED = 0x002, + AZAC_ERR_ALREADY_INITIALIZED = 0x002, /// /// An unhandled exception was detected. /// - AZAC_ERR_UNHANDLED_EXCEPTION = 0x003, + AZAC_ERR_UNHANDLED_EXCEPTION = 0x003, /// /// The object or property was not found. /// - AZAC_ERR_NOT_FOUND = 0x004, + AZAC_ERR_NOT_FOUND = 0x004, /// /// One or more arguments are not valid. /// - AZAC_ERR_INVALID_ARG = 0x005, + AZAC_ERR_INVALID_ARG = 0x005, /// /// The specified timeout value has elapsed. /// - AZAC_ERR_TIMEOUT = 0x006, + AZAC_ERR_TIMEOUT = 0x006, /// /// The asynchronous operation is already in progress. /// - AZAC_ERR_ALREADY_IN_PROGRESS = 0x007, + AZAC_ERR_ALREADY_IN_PROGRESS = 0x007, /// /// The attempt to open the file failed. /// - AZAC_ERR_FILE_OPEN_FAILED = 0x008, + AZAC_ERR_FILE_OPEN_FAILED = 0x008, /// /// The end of the file was reached unexpectedly. /// - AZAC_ERR_UNEXPECTED_EOF = 0x009, + AZAC_ERR_UNEXPECTED_EOF = 0x009, /// /// Invalid audio header encountered. /// - AZAC_ERR_INVALID_HEADER = 0x00a, + AZAC_ERR_INVALID_HEADER = 0x00a, /// /// The requested operation cannot be performed while audio is pumping /// - AZAC_ERR_AUDIO_IS_PUMPING = 0x00b, + AZAC_ERR_AUDIO_IS_PUMPING = 0x00b, /// /// Unsupported audio format. /// - AZAC_ERR_UNSUPPORTED_FORMAT = 0x00c, + AZAC_ERR_UNSUPPORTED_FORMAT = 0x00c, /// /// Operation aborted. /// - AZAC_ERR_ABORT = 0x00d, + AZAC_ERR_ABORT = 0x00d, /// /// Microphone is not available. /// - AZAC_ERR_MIC_NOT_AVAILABLE = 0x00e, + AZAC_ERR_MIC_NOT_AVAILABLE = 0x00e, /// /// An invalid state was encountered. /// - AZAC_ERR_INVALID_STATE = 0x00f, + AZAC_ERR_INVALID_STATE = 0x00f, /// /// Attempting to create a UUID failed. /// - AZAC_ERR_UUID_CREATE_FAILED = 0x010, + AZAC_ERR_UUID_CREATE_FAILED = 0x010, /// /// An unexpected session state transition was encountered when setting the session audio format. @@ -107,7 +107,7 @@ public enum MAPICodes /// * ProcessingAudio --> WaitForAdapterCompletedSetFormatStop (when the stream runs out of data) /// All other state transitions are invalid. /// - AZAC_ERR_SETFORMAT_UNEXPECTED_STATE_TRANSITION = 0x011, + AZAC_ERR_SETFORMAT_UNEXPECTED_STATE_TRANSITION = 0x011, /// /// An unexpected session state was encountered in while processing audio. @@ -118,7 +118,7 @@ public enum MAPICodes /// * StoppingPump: We're allowed to be called to process audio, but we'll ignore the data passed in while we're attempting to stop the pump. /// All other states are invalid while processing audio. /// - AZAC_ERR_PROCESS_AUDIO_INVALID_STATE = 0x012, + AZAC_ERR_PROCESS_AUDIO_INVALID_STATE = 0x012, /// /// An unexpected state transition was encountered while attempting to start recognizing. @@ -128,303 +128,303 @@ public enum MAPICodes /// * Idle --> WaitForPumpSetFormatStart /// All other state transitions are invalid when attempting to start recognizing /// - AZAC_ERR_START_RECOGNIZING_INVALID_STATE_TRANSITION = 0x013, + AZAC_ERR_START_RECOGNIZING_INVALID_STATE_TRANSITION = 0x013, /// /// An unexpected error was encountered when trying to create an internal object. /// - AZAC_ERR_UNEXPECTED_CREATE_OBJECT_FAILURE = 0x014, + AZAC_ERR_UNEXPECTED_CREATE_OBJECT_FAILURE = 0x014, /// /// An error in the audio-capturing system. /// - AZAC_ERR_MIC_ERROR = 0x015, + AZAC_ERR_MIC_ERROR = 0x015, /// /// The requested operation cannot be performed, there is no audio input. /// - AZAC_ERR_NO_AUDIO_INPUT = 0x016, + AZAC_ERR_NO_AUDIO_INPUT = 0x016, /// /// An unexpected error was encountered when trying to access the USP site. /// - AZAC_ERR_UNEXPECTED_USP_SITE_FAILURE = 0x017, + AZAC_ERR_UNEXPECTED_USP_SITE_FAILURE = 0x017, /// /// An unexpected error was encountered when trying to access the LU site. /// - AZAC_ERR_UNEXPECTED_LU_SITE_FAILURE = 0x018, + AZAC_ERR_UNEXPECTED_LU_SITE_FAILURE = 0x018, /// /// The buffer is too small. /// - AZAC_ERR_BUFFER_TOO_SMALL = 0x019, + AZAC_ERR_BUFFER_TOO_SMALL = 0x019, /// /// A method failed to allocate memory. /// - AZAC_ERR_OUT_OF_MEMORY = 0x01A, + AZAC_ERR_OUT_OF_MEMORY = 0x01A, /// /// An unexpected runtime error occurred. /// - AZAC_ERR_RUNTIME_ERROR = 0x01B, + AZAC_ERR_RUNTIME_ERROR = 0x01B, /// /// The url specified is invalid. /// - AZAC_ERR_INVALID_URL = 0x01C, + AZAC_ERR_INVALID_URL = 0x01C, /// /// The region specified is invalid or missing. /// - AZAC_ERR_INVALID_REGION = 0x01D, + AZAC_ERR_INVALID_REGION = 0x01D, /// /// Switch between single shot and continuous recognition is not supported. /// - AZAC_ERR_SWITCH_MODE_NOT_ALLOWED = 0x01E, + AZAC_ERR_SWITCH_MODE_NOT_ALLOWED = 0x01E, /// /// Changing connection status is not supported in the current recognition state. /// - AZAC_ERR_CHANGE_CONNECTION_STATUS_NOT_ALLOWED = 0x01F, + AZAC_ERR_CHANGE_CONNECTION_STATUS_NOT_ALLOWED = 0x01F, /// /// Explicit connection management is not supported by the specified recognizer. /// - AZAC_ERR_EXPLICIT_CONNECTION_NOT_SUPPORTED_BY_RECOGNIZER = 0x020, + AZAC_ERR_EXPLICIT_CONNECTION_NOT_SUPPORTED_BY_RECOGNIZER = 0x020, /// /// The handle is invalid. /// - AZAC_ERR_INVALID_HANDLE = 0x021, + AZAC_ERR_INVALID_HANDLE = 0x021, /// /// The recognizer is invalid. /// - AZAC_ERR_INVALID_RECOGNIZER = 0x022, + AZAC_ERR_INVALID_RECOGNIZER = 0x022, /// /// The value is out of range. /// Added in version 1.3.0. /// - AZAC_ERR_OUT_OF_RANGE = 0x023, + AZAC_ERR_OUT_OF_RANGE = 0x023, /// /// Extension library not found. /// Added in version 1.3.0. /// - AZAC_ERR_EXTENSION_LIBRARY_NOT_FOUND = 0x024, + AZAC_ERR_EXTENSION_LIBRARY_NOT_FOUND = 0x024, /// /// An unexpected error was encountered when trying to access the TTS engine site. /// Added in version 1.4.0. /// - AZAC_ERR_UNEXPECTED_TTS_ENGINE_SITE_FAILURE = 0x025, + AZAC_ERR_UNEXPECTED_TTS_ENGINE_SITE_FAILURE = 0x025, /// /// An unexpected error was encountered when trying to access the audio output stream. /// Added in version 1.4.0. /// - AZAC_ERR_UNEXPECTED_AUDIO_OUTPUT_FAILURE = 0x026, + AZAC_ERR_UNEXPECTED_AUDIO_OUTPUT_FAILURE = 0x026, /// /// Gstreamer internal error. /// Added in version 1.4.0. /// - AZAC_ERR_GSTREAMER_INTERNAL_ERROR = 0x027, + AZAC_ERR_GSTREAMER_INTERNAL_ERROR = 0x027, /// /// Compressed container format not supported. /// Added in version 1.4.0. /// - AZAC_ERR_CONTAINER_FORMAT_NOT_SUPPORTED_ERROR = 0x028, + AZAC_ERR_CONTAINER_FORMAT_NOT_SUPPORTED_ERROR = 0x028, /// /// Codec extension or gstreamer not found. /// Added in version 1.4.0. /// - AZAC_ERR_GSTREAMER_NOT_FOUND_ERROR = 0x029, + AZAC_ERR_GSTREAMER_NOT_FOUND_ERROR = 0x029, /// /// The language specified is missing. /// Added in version 1.5.0. /// - AZAC_ERR_INVALID_LANGUAGE = 0x02A, + AZAC_ERR_INVALID_LANGUAGE = 0x02A, /// /// The API is not applicable. /// Added in version 1.5.0. /// - AZAC_ERR_UNSUPPORTED_API_ERROR = 0x02B, + AZAC_ERR_UNSUPPORTED_API_ERROR = 0x02B, /// /// The ring buffer is unavailable. /// Added in version 1.8.0. /// - AZAC_ERR_RINGBUFFER_DATA_UNAVAILABLE = 0x02C, + AZAC_ERR_RINGBUFFER_DATA_UNAVAILABLE = 0x02C, /// /// An unexpected error was encountered when trying to access the Conversation site. /// Added in version 1.5.0. /// - AZAC_ERR_UNEXPECTED_CONVERSATION_SITE_FAILURE = 0x030, + AZAC_ERR_UNEXPECTED_CONVERSATION_SITE_FAILURE = 0x030, /// /// An unexpected error was encountered when trying to access the Conversation site. /// Added in version 1.8.0. /// - AZAC_ERR_UNEXPECTED_CONVERSATION_TRANSLATOR_SITE_FAILURE = 0x031, + AZAC_ERR_UNEXPECTED_CONVERSATION_TRANSLATOR_SITE_FAILURE = 0x031, /// /// An asynchronous operation was canceled before it was executed. /// Added in version 1.8.0. /// - AZAC_ERR_CANCELED = 0x032, + AZAC_ERR_CANCELED = 0x032, /// /// Codec for compression could not be initialized. /// Added in version 1.10.0. /// - AZAC_ERR_COMPRESS_AUDIO_CODEC_INITIFAILED = 0x033, + AZAC_ERR_COMPRESS_AUDIO_CODEC_INITIFAILED = 0x033, /// /// Data not available. /// Added in version 1.10.0. /// - AZAC_ERR_DATA_NOT_AVAILABLE = 0x034, + AZAC_ERR_DATA_NOT_AVAILABLE = 0x034, /// /// Invalid result reason. /// Added in version 1.12.0 /// - AZAC_ERR_INVALID_RESULT_REASON = 0x035, + AZAC_ERR_INVALID_RESULT_REASON = 0x035, /// /// An unexpected error was encountered when trying to access the RNN-T site. /// - AZAC_ERR_UNEXPECTED_RNNT_SITE_FAILURE = 0x036, + AZAC_ERR_UNEXPECTED_RNNT_SITE_FAILURE = 0x036, /// /// Sending of a network message failed. /// - AZAC_ERR_NETWORK_SEND_FAILED = 0x037, + AZAC_ERR_NETWORK_SEND_FAILED = 0x037, /// /// Audio extension library not found. /// Added in version 1.16.0. /// - AZAC_ERR_AUDIO_SYS_LIBRARY_NOT_FOUND = 0x038, + AZAC_ERR_AUDIO_SYS_LIBRARY_NOT_FOUND = 0x038, /// /// An error in the audio-rendering system. /// Added in version 1.20.0 /// - AZAC_ERR_LOUDSPEAKER_ERROR = 0x039, + AZAC_ERR_LOUDSPEAKER_ERROR = 0x039, /// /// An unexpected error was encountered when trying to access the Vision site. /// Added in version 1.15.0. /// - AZAC_ERR_VISION_SITE_FAILURE = 0x050, + AZAC_ERR_VISION_SITE_FAILURE = 0x050, /// /// Stream number provided was invalid in the current context. /// Added in version 1.15.0. /// - AZAC_ERR_MEDIA_INVALID_STREAM = 0x060, + AZAC_ERR_MEDIA_INVALID_STREAM = 0x060, /// /// Offset required is invalid in the current context. /// Added in version 1.15.0. /// - AZAC_ERR_MEDIA_INVALID_OFFSET = 0x061, + AZAC_ERR_MEDIA_INVALID_OFFSET = 0x061, /// /// No more data is available in source. /// Added in version 1.15.0. /// - AZAC_ERR_MEDIA_NO_MORE_DATA = 0x062, + AZAC_ERR_MEDIA_NO_MORE_DATA = 0x062, /// /// Source has not been started. /// Added in version 1.15.0. /// - AZAC_ERR_MEDIA_NOT_STARTED = 0x063, + AZAC_ERR_MEDIA_NOT_STARTED = 0x063, /// /// Source has already been started. /// Added in version 1.15.0. /// - AZAC_ERR_MEDIA_ALREADY_STARTED = 0x064, + AZAC_ERR_MEDIA_ALREADY_STARTED = 0x064, /// /// Media device creation failed. /// Added in version 1.18.0. /// - AZAC_ERR_MEDIA_DEVICE_CREATION_FAILED = 0x065, + AZAC_ERR_MEDIA_DEVICE_CREATION_FAILED = 0x065, /// /// No devices of the selected category are available. /// Added in version 1.18.0. /// - AZAC_ERR_MEDIA_NO_DEVICE_AVAILABLE = 0x066, + AZAC_ERR_MEDIA_NO_DEVICE_AVAILABLE = 0x066, /// /// Enabled Voice Activity Detection while using keyword recognition is not allowed. /// - AZAC_ERR_VAD_COULD_NOT_USE_WITH_KEYWORD_RECOGNIZER = 0x067, + AZAC_ERR_VAD_COULD_NOT_USE_WITH_KEYWORD_RECOGNIZER = 0x067, /// /// The specified RecoEngineAdapter could not be created. /// - AZAC_ERR_COULD_NOT_CREATE_ENGINE_ADAPTER = 0x070, + AZAC_ERR_COULD_NOT_CREATE_ENGINE_ADAPTER = 0x070, /// /// The input file has a size of 0 bytes. /// - AZAC_ERR_INPUT_FILE_SIZE_IS_ZERO_BYTES = 0x072, + AZAC_ERR_INPUT_FILE_SIZE_IS_ZERO_BYTES = 0x072, /// /// Cannot open the input media file for reading. Does it exist? /// - AZAC_ERR_FAILED_TO_OPEN_INPUT_FILE_FOR_READING = 0x073, + AZAC_ERR_FAILED_TO_OPEN_INPUT_FILE_FOR_READING = 0x073, /// /// Failed to read from the input media file. /// - AZAC_ERR_FAILED_TO_READ_FROM_INPUT_FILE = 0x074, + AZAC_ERR_FAILED_TO_READ_FROM_INPUT_FILE = 0x074, /// /// Input media file is too large. /// - AZAC_ERR_INPUT_FILE_TOO_LARGE = 0x075, + AZAC_ERR_INPUT_FILE_TOO_LARGE = 0x075, /// /// The input URL is unsupported. It should start with `http://`, `https://` or `rtsp://`. /// - AZAC_ERR_UNSUPPORTED_URL_PROTOCOL = 0x076, + AZAC_ERR_UNSUPPORTED_URL_PROTOCOL = 0x076, /// /// The Nullable value is empty. Check HasValue() before getting the value. /// - AZAC_ERR_EMPTY_NULLABLE = 0x077, + AZAC_ERR_EMPTY_NULLABLE = 0x077, /// /// The given model version string is not in the expected format. The format /// is specified by the regular expression `^(latest|\d{4}-\d{2}-\d{2})(-preview)?$`. /// - AZAC_ERR_INVALID_MODEL_VERSION_FORMAT = 0x078, + AZAC_ERR_INVALID_MODEL_VERSION_FORMAT = 0x078, /// /// Malformed network message /// - AZAC_ERR_NETWORK_MALFORMED = 0x090, + AZAC_ERR_NETWORK_MALFORMED = 0x090, /// /// Unexpected message received /// - AZAC_ERR_NETWORK_PROTOCOL_VIOLATION = 0x091, + AZAC_ERR_NETWORK_PROTOCOL_VIOLATION = 0x091, } } diff --git a/src/macaroni_api_c/NativeCommandSystemBuilder.cs b/src/macaroni_api_c/NativeCommandSystemBuilder.cs index 7f2901fe..7fef0b54 100644 --- a/src/macaroni_api_c/NativeCommandSystemBuilder.cs +++ b/src/macaroni_api_c/NativeCommandSystemBuilder.cs @@ -404,10 +404,10 @@ public static UInt32 CommandSystemBuilder_ConfigureSecrets_UseKeyVault(IntPtr bu var uriStr = Utf8StringMarshaler.MarshalNativeToManaged(uri); var tenantIdStr = Utf8StringMarshaler.MarshalNativeToManaged(tenantId); var clientIdStr = Utf8StringMarshaler.MarshalNativeToManaged(clientId); - if (builder != default && + if (builder != default && uriStr != null && tenantIdStr != null && - clientIdStr != null + clientIdStr != null ) { builder.ConfigureSecrets(secrets => secrets.UseKeyVault(uriStr, tenantIdStr, clientIdStr)); @@ -656,7 +656,7 @@ public unsafe static UInt32 CommandSystemBuilder_ConfigureResolvers_AddResolver_ var nameStr = Utf8StringMarshaler.MarshalNativeToManaged(name); if (builder != default && nameStr != null) { - builder.ConfigureResolvers(resolvers => resolvers.AddResolver(nameStr, + builder.ConfigureResolvers(resolvers => resolvers.AddResolver(nameStr, () => { return InteropFunctions.CallNativeNullStringFunction(callbackFunction, callbackContext, nativeFreeFunction); @@ -1030,7 +1030,8 @@ public unsafe static UInt32 CommandSystemBuilder_ConfigureMedia_UseBeep(IntPtr b if (builder != default) { builder.ConfigureMedia(ui => ui.UseBeep( - (freq, duration) => { + (freq, duration) => + { InteropFunctions.CallNativeVoidFunctionWithIntIntParameter(callbackFunction, callbackContext, freq, duration); })); return (UInt32)MAPICodes.AZAC_ERR_NONE; @@ -1061,7 +1062,8 @@ public unsafe static UInt32 CommandSystemBuilder_ConfigureMedia_UsePlay(IntPtr b if (builder != default) { builder.ConfigureMedia(ui => ui.UsePlay( - (filepath, position) => { + (filepath, position) => + { InteropFunctions.CallNativeVoidFunctionWithStringIntParameter(callbackFunction, callbackContext, filepath, position); })); return (UInt32)MAPICodes.AZAC_ERR_NONE; @@ -1092,7 +1094,8 @@ public unsafe static UInt32 CommandSystemBuilder_ConfigureMedia_UsePause(IntPtr if (builder != default) { builder.ConfigureMedia(ui => ui.UsePause( - () => { + () => + { InteropFunctions.CallNativeVoidFunction(callbackFunction, callbackContext); })); return (UInt32)MAPICodes.AZAC_ERR_NONE; @@ -1123,7 +1126,8 @@ public unsafe static UInt32 CommandSystemBuilder_ConfigureMedia_UseResume(IntPtr if (builder != default) { builder.ConfigureMedia(ui => ui.UseResume( - () => { + () => + { InteropFunctions.CallNativeVoidFunction(callbackFunction, callbackContext); })); return (UInt32)MAPICodes.AZAC_ERR_NONE; @@ -1154,7 +1158,8 @@ public unsafe static UInt32 CommandSystemBuilder_ConfigureMedia_UseStop(IntPtr b if (builder != default) { builder.ConfigureMedia(ui => ui.UseStop( - () => { + () => + { InteropFunctions.CallNativeVoidFunction(callbackFunction, callbackContext); })); return (UInt32)MAPICodes.AZAC_ERR_NONE; diff --git a/src/maui/MainPage.xaml.cs b/src/maui/MainPage.xaml.cs index 56739b03..fbcb8729 100644 --- a/src/maui/MainPage.xaml.cs +++ b/src/maui/MainPage.xaml.cs @@ -1,7 +1,6 @@ using Android.App; using Android.Content; using Android.Provider; -using Microsoft.Extensions.Hosting; using System.Diagnostics; using Application = Android.App.Application; @@ -137,5 +136,5 @@ private void DisplayTips(IEnumerable? tips) { DisplayText("TIPS not yet implemented", 800); } - } + } } diff --git a/src/maui/MauiProgram.cs b/src/maui/MauiProgram.cs index 7100dd01..64a2c1ce 100644 --- a/src/maui/MauiProgram.cs +++ b/src/maui/MauiProgram.cs @@ -1,9 +1,6 @@ -using System.Diagnostics; -using System.Threading.Tasks; -using Android.Content; -using Android.Content.PM; -using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Hosting; using Newtonsoft.Json.Linq; +using System.Diagnostics; namespace maui { @@ -47,27 +44,27 @@ public static async Task CreateMacaroni() // .MonitorFolder(FileSystem.Current.AppDataDirectory) ) //.ConfigureSecrets(secrets => secrets - // .UseKeyVault(_keyVaultUri, _keyVaultTenantId, _keyVaultClientId) // ... or ... - // .AddSecret("KEY_VAULT_CLIENT_SECRET", "PUT_SECRET_HERE") - // .AddSecret("SPEECH_KEY", "PUT_SECRET_HERE") - // .AddSecret("CLU_KEY", "PUT_SECRET_HERE") - // .AddSecret("OPEN_AI_KEY", "PUT_SECRET_HERE") - // .AddSecret("TRANSLATOR_KEY", "PUT_SECRET_HERE") - // .AddSecret("VISION_KEY", "PUT_SECRET_HERE") - // .AddSecret("CLU_DEPLOYMENT_NAME", "v1") - // .AddSecret("CLU_ENDPOINT", "https://internal-gm-dev.cognitiveservices.azure.com") - // .AddSecret("CLU_PROJECT_NAME", "GM-Orchestrator") - // .AddSecret("OPEN_AI_DEPLOYMENT", "robch-southcentral-oai-txtdav002") - // .AddSecret("OPEN_AI_ENDPOINT", "https://robch-openai.openai.azure.com/") - // .AddSecret("SPEECH_RECOGNITION_ENDPOINT", "...") - // .AddSecret("SPEECH_SYNTHESIS_ENDPOINT", "...") - // .AddSecret("SPEECH_CUSTOM_RECOGNITION_ENDPOINT_ID", "") - // .AddSecret("SPEECH_CUSTOM_SYNTHESIS_ENDPOINT_ID", "") - // .AddSecret("TRANSLATOR_ENDPOINT", "https://api.cognitive.microsofttranslator.com/") - // .AddSecret("TRANSLATOR_REGION", "westus2") - // .AddSecret("VISION_DEFAULT_LANGUAGE", "en") - // .AddSecret("VISION_ENDPOINT", "https://carbon-vision.cognitiveservices.azure.com") - // ) + // .UseKeyVault(_keyVaultUri, _keyVaultTenantId, _keyVaultClientId) // ... or ... + // .AddSecret("KEY_VAULT_CLIENT_SECRET", "PUT_SECRET_HERE") + // .AddSecret("SPEECH_KEY", "PUT_SECRET_HERE") + // .AddSecret("CLU_KEY", "PUT_SECRET_HERE") + // .AddSecret("OPEN_AI_KEY", "PUT_SECRET_HERE") + // .AddSecret("TRANSLATOR_KEY", "PUT_SECRET_HERE") + // .AddSecret("VISION_KEY", "PUT_SECRET_HERE") + // .AddSecret("CLU_DEPLOYMENT_NAME", "v1") + // .AddSecret("CLU_ENDPOINT", "https://internal-gm-dev.cognitiveservices.azure.com") + // .AddSecret("CLU_PROJECT_NAME", "GM-Orchestrator") + // .AddSecret("OPEN_AI_DEPLOYMENT", "robch-southcentral-oai-txtdav002") + // .AddSecret("OPEN_AI_ENDPOINT", "https://robch-openai.openai.azure.com/") + // .AddSecret("SPEECH_RECOGNITION_ENDPOINT", "...") + // .AddSecret("SPEECH_SYNTHESIS_ENDPOINT", "...") + // .AddSecret("SPEECH_CUSTOM_RECOGNITION_ENDPOINT_ID", "") + // .AddSecret("SPEECH_CUSTOM_SYNTHESIS_ENDPOINT_ID", "") + // .AddSecret("TRANSLATOR_ENDPOINT", "https://api.cognitive.microsofttranslator.com/") + // .AddSecret("TRANSLATOR_REGION", "westus2") + // .AddSecret("VISION_DEFAULT_LANGUAGE", "en") + // .AddSecret("VISION_ENDPOINT", "https://carbon-vision.cognitiveservices.azure.com") + // ) .ConfigureSpeech(speech => speech .AddListeningStateChangedHandler(state => DisplayRecognizerStateChange(state)) .UseDefaultListeningState(macaroni.ListeningState.Sleep) @@ -295,7 +292,7 @@ private static async Task CopyPackageBinaryFileAsync(string appPackageFileName, using var source = new BinaryReader(stream); using var destination = File.OpenWrite(fileSystemFileName); - for (; ;) + for (; ; ) { var bytes = source.ReadBytes(1024); if (bytes.Length == 0) diff --git a/src/maui/Platforms/Android/MainActivity.cs b/src/maui/Platforms/Android/MainActivity.cs index bcef5224..58323901 100644 --- a/src/maui/Platforms/Android/MainActivity.cs +++ b/src/maui/Platforms/Android/MainActivity.cs @@ -1,6 +1,5 @@ using Android.App; using Android.Content.PM; -using Android.OS; namespace maui { diff --git a/src/mr/BroadcastTestInstruction.cs b/src/mr/BroadcastTestInstruction.cs index 02c6c295..3c0022a4 100644 --- a/src/mr/BroadcastTestInstruction.cs +++ b/src/mr/BroadcastTestInstruction.cs @@ -1,8 +1,9 @@ -namespace macaroni; - -class BroadcastTestInstruction : TestInstruction +namespace macaroni { - public override string? Kind => "broadcast"; - public string? Message; - public string? Value; -} + class BroadcastTestInstruction : TestInstruction + { + public override string? Kind => "broadcast"; + public string? Message; + public string? Value; + } +} \ No newline at end of file diff --git a/src/mr/CommandSetParseChecker.cs b/src/mr/CommandSetParseChecker.cs index 2a836a46..2ad5c40d 100644 --- a/src/mr/CommandSetParseChecker.cs +++ b/src/mr/CommandSetParseChecker.cs @@ -1,151 +1,151 @@ -using Microsoft.Extensions.DependencyInjection; using System.Diagnostics; -namespace macaroni; - -internal static class CommandSetParseChecker +namespace macaroni { - public static int ParseOneOrMoreFiles(string fileName) - { - return File.Exists(fileName) - ? ParseOneFile(fileName) - : ParseMultipleFiles(fileName); - } - - private static int ParseOneFile(string fileName) + internal static class CommandSetParseChecker { - return TryParseFile(fileName) ? Program.ParseSucceeded : Program.ParseFailed; - } + public static int ParseOneOrMoreFiles(string fileName) + { + return File.Exists(fileName) + ? ParseOneFile(fileName) + : ParseMultipleFiles(fileName); + } - private static int ParseMultipleFiles(string fileName) - { - try + private static int ParseOneFile(string fileName) { - var fi = new FileInfo(fileName); - var path = fi.DirectoryName ?? "."; - var search = fi.Name; + return TryParseFile(fileName) ? Program.ParseSucceeded : Program.ParseFailed; + } - var files = Directory.GetFiles(path, search); - if (files.Length == 0) + private static int ParseMultipleFiles(string fileName) + { + try { - Console.ForegroundColor = ConsoleColor.DarkRed; - Console.WriteLine($"No files found matching '{fileName}'"); - Console.ResetColor(); + var fi = new FileInfo(fileName); + var path = fi.DirectoryName ?? "."; + var search = fi.Name; + + var files = Directory.GetFiles(path, search); + if (files.Length == 0) + { + Console.ForegroundColor = ConsoleColor.DarkRed; + Console.WriteLine($"No files found matching '{fileName}'"); + Console.ResetColor(); + return Program.FileNotFound; + } + + var parsed = files.Count(x => TryParseFile(x)); + if (parsed != files.Count()) return Program.ParseFailed; + + return Program.ParseSucceeded; + } + catch (DirectoryNotFoundException ex) + { + Console.WriteLine(ex.Message); return Program.FileNotFound; } + } - var parsed = files.Count(x => TryParseFile(x)); - if (parsed != files.Count()) return Program.ParseFailed; + private static bool TryParseFile(string fileName) + { + var yaml = FileHelpers.FileReadAllText(fileName); + try + { + EnsureInitCommandSystem(); + var parser = _commandSystem?.Services.GetRequiredService(); + + Console.WriteLine($"{fileName}"); + var parsed = parser?.Parse(fileName, new StringReader(yaml)); + CheckPrintParseWarnings(parsed); + } + catch (Exception ex) + { + PrintParseError(fileName, ex); + return false; + } - return Program.ParseSucceeded; + return true; } - catch (DirectoryNotFoundException ex) + + private static void CheckPrintParseWarnings(IEnumerable? parsed) { - Console.WriteLine(ex.Message); - return Program.FileNotFound; + parsed?.Where(cs => cs.Warnings?.Any() ?? false) + .SelectMany(cs => cs.Warnings!) + .ToList() + .ForEach(PrintParseWarning); } - } - private static bool TryParseFile(string fileName) - { - var yaml = FileHelpers.FileReadAllText(fileName); - try + private static void PrintParseWarning(FileParseWarning warning) { - EnsureInitCommandSystem(); - var parser = _commandSystem?.Services.GetRequiredService(); - - Console.WriteLine($"{fileName}"); - var parsed = parser?.Parse(fileName, new StringReader(yaml)); - CheckPrintParseWarnings(parsed); + var message = warning.Message; + var lines = message.Split("\r\n".ToArray(), StringSplitOptions.RemoveEmptyEntries); + + var prevColor = Console.ForegroundColor; + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine($"{warning.DocumentPosition}: {lines[0]}"); + Console.ForegroundColor = prevColor; + Console.WriteLine(string.Join("\r\n", lines.Skip(1))); + Console.WriteLine(); } - catch (Exception ex) + + private static void PrintParseError(string fileName, Exception ex) { - PrintParseError(fileName, ex); - return false; + var message = GetParseErrorMessage(fileName, ex); + var lines = message.Split("\r\n".ToArray(), StringSplitOptions.RemoveEmptyEntries); + + var prevColor = Console.ForegroundColor; + Console.ForegroundColor = ConsoleColor.DarkRed; + Console.WriteLine(lines[0]); + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine(string.Join("\r\n", lines.Skip(1))); + Console.WriteLine(); + Console.ForegroundColor = prevColor; } - return true; - } - - private static void CheckPrintParseWarnings(IEnumerable? parsed) - { - parsed?.Where(cs => cs.Warnings?.Any() ?? false) - .SelectMany(cs => cs.Warnings!) - .ToList() - .ForEach(PrintParseWarning); - } - - private static void PrintParseWarning(FileParseWarning warning) - { - var message = warning.Message; - var lines = message.Split("\r\n".ToArray(), StringSplitOptions.RemoveEmptyEntries); - - var prevColor = Console.ForegroundColor; - Console.ForegroundColor = ConsoleColor.Yellow; - Console.WriteLine($"{warning.DocumentPosition}: {lines[0]}"); - Console.ForegroundColor = prevColor; - Console.WriteLine(string.Join("\r\n", lines.Skip(1))); - Console.WriteLine(); - } + private static void EnsureInitCommandSystem() + { + if (_commandSystem == null) + { + InitCommandSystem(); + } + } - private static void PrintParseError(string fileName, Exception ex) - { - var message = GetParseErrorMessage(fileName, ex); - var lines = message.Split("\r\n".ToArray(), StringSplitOptions.RemoveEmptyEntries); - - var prevColor = Console.ForegroundColor; - Console.ForegroundColor = ConsoleColor.DarkRed; - Console.WriteLine(lines[0]); - Console.ForegroundColor = ConsoleColor.Yellow; - Console.WriteLine(string.Join("\r\n", lines.Skip(1))); - Console.WriteLine(); - Console.ForegroundColor = prevColor; - } + private static void InitCommandSystem() + { + var builder = macaroni.CommandSystem.CreateBuilder() + .ConfigureSources(sources => sources.UseDefaultFolderMonitor(false)) + .ConfigureMessages(messages => messages + .AddHandler((name, value) => Debug.WriteLine($"BROADCAST: name={name}, value={value}")) + .AddHandler("beeper", value => Debug.WriteLine("BROADCAST GOT BEEPER!!")) + ) + .ConfigureResolvers(resolvers => resolvers + .UseContext("IsEditorDesignMode", "true") + .UseContext("folders.macros", GetMacrosFolder()) + ); + _commandSystem = builder.Build(); + Services = _commandSystem.Services; + } - private static void EnsureInitCommandSystem() - { - if (_commandSystem == null) + private static string GetMacrosFolder() { - InitCommandSystem(); + return FileHelpers.TryFileReadAllText("MACRO_FOLDER") ?? "."; } - } - private static void InitCommandSystem() - { - var builder = macaroni.CommandSystem.CreateBuilder() - .ConfigureSources(sources => sources.UseDefaultFolderMonitor(false)) - .ConfigureMessages(messages => messages - .AddHandler((name, value) => Debug.WriteLine($"BROADCAST: name={name}, value={value}")) - .AddHandler("beeper", value => Debug.WriteLine("BROADCAST GOT BEEPER!!")) - ) - .ConfigureResolvers(resolvers => resolvers - .UseContext("IsEditorDesignMode", "true") - .UseContext("folders.macros", GetMacrosFolder()) - ); - _commandSystem = builder.Build(); - Services = _commandSystem.Services; - } + private static string GetParseErrorMessage(string file, Exception ex) + { + var parseEx = ex as FileParseException; + var context = parseEx?.DocumentPosition ?? file; - private static string GetMacrosFolder() - { - return FileHelpers.TryFileReadAllText("MACRO_FOLDER") ?? "."; - } + var lines = ex.Message.Split('\n'); + var error = lines[0]; + var message = "\n" + string.Join("\n", lines.Skip(1).Select(line => line.Trim())).Trim(); + message = message.Replace("\n", "\n "); + message = $"{context}: ERROR: {error}\n{message}\n"; - private static string GetParseErrorMessage(string file, Exception ex) - { - var parseEx = ex as FileParseException; - var context = parseEx?.DocumentPosition ?? file; + return message; + } - var lines = ex.Message.Split('\n'); - var error = lines[0]; - var message = "\n" + string.Join("\n", lines.Skip(1).Select(line => line.Trim())).Trim(); - message = message.Replace("\n", "\n "); - message = $"{context}: ERROR: {error}\n{message}\n"; + public static IServiceProvider? Services { get; private set; } - return message; + private static macaroni.ICommandSystem? _commandSystem; } - - public static IServiceProvider? Services { get; private set; } - - private static macaroni.ICommandSystem? _commandSystem; -} +} \ No newline at end of file diff --git a/src/mr/CommandSetRunner.cs b/src/mr/CommandSetRunner.cs index cf50cfa4..5bd94944 100644 --- a/src/mr/CommandSetRunner.cs +++ b/src/mr/CommandSetRunner.cs @@ -5,417 +5,418 @@ using static System.Net.Mime.MediaTypeNames; using Newtonsoft.Json.Linq; -namespace macaroni; - -class CommandSetRunner +namespace macaroni { - public CommandSetRunner() + class CommandSetRunner { - } + public CommandSetRunner() + { + } - public CommandSetRunner(string? keyVaultUri, string? keyVaultTenantId, string? keyVaultClientId) - { - _keyVaultUri = keyVaultUri; - _keyVaultClientId = keyVaultClientId; - _keyVaultTenantId = keyVaultTenantId; - } + public CommandSetRunner(string? keyVaultUri, string? keyVaultTenantId, string? keyVaultClientId) + { + _keyVaultUri = keyVaultUri; + _keyVaultClientId = keyVaultClientId; + _keyVaultTenantId = keyVaultTenantId; + } - public int Run(List files, List? assemblies, string? logPath, List? secretNameValues, string? defaultListeningState, string? keyword, string? keywordModel, bool? clu, bool? nuggets) - { - Console.WriteLine(); - Console.ForegroundColor = ConsoleColor.Black; - Console.BackgroundColor = ConsoleColor.White; - Console.Write("Press ENTER to TOGGLE listening states; type `:quit` to exit"); - Console.ResetColor(); - Console.WriteLine(); - Console.WriteLine(); - Console.WriteLine(); - - AppDomain domain = AppDomain.CurrentDomain; - domain.UnhandledException += (s, e) => HandleUnhandledException(e); - - var builder = macaroni.CommandSystem.CreateBuilder() - .ConfigureComponents(components => ConfigureComponents(components, assemblies)) - .ConfigureSpeech(speech => ConfigureSpeech(speech, defaultListeningState, keyword, keywordModel, clu, nuggets)) - .ConfigureLogging(logging => ConfigureLogging(logging, logPath)) - .ConfigureSecrets(secrets => ConfigureSecrets(secrets, secretNameValues)) - .ConfigureSources(sources => ConfigureSources(sources, files)) - .ConfigureMessages(messages => ConfigureMessages(messages)) - .ConfigureResolvers(resolvers => ConfigureResolvers(resolvers)) - .ConfigureUi(ui => ConfigureUi(ui)); - - _commandSystem = builder.Build(); - _commandSystem.StartAsync().Wait(); - _intent = _commandSystem.Services.GetRequiredService(); - - var running = Task.Run(() => _commandSystem.Run()); - var exitCode = HandleInputLoop(defaultListeningState); - - _commandSystem.StopAsync(); - running.Wait(); - - return exitCode; - } + public int Run(List files, List? assemblies, string? logPath, List? secretNameValues, string? defaultListeningState, string? keyword, string? keywordModel, bool? clu, bool? nuggets) + { + Console.WriteLine(); + Console.ForegroundColor = ConsoleColor.Black; + Console.BackgroundColor = ConsoleColor.White; + Console.Write("Press ENTER to TOGGLE listening states; type `:quit` to exit"); + Console.ResetColor(); + Console.WriteLine(); + Console.WriteLine(); + Console.WriteLine(); + + AppDomain domain = AppDomain.CurrentDomain; + domain.UnhandledException += (s, e) => HandleUnhandledException(e); + + var builder = macaroni.CommandSystem.CreateBuilder() + .ConfigureComponents(components => ConfigureComponents(components, assemblies)) + .ConfigureSpeech(speech => ConfigureSpeech(speech, defaultListeningState, keyword, keywordModel, clu, nuggets)) + .ConfigureLogging(logging => ConfigureLogging(logging, logPath)) + .ConfigureSecrets(secrets => ConfigureSecrets(secrets, secretNameValues)) + .ConfigureSources(sources => ConfigureSources(sources, files)) + .ConfigureMessages(messages => ConfigureMessages(messages)) + .ConfigureResolvers(resolvers => ConfigureResolvers(resolvers)) + .ConfigureUi(ui => ConfigureUi(ui)); + + _commandSystem = builder.Build(); + _commandSystem.StartAsync().Wait(); + _intent = _commandSystem.Services.GetRequiredService(); + + var running = Task.Run(() => _commandSystem.Run()); + var exitCode = HandleInputLoop(defaultListeningState); + + _commandSystem.StopAsync(); + running.Wait(); + + return exitCode; + } - private int HandleInputLoop(string? defaultListeningState) - { - try + private int HandleInputLoop(string? defaultListeningState) { - for (; ; ) + try { - PrintPrompt(); - - string? input = ConsoleReadLine(); - if (!HandleInput(input, defaultListeningState)) + for (; ; ) { - break; + PrintPrompt(); + + string? input = ConsoleReadLine(); + if (!HandleInput(input, defaultListeningState)) + { + break; + } } - } - return 0; + return 0; + } + catch (TimeoutException) + { + throw; + } + catch (Exception ex) + { + Console.WriteLine(ex); + return Program.UnhandledException; + } } - catch (TimeoutException) + + protected virtual object? ResolveContext(string name) { - throw; + return null; } - catch (Exception ex) + + protected virtual bool HandleInput(string? input, string? defaultListeningState) { - Console.WriteLine(ex); - return Program.UnhandledException; + return input?.Trim() switch + { + null or "" => HandleToggleInput(defaultListeningState), + ":toggle" => HandleToggleInput(defaultListeningState), + ":quit" => HandleQuit(), + _ => HandleEmulate(input) + }; } - } - - protected virtual object? ResolveContext(string name) - { - return null; - } - protected virtual bool HandleInput(string? input, string? defaultListeningState) - { - return input?.Trim() switch + private static bool HandleQuit() { - null or "" => HandleToggleInput(defaultListeningState), - ":toggle" => HandleToggleInput(defaultListeningState), - ":quit" => HandleQuit(), - _ => HandleEmulate(input) - }; - } - - private static bool HandleQuit() - { - return false; - } + return false; + } - private bool HandleToggleInput(string? defaultListeningState) - { - ToggleListeningState(defaultListeningState); - return true; - } + private bool HandleToggleInput(string? defaultListeningState) + { + ToggleListeningState(defaultListeningState); + return true; + } - private bool HandleEmulate(string text) - { - _commandSystem?.EmulateSpeechRecognition(text); - return true; - } + private bool HandleEmulate(string text) + { + _commandSystem?.EmulateSpeechRecognition(text); + return true; + } - protected virtual string? ConsoleReadLine() - { - var input = Console.ReadLine(); - SetCursorPreviousLineAtEndOfLine(); - return input; - } + protected virtual string? ConsoleReadLine() + { + var input = Console.ReadLine(); + SetCursorPreviousLineAtEndOfLine(); + return input; + } - protected virtual void ConsoleWriteLine(string? output) - { - _printPromptNeeded = true; + protected virtual void ConsoleWriteLine(string? output) + { + _printPromptNeeded = true; - EraseCurrentLine(); - SetCursorPreviousLineAtStartOfLine(); - Console.WriteLine(output); - } + EraseCurrentLine(); + SetCursorPreviousLineAtStartOfLine(); + Console.WriteLine(output); + } - protected static void EraseCurrentLine() - { - try + protected static void EraseCurrentLine() { - (var x, var y) = Console.GetCursorPosition(); - for (int i = 0; i < x; i++) + try + { + (var x, var y) = Console.GetCursorPosition(); + for (int i = 0; i < x; i++) + { + Console.SetCursorPosition(i, y); + Console.Write(' '); + } + } + catch (Exception) { - Console.SetCursorPosition(i, y); - Console.Write(' '); } } - catch (Exception) - { - } - } - protected static void SetCursorPreviousLineAtStartOfLine() - { - try + protected static void SetCursorPreviousLineAtStartOfLine() { - (var x, var y) = Console.GetCursorPosition(); - Console.SetCursorPosition(0, y - 1); + try + { + (var x, var y) = Console.GetCursorPosition(); + Console.SetCursorPosition(0, y - 1); + } + catch (Exception) + { + } } - catch (Exception) + + protected static void SetCursorPreviousLineAtEndOfLine() { + try + { + (var x, var y) = Console.GetCursorPosition(); + Console.SetCursorPosition(Console.WindowWidth - 1, y - 1); + } + catch (Exception) + { + } } - } - protected static void SetCursorPreviousLineAtEndOfLine() - { - try + private string GetKeyword() { - (var x, var y) = Console.GetCursorPosition(); - Console.SetCursorPosition(Console.WindowWidth - 1, y - 1); + return "Copilot"; } - catch (Exception) + + private string GetKeywordModelFile() { + var use = 1; + var file = use switch + { + 1 => "copilot_higher_ca.table", + 2 => "copilot_lower_fa.table", + _ => "copilot_default.table" + }; + return file; } - } - private string GetKeyword() - { - return "Copilot"; - } + private void ToggleListeningState(string? defaultListeningState) + { + if (defaultListeningState == null || !ListeningStateHelpers.TryParse(defaultListeningState, out var toggleOnToWhat)) + { + toggleOnToWhat = ListeningState.Off; + } - private string GetKeywordModelFile() - { - var use = 1; - var file = use switch - { - 1 => "copilot_higher_ca.table", - 2 => "copilot_lower_fa.table", - _ => "copilot_default.table" - }; - return file; - } + var newState = _intent?.GetState() switch + { + ListeningState.Off or ListeningState.Sleep => ListeningState.Once, + ListeningState.On or _ => toggleOnToWhat + }; + _intent?.SetState(newState); + } - private void ToggleListeningState(string? defaultListeningState) - { - if (defaultListeningState == null || !ListeningStateHelpers.TryParse(defaultListeningState, out var toggleOnToWhat)) + private void PrintPrompt() { - toggleOnToWhat = ListeningState.Off; + if (_printPromptNeeded) + { + Console.Write($"\n{_promptState}> "); + _printPromptNeeded = false; + } } - var newState = _intent?.GetState() switch + private void DisplayRecognizerStateChange(ListeningState state) { - ListeningState.Off or ListeningState.Sleep => ListeningState.Once, - ListeningState.On or _ => toggleOnToWhat - }; - _intent?.SetState(newState); - } + _promptState = ListeningStateHelpers.AsString(state); + DisplayOnScreenText($"{_promptState}..."); + } - private void PrintPrompt() - { - if (_printPromptNeeded) + private void DisplaySynthesizerStateChange(SpeakingState state) { - Console.Write($"\n{_promptState}> "); - _printPromptNeeded = false; + if (_verbose) + { + DisplayOnScreenText($"SpeakingState: {state}..."); + } } - } - - private void DisplayRecognizerStateChange(ListeningState state) - { - _promptState = ListeningStateHelpers.AsString(state); - DisplayOnScreenText($"{_promptState}..."); - } - private void DisplaySynthesizerStateChange(SpeakingState state) - { - if (_verbose) + private void DisplayOnScreenText(string text) { - DisplayOnScreenText($"SpeakingState: {state}..."); + var osd = _commandSystem?.Services?.GetService(); + osd?.DisplayText(text); } - } - private void DisplayOnScreenText(string text) - { - var osd = _commandSystem?.Services?.GetService(); - osd?.DisplayText(text); - } - - private void DisplayMessageBox(string? message, string? title) - { - var messageBox = _commandSystem?.Services?.GetService(); - if (messageBox != null && message != null && title != null) + private void DisplayMessageBox(string? message, string? title) { - messageBox.Show(message, title, null); + var messageBox = _commandSystem?.Services?.GetService(); + if (messageBox != null && message != null && title != null) + { + messageBox.Show(message, title, null); + } } - } - private void DisplayRecognitionError(string? error) - { - if (error != null) + private void DisplayRecognitionError(string? error) { - DisplayOnScreenText(error); + if (error != null) + { + DisplayOnScreenText(error); + } } - } - - private void DisplayRuntimeException(Exception ex) - { - DisplayOnScreenText(ex.ToString()); - } - - private void DisplayParsingException(Exception ex) - { - DisplayOnScreenText(ex.ToString()); - } - - private void DisplaySystemException(Exception ex) - { - DisplayOnScreenText(ex.ToString()); - } - - private string GetMacrosFolder() - { - return FileHelpers.TryFileReadAllText("MACRO_FOLDER") ?? "."; - } - private void Display(string text, string from, bool? pending, int timeout) - { - var thisDisplayFromUser = from == "USER"; - var addLF = thisDisplayFromUser && !_lastDisplayFromUser ? "\n" : ""; - _lastDisplayFromUser = thisDisplayFromUser; + private void DisplayRuntimeException(Exception ex) + { + DisplayOnScreenText(ex.ToString()); + } - ConsoleWriteLine( - !string.IsNullOrEmpty(from) - ? $"{addLF}{from.ToUpper()}: {text}" - : text); + private void DisplayParsingException(Exception ex) + { + DisplayOnScreenText(ex.ToString()); + } - PrintPrompt(); - } + private void DisplaySystemException(Exception ex) + { + DisplayOnScreenText(ex.ToString()); + } - private void Alert(string message, string? title, int? timeout) - { - } + private string GetMacrosFolder() + { + return FileHelpers.TryFileReadAllText("MACRO_FOLDER") ?? "."; + } - private void Confirm(string message, string? title, int? timeout) - { - } + private void Display(string text, string from, bool? pending, int timeout) + { + var thisDisplayFromUser = from == "USER"; + var addLF = thisDisplayFromUser && !_lastDisplayFromUser ? "\n" : ""; + _lastDisplayFromUser = thisDisplayFromUser; - private string? Pick(string? message, string? title, int? timeout, IEnumerable choices, string? choice) - { - return null; - } + ConsoleWriteLine( + !string.IsNullOrEmpty(from) + ? $"{addLF}{from.ToUpper()}: {text}" + : text); - private string? Prompt(string message, string? title, string? defaultText, int? timeout) - { - return null; - } + PrintPrompt(); + } - private void HandleUnhandledException(UnhandledExceptionEventArgs e) - { - var ex = (Exception)e.ExceptionObject; - var details = ex.ToString(); - try + private void Alert(string message, string? title, int? timeout) { - var file = $"macaroni.exception-{DateTime.Now.ToFileTime()}.log"; - File.WriteAllText(file, details); } - catch (Exception) + + private void Confirm(string message, string? title, int? timeout) { } - finally + + private string? Pick(string? message, string? title, int? timeout, IEnumerable choices, string? choice) { - DisplayOnScreenText($"UNHANDLED EXCEPTION: {details}"); + return null; } - } - - protected virtual void ConfigureSpeech(IConfigureSpeechBuilder speech, string? defaultListeningState, string? keyword, string? keywordModelFile, bool? clu, bool? nuggets) - { - speech.AddListeningStateChangedHandler(DisplayRecognizerStateChange); - speech.AddSpeakingStateChangedHandler(DisplaySynthesizerStateChange); - if (defaultListeningState != null && ListeningStateHelpers.TryParse(defaultListeningState, out var listeningState)) + private string? Prompt(string message, string? title, string? defaultText, int? timeout) { - speech.UseDefaultListeningState(listeningState); + return null; } - if (keyword != null && keywordModelFile != null) + private void HandleUnhandledException(UnhandledExceptionEventArgs e) { - speech.UseKeywordRecognition(keyword, keywordModelFile); + var ex = (Exception)e.ExceptionObject; + var details = ex.ToString(); + try + { + var file = $"macaroni.exception-{DateTime.Now.ToFileTime()}.log"; + File.WriteAllText(file, details); + } + catch (Exception) + { + } + finally + { + DisplayOnScreenText($"UNHANDLED EXCEPTION: {details}"); + } } - if (clu != null || nuggets != null) - { - speech.UseHighRecall(clu ?? false, nuggets ?? false); - } - } + protected virtual void ConfigureSpeech(IConfigureSpeechBuilder speech, string? defaultListeningState, string? keyword, string? keywordModelFile, bool? clu, bool? nuggets) + { + speech.AddListeningStateChangedHandler(DisplayRecognizerStateChange); + speech.AddSpeakingStateChangedHandler(DisplaySynthesizerStateChange); - protected virtual void ConfigureLogging(IConfigureLoggingBuilder logging, string? logPath) - { - logging.UseFileLogging(logPath ?? Directory.GetCurrentDirectory()); - logging.AddExceptionHandler(ExceptionKind.Runtime, DisplayRuntimeException); - logging.AddExceptionHandler(ExceptionKind.Parsing, DisplayParsingException); - logging.AddExceptionHandler(ExceptionKind.System, DisplaySystemException); - } + if (defaultListeningState != null && ListeningStateHelpers.TryParse(defaultListeningState, out var listeningState)) + { + speech.UseDefaultListeningState(listeningState); + } - protected virtual void ConfigureSecrets(IConfigureSecretBuilder secrets, List? secretNameValues) - { - secrets.AddSecret("DEFAULT_LANGUAGE", "en-us"); - secretNameValues?.ForEach(nameValue => - secrets.AddSecret( - nameValue.Before('='), - nameValue.After('='))); + if (keyword != null && keywordModelFile != null) + { + speech.UseKeywordRecognition(keyword, keywordModelFile); + } + + if (clu != null || nuggets != null) + { + speech.UseHighRecall(clu ?? false, nuggets ?? false); + } + } - var useKeyVault = !string.IsNullOrEmpty(_keyVaultUri) && !string.IsNullOrEmpty(_keyVaultClientId) && !string.IsNullOrEmpty(_keyVaultTenantId); - if (useKeyVault) + protected virtual void ConfigureLogging(IConfigureLoggingBuilder logging, string? logPath) { - secrets.UseKeyVault(_keyVaultUri!, _keyVaultTenantId!, _keyVaultClientId!); + logging.UseFileLogging(logPath ?? Directory.GetCurrentDirectory()); + logging.AddExceptionHandler(ExceptionKind.Runtime, DisplayRuntimeException); + logging.AddExceptionHandler(ExceptionKind.Parsing, DisplayParsingException); + logging.AddExceptionHandler(ExceptionKind.System, DisplaySystemException); } - } - protected virtual void ConfigureSources(IConfigureSourceBuilder sources, List files) - { - sources.UseDefaultFolderMonitor(false); - foreach (var file in files.Select(x => new FileInfo(x))) + protected virtual void ConfigureSecrets(IConfigureSecretBuilder secrets, List? secretNameValues) + { + secrets.AddSecret("DEFAULT_LANGUAGE", "en-us"); + secretNameValues?.ForEach(nameValue => + secrets.AddSecret( + nameValue.Before('='), + nameValue.After('='))); + + var useKeyVault = !string.IsNullOrEmpty(_keyVaultUri) && !string.IsNullOrEmpty(_keyVaultClientId) && !string.IsNullOrEmpty(_keyVaultTenantId); + if (useKeyVault) + { + secrets.UseKeyVault(_keyVaultUri!, _keyVaultTenantId!, _keyVaultClientId!); + } + } + + protected virtual void ConfigureSources(IConfigureSourceBuilder sources, List files) { - var path = file.Directory?.FullName ?? "."; - var fileSpec = file.Name; - sources.MonitorFolder(path, fileSpec); + sources.UseDefaultFolderMonitor(false); + foreach (var file in files.Select(x => new FileInfo(x))) + { + var path = file.Directory?.FullName ?? "."; + var fileSpec = file.Name; + sources.MonitorFolder(path, fileSpec); + } } - } - protected void ConfigureComponents(IConfigureComponentBuilder builder, List? assemblies) - { - if (assemblies?.Count() > 0) + protected void ConfigureComponents(IConfigureComponentBuilder builder, List? assemblies) { - foreach (string assemblyReference in assemblies) + if (assemblies?.Count() > 0) { - var assembly = Assembly.LoadFrom(assemblyReference); - builder.AddComponentsFromAssembly(assembly); + foreach (string assemblyReference in assemblies) + { + var assembly = Assembly.LoadFrom(assemblyReference); + builder.AddComponentsFromAssembly(assembly); + } } } - } - protected virtual void ConfigureMessages(IConfigureMessageBuilder messages) - { - } + protected virtual void ConfigureMessages(IConfigureMessageBuilder messages) + { + } - protected virtual void ConfigureResolvers(IConfigureResolverBuilder resolvers) - { - resolvers.AddResolver(name => ResolveContext(name)); - } + protected virtual void ConfigureResolvers(IConfigureResolverBuilder resolvers) + { + resolvers.AddResolver(name => ResolveContext(name)); + } - protected virtual void ConfigureUi(IConfigureUiBuilder ui) - { - ui.UseDisplay(Display); - ui.UseAlert(Alert); - ui.UseConfirm(Confirm); - ui.UsePick(Pick); - ui.UsePrompt(Prompt); - } + protected virtual void ConfigureUi(IConfigureUiBuilder ui) + { + ui.UseDisplay(Display); + ui.UseAlert(Alert); + ui.UseConfirm(Confirm); + ui.UsePick(Pick); + ui.UsePrompt(Prompt); + } - protected ICommandSystem? _commandSystem { get; private set; } - private IIntentRecognizerService? _intent; + protected ICommandSystem? _commandSystem { get; private set; } + private IIntentRecognizerService? _intent; - private bool _printPromptNeeded = true; - private string _promptState = "Off"; - private bool _lastDisplayFromUser = false; + private bool _printPromptNeeded = true; + private string _promptState = "Off"; + private bool _lastDisplayFromUser = false; - private string? _keyVaultUri; - private string? _keyVaultTenantId; - private string? _keyVaultClientId; - private bool _verbose = false; + private string? _keyVaultUri; + private string? _keyVaultTenantId; + private string? _keyVaultClientId; + private bool _verbose = false; + } } diff --git a/src/mr/CommandSetTestRunner.cs b/src/mr/CommandSetTestRunner.cs index fde66abf..204ba631 100644 --- a/src/mr/CommandSetTestRunner.cs +++ b/src/mr/CommandSetTestRunner.cs @@ -2,499 +2,500 @@ using System.Diagnostics; using System.Text; -namespace macaroni; - -class CommandSetTestRunner : CommandSetRunner +namespace macaroni { - public CommandSetTestRunner() - { - } - - public CommandSetTestRunner(string? keyVaultUri, string? keyVaultTenantId, string? keyVaultClientId) : - base(keyVaultUri, keyVaultTenantId, keyVaultClientId) - { - } - - public int RunTest(List files, List? assemblies, string testFile, string? logPath, List? secrets, string? defaultListeningState, string? keyword, string? keywordModel, bool? clu, bool? nuggets) + class CommandSetTestRunner : CommandSetRunner { - try + public CommandSetTestRunner() { - InitTestInstructions(testFile); - } - catch (FileNotFoundException) - { - Console.ForegroundColor = ConsoleColor.DarkRed; - Console.WriteLine($"Test file not found: {testFile}"); - Console.ResetColor(); - return Program.FileNotFound; - } - catch (FormatException ex) - { - Console.ForegroundColor = ConsoleColor.DarkRed; - Console.WriteLine($"Invalid test file format: {testFile}"); - Console.ForegroundColor = ConsoleColor.DarkYellow; - Console.WriteLine("ERROR: " + ex.Message); - Console.ResetColor(); - return Program.ParseFailed; } - try + public CommandSetTestRunner(string? keyVaultUri, string? keyVaultTenantId, string? keyVaultClientId) : + base(keyVaultUri, keyVaultTenantId, keyVaultClientId) { - Run(files, assemblies, logPath, secrets, defaultListeningState, keyword, keywordModel, clu, nuggets); - } - catch (TimeoutException ex) - { - Console.ForegroundColor = ConsoleColor.DarkRed; - Console.WriteLine($"\n\nTIMEOUT: {ex.Message}"); - Console.ResetColor(); - return Program.TimeoutException; } - return Program.ProgramSucceeded; - } - - protected override void ConfigureSources(IConfigureSourceBuilder sources, List files) - { - if (_templates.Count > 0) + public int RunTest(List files, List? assemblies, string testFile, string? logPath, List? secrets, string? defaultListeningState, string? keyword, string? keywordModel, bool? clu, bool? nuggets) { - sources.AddTemplateReader(name => + try { - if (_templates.ContainsKey(name)) - { - return new StringReader(_templates[name]); - } + InitTestInstructions(testFile); + } + catch (FileNotFoundException) + { + Console.ForegroundColor = ConsoleColor.DarkRed; + Console.WriteLine($"Test file not found: {testFile}"); + Console.ResetColor(); + return Program.FileNotFound; + } + catch (FormatException ex) + { + Console.ForegroundColor = ConsoleColor.DarkRed; + Console.WriteLine($"Invalid test file format: {testFile}"); + Console.ForegroundColor = ConsoleColor.DarkYellow; + Console.WriteLine("ERROR: " + ex.Message); + Console.ResetColor(); + return Program.ParseFailed; + } - return null; - }); + try + { + Run(files, assemblies, logPath, secrets, defaultListeningState, keyword, keywordModel, clu, nuggets); + } + catch (TimeoutException ex) + { + Console.ForegroundColor = ConsoleColor.DarkRed; + Console.WriteLine($"\n\nTIMEOUT: {ex.Message}"); + Console.ResetColor(); + return Program.TimeoutException; + } + + return Program.ProgramSucceeded; } - base.ConfigureSources(sources, files); - } + protected override void ConfigureSources(IConfigureSourceBuilder sources, List files) + { + if (_templates.Count > 0) + { + sources.AddTemplateReader(name => + { + if (_templates.ContainsKey(name)) + { + return new StringReader(_templates[name]); + } - protected override void ConfigureSpeech(IConfigureSpeechBuilder speech, string? defaultListeningState, string? keyword, string? keywordModelFile, bool? clu, bool? nuggets) - { - base.ConfigureSpeech(speech, defaultListeningState, keyword, keywordModelFile, clu, nuggets); - speech.UsePullStream(ReadTestAudio, null); - } + return null; + }); + } - private void InitTestInstructions(string testFile) - { - if (!File.Exists(testFile)) - { - throw new FileNotFoundException($"Test file not found: {testFile}"); + base.ConfigureSources(sources, files); } - _testInstructions = TestInstructionCollection.FromFile(testFile); - if (_testInstructions == null) + protected override void ConfigureSpeech(IConfigureSpeechBuilder speech, string? defaultListeningState, string? keyword, string? keywordModelFile, bool? clu, bool? nuggets) { - throw new FormatException($"Test file found, but not valid: {testFile}"); + base.ConfigureSpeech(speech, defaultListeningState, keyword, keywordModelFile, clu, nuggets); + speech.UsePullStream(ReadTestAudio, null); } - PrepareTopInstruction(); - } - - private bool DoneWithInstructions() - { - return _testInstructions?.Count() == 0; - } - - private void PrepareTopInstruction() - { - lock (this) + private void InitTestInstructions(string testFile) { - while (!DoneWithInstructions()) + if (!File.Exists(testFile)) { - var instruction = _testInstructions!.First(); - - if (instruction.Kind == "template") - { - var template = (TemplateTestInstruction)instruction; - HandleTemplateInstruction(template.Name, template.Value); - _testInstructions?.RemoveAt(0); - continue; - } - - if (instruction.Kind == "timeout") - { - var timeout = (TimeoutTestInstruction)instruction; - HandleTimeoutInstruction(timeout.Timeout); - _testInstructions?.RemoveAt(0); - continue; - } - - if (instruction.Kind == "broadcast") - { - var broadcast = (BroadcastTestInstruction)instruction; - HandleBroadcastInstruction(broadcast.Message, broadcast.Value); - _testInstructions?.RemoveAt(0); - continue; - } + throw new FileNotFoundException($"Test file not found: {testFile}"); + } - if (instruction.Kind == "resolve") - { - var resolve = (ResolveTestInstruction)instruction; - HandleResolveInstruction(resolve.Name, resolve.Value); - _testInstructions?.RemoveAt(0); - continue; - } + _testInstructions = TestInstructionCollection.FromFile(testFile); + if (_testInstructions == null) + { + throw new FormatException($"Test file found, but not valid: {testFile}"); + } - if (instruction.Kind == "send") - { - var send = (SendTestInstruction)instruction; - HandleSendInstruction(send, out var waitForSend); - if (waitForSend) break; + PrepareTopInstruction(); + } - _testInstructions?.RemoveAt(0); - continue; - } + private bool DoneWithInstructions() + { + return _testInstructions?.Count() == 0; + } - if (instruction.Kind == "expect") + private void PrepareTopInstruction() + { + lock (this) + { + while (!DoneWithInstructions()) { - var expect = (ExpectTestInstruction)instruction; - HandleExpectInstruction(expect); - break; + var instruction = _testInstructions!.First(); + + if (instruction.Kind == "template") + { + var template = (TemplateTestInstruction)instruction; + HandleTemplateInstruction(template.Name, template.Value); + _testInstructions?.RemoveAt(0); + continue; + } + + if (instruction.Kind == "timeout") + { + var timeout = (TimeoutTestInstruction)instruction; + HandleTimeoutInstruction(timeout.Timeout); + _testInstructions?.RemoveAt(0); + continue; + } + + if (instruction.Kind == "broadcast") + { + var broadcast = (BroadcastTestInstruction)instruction; + HandleBroadcastInstruction(broadcast.Message, broadcast.Value); + _testInstructions?.RemoveAt(0); + continue; + } + + if (instruction.Kind == "resolve") + { + var resolve = (ResolveTestInstruction)instruction; + HandleResolveInstruction(resolve.Name, resolve.Value); + _testInstructions?.RemoveAt(0); + continue; + } + + if (instruction.Kind == "send") + { + var send = (SendTestInstruction)instruction; + HandleSendInstruction(send, out var waitForSend); + if (waitForSend) break; + + _testInstructions?.RemoveAt(0); + continue; + } + + if (instruction.Kind == "expect") + { + var expect = (ExpectTestInstruction)instruction; + HandleExpectInstruction(expect); + break; + } + + throw new NotImplementedException($"{instruction} is not a valid command."); } - - throw new NotImplementedException($"{instruction} is not a valid command."); } } - } - private void PrepareNextInstruction() - { - if (!DoneWithInstructions()) + private void PrepareNextInstruction() { - lock (this) + if (!DoneWithInstructions()) { - _testInstructions!.RemoveAt(0); + lock (this) + { + _testInstructions!.RemoveAt(0); - _topInstructionExpect = null; - _topInstructionSendValue = null; - _topInstructionIsSend.Reset(); + _topInstructionExpect = null; + _topInstructionSendValue = null; + _topInstructionIsSend.Reset(); - PrepareTopInstruction(); + PrepareTopInstruction(); + } } } - } - private bool IsTopInstructionSend() - { - return _topInstructionIsSend.WaitOne(0); - } + private bool IsTopInstructionSend() + { + return _topInstructionIsSend.WaitOne(0); + } - private string? PopTopSendInstruction() - { - lock (this) + private string? PopTopSendInstruction() { - var input = _topInstructionSendValue; + lock (this) + { + var input = _topInstructionSendValue; - Console.ForegroundColor = ConsoleColor.Cyan; - Console.WriteLine(input); - Console.ForegroundColor = ConsoleColor.White; - SetCursorPreviousLineAtEndOfLine(); + Console.ForegroundColor = ConsoleColor.Cyan; + Console.WriteLine(input); + Console.ForegroundColor = ConsoleColor.White; + SetCursorPreviousLineAtEndOfLine(); - PrepareNextInstruction(); + PrepareNextInstruction(); - return input; + return input; + } } - } - private void InitTimeoutStopWatch() - { - _stopwatch.Restart(); - } - - private bool TimeoutStopWatchExpired() - { - return _timeout > 0 && _stopwatch.Elapsed.TotalSeconds > _timeout; - } - - private TimeoutException NewTimeoutException() - { - lock (this) + private void InitTimeoutStopWatch() { - var expected = _topInstructionExpect?.ToString(); - var expectingSomething = !string.IsNullOrWhiteSpace(expected); - var extra = expectingSomething ? $"; expected: {expected}" : ""; - return new TimeoutException($"Timeout expired after {_timeout} seconds{extra}."); + _stopwatch.Restart(); } - } - protected override object? ResolveContext(string name) - { - lock (this) + private bool TimeoutStopWatchExpired() { - return resolvers.ContainsKey(name) ? resolvers[name] : null; + return _timeout > 0 && _stopwatch.Elapsed.TotalSeconds > _timeout; } - } - protected override string? ConsoleReadLine() - { - InitTimeoutStopWatch(); - - while (!IsTopInstructionSend()) + private TimeoutException NewTimeoutException() { - if (TimeoutStopWatchExpired()) + lock (this) { - throw NewTimeoutException(); + var expected = _topInstructionExpect?.ToString(); + var expectingSomething = !string.IsNullOrWhiteSpace(expected); + var extra = expectingSomething ? $"; expected: {expected}" : ""; + return new TimeoutException($"Timeout expired after {_timeout} seconds{extra}."); } + } - if (DoneWithInstructions()) + protected override object? ResolveContext(string name) + { + lock (this) { - return ":quit"; + return resolvers.ContainsKey(name) ? resolvers[name] : null; } - - _topInstructionIsSend.WaitOne(100); } - return PopTopSendInstruction(); - } - - protected override void ConsoleWriteLine(string? output) - { - if (output == null) return; - - lock (this) + protected override string? ConsoleReadLine() { - base.ConsoleWriteLine(output); + InitTimeoutStopWatch(); - output += "\n"; - foreach (var ch in output) + while (!IsTopInstructionSend()) { - if (ch == '\n' || ch == '\r') + if (TimeoutStopWatchExpired()) { - var terminatedLine = _outputNotYetLineTerminated.ToString(); - _outputLinesNotYetChecked.Add(terminatedLine); - _outputNotYetLineTerminated.Clear(); + throw NewTimeoutException(); } - else + + if (DoneWithInstructions()) { - _outputNotYetLineTerminated.Append(ch); + return ":quit"; } + + _topInstructionIsSend.WaitOne(100); } - while (_topInstructionExpect != null && _outputLinesNotYetChecked.Count() > 0) + return PopTopSendInstruction(); + } + + protected override void ConsoleWriteLine(string? output) + { + if (output == null) return; + + lock (this) { - var line = _outputLinesNotYetChecked.First(); - _outputLinesNotYetChecked.RemoveAt(0); + base.ConsoleWriteLine(output); - var isMatch = _topInstructionExpect!.IsMatch(line, out var matched); - if (isMatch) + output += "\n"; + foreach (var ch in output) { - Console.ForegroundColor = ConsoleColor.Green; - Console.WriteLine($"***MATCH: Compared `{line}` (output) with `{matched}` (expected)."); - Console.ForegroundColor = ConsoleColor.White; - CheckDebugBreak(_topInstructionExpect); - PrepareNextInstruction(); - continue; + if (ch == '\n' || ch == '\r') + { + var terminatedLine = _outputNotYetLineTerminated.ToString(); + _outputLinesNotYetChecked.Add(terminatedLine); + _outputNotYetLineTerminated.Clear(); + } + else + { + _outputNotYetLineTerminated.Append(ch); + } } - Console.ForegroundColor = ConsoleColor.DarkYellow; - Console.WriteLine($"NO MATCH: Compared `{line}` (output) with `{_topInstructionExpect}` (expected)."); - Console.ForegroundColor = ConsoleColor.White; + while (_topInstructionExpect != null && _outputLinesNotYetChecked.Count() > 0) + { + var line = _outputLinesNotYetChecked.First(); + _outputLinesNotYetChecked.RemoveAt(0); + + var isMatch = _topInstructionExpect!.IsMatch(line, out var matched); + if (isMatch) + { + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine($"***MATCH: Compared `{line}` (output) with `{matched}` (expected)."); + Console.ForegroundColor = ConsoleColor.White; + CheckDebugBreak(_topInstructionExpect); + PrepareNextInstruction(); + continue; + } + + Console.ForegroundColor = ConsoleColor.DarkYellow; + Console.WriteLine($"NO MATCH: Compared `{line}` (output) with `{_topInstructionExpect}` (expected)."); + Console.ForegroundColor = ConsoleColor.White; + } } } - } - private void ConsoleSetTitle(string? title) - { - if (title != null) + private void ConsoleSetTitle(string? title) { - Console.Title = title; + if (title != null) + { + Console.Title = title; + } } - } - private void HandleSendInstruction(SendTestInstruction send, out bool waitForSend) - { - waitForSend = send.Format switch + private void HandleSendInstruction(SendTestInstruction send, out bool waitForSend) { - "wav" => HandleSendWavFileInstruction(send.Send!), - "tts" or "speak" => HandleSpeakTextInstruction(send.Send!), - "ssml" or "xml" => HandleSpeakSsmlInstruction(send.Send!), - _ => HandleSendTextInstruction(send.Send!) - }; - } + waitForSend = send.Format switch + { + "wav" => HandleSendWavFileInstruction(send.Send!), + "tts" or "speak" => HandleSpeakTextInstruction(send.Send!), + "ssml" or "xml" => HandleSpeakSsmlInstruction(send.Send!), + _ => HandleSendTextInstruction(send.Send!) + }; + } - private bool HandleSendWavFileInstruction(string fileName) - { - lock (this) + private bool HandleSendWavFileInstruction(string fileName) { - var stream = AudioDataStream.FromWavFileInput(fileName); - _audioDataStreams.Add(stream); - return false; + lock (this) + { + var stream = AudioDataStream.FromWavFileInput(fileName); + _audioDataStreams.Add(stream); + return false; + } } - } - private bool HandleSpeakTextInstruction(string text) - { - TestInstructionRequiresCommandSystemInitialized("Cannot generate speech w/ TTS"); - - var tempFile = Path.GetTempFileName() + ".wav"; + private bool HandleSpeakTextInstruction(string text) + { + TestInstructionRequiresCommandSystemInitialized("Cannot generate speech w/ TTS"); - var service = _commandSystem!.Services.GetRequiredService(); - service.SpeakText(text, null, tempFile, "no-barge-in").Wait(); + var tempFile = Path.GetTempFileName() + ".wav"; - var stream = AudioDataStream.FromWavFileInput(tempFile); - _audioDataStreams.Add(stream); + var service = _commandSystem!.Services.GetRequiredService(); + service.SpeakText(text, null, tempFile, "no-barge-in").Wait(); - return false; - } + var stream = AudioDataStream.FromWavFileInput(tempFile); + _audioDataStreams.Add(stream); - private bool HandleSpeakSsmlInstruction(string ssml) - { - TestInstructionRequiresCommandSystemInitialized("Cannot generate speech w/ TTS"); - var tempFile = Path.GetTempFileName() + ".wav"; + return false; + } - var service = _commandSystem!.Services.GetRequiredService(); - service.SpeakSsml(ssml, null, tempFile, "no-barge-in").Wait(); + private bool HandleSpeakSsmlInstruction(string ssml) + { + TestInstructionRequiresCommandSystemInitialized("Cannot generate speech w/ TTS"); + var tempFile = Path.GetTempFileName() + ".wav"; - var stream = AudioDataStream.FromWavFileInput(tempFile); - _audioDataStreams.Add(stream); + var service = _commandSystem!.Services.GetRequiredService(); + service.SpeakSsml(ssml, null, tempFile, "no-barge-in").Wait(); - return false; - } + var stream = AudioDataStream.FromWavFileInput(tempFile); + _audioDataStreams.Add(stream); - private bool HandleSendTextInstruction(string sendText) - { - _topInstructionSendValue = sendText; - _topInstructionIsSend.Set(); - ConsoleSetTitle(sendText); - return true; - } + return false; + } - private void HandleExpectInstruction(ExpectTestInstruction expect) - { - _topInstructionExpect = expect; - ConsoleSetTitle(expect.ToString()); - } + private bool HandleSendTextInstruction(string sendText) + { + _topInstructionSendValue = sendText; + _topInstructionIsSend.Set(); + ConsoleSetTitle(sendText); + return true; + } - private void HandleTimeoutInstruction(int timeout) - { - _timeout = timeout; - } + private void HandleExpectInstruction(ExpectTestInstruction expect) + { + _topInstructionExpect = expect; + ConsoleSetTitle(expect.ToString()); + } - private void HandleTemplateInstruction(string? name, string? value) - { - if (name != null && value != null) + private void HandleTimeoutInstruction(int timeout) { - _templates[name] = value; + _timeout = timeout; } - } - private void HandleBroadcastInstruction(string? message, string? value) - { - TestInstructionRequiresCommandSystemInitialized("Cannot broadcast message"); + private void HandleTemplateInstruction(string? name, string? value) + { + if (name != null && value != null) + { + _templates[name] = value; + } + } - if (message != null) + private void HandleBroadcastInstruction(string? message, string? value) { - var service = _commandSystem!.Services!.GetRequiredService(); - service!.BroadcastMessage(message, value, null); + TestInstructionRequiresCommandSystemInitialized("Cannot broadcast message"); + + if (message != null) + { + var service = _commandSystem!.Services!.GetRequiredService(); + service!.BroadcastMessage(message, value, null); + } } - } - private void HandleResolveInstruction(string? name, string? value) - { - lock (this) + private void HandleResolveInstruction(string? name, string? value) { - if (name != null) + lock (this) { - if (value == null) + if (name != null) { - resolvers.Remove(name); - } - else - { - resolvers[name] = value; + if (value == null) + { + resolvers.Remove(name); + } + else + { + resolvers[name] = value; + } } } } - } - private int ReadTestAudio(byte[] buffer, uint size) - { - lock (this) + private int ReadTestAudio(byte[] buffer, uint size) { - if (_audioDataStreams.Count == 0) + lock (this) { - return FakeReadFillWithZeros(buffer, size); - } + if (_audioDataStreams.Count == 0) + { + return FakeReadFillWithZeros(buffer, size); + } - var stream = _audioDataStreams[0]; - var read = stream.ReadData(buffer); - if (read < size) - { - FakeReadFillWithZeros(buffer, (int)read, size - read); - _audioDataStreams.RemoveAt(0); - stream.Dispose(); + var stream = _audioDataStreams[0]; + var read = stream.ReadData(buffer); + if (read < size) + { + FakeReadFillWithZeros(buffer, (int)read, size - read); + _audioDataStreams.RemoveAt(0); + stream.Dispose(); + } + + return (int)size; } + } + private static int FakeReadFillWithZeros(byte[] buffer, int start, uint size) + { + Array.Fill(buffer, 0, start, (int)size); return (int)size; } - } - private static int FakeReadFillWithZeros(byte[] buffer, int start, uint size) - { - Array.Fill(buffer, 0, start, (int)size); - return (int)size; - } - - private static int FakeReadFillWithZeros(byte[] buffer, uint size) - { - return FakeReadFillWithZeros(buffer, 0, size); - } - - private void TestInstructionRequiresCommandSystemInitialized(string message) - { - if (_commandSystem == null || _commandSystem.Services == null) + private static int FakeReadFillWithZeros(byte[] buffer, uint size) { - throw CommandSystemNotInitializedTestFormatInvalidException(message); + return FakeReadFillWithZeros(buffer, 0, size); } - } - private static FormatException CommandSystemNotInitializedTestFormatInvalidException(string message) - { - return new FormatException($"{message}; CommandSystem not initialized; Are you missing `- expect: '*Started!!*'` test instruction?"); - } - private static void CheckDebugBreak(ExpectTestInstruction expect) - { - if (expect.DebugBreak) + private void TestInstructionRequiresCommandSystemInitialized(string message) { - DebugBreak(); + if (_commandSystem == null || _commandSystem.Services == null) + { + throw CommandSystemNotInitializedTestFormatInvalidException(message); + } + } + private static FormatException CommandSystemNotInitializedTestFormatInvalidException(string message) + { + return new FormatException($"{message}; CommandSystem not initialized; Are you missing `- expect: '*Started!!*'` test instruction?"); } - } - private static void DebugBreak() - { - Console.Write("Waiting for debugger..."); + private static void CheckDebugBreak(ExpectTestInstruction expect) + { + if (expect.DebugBreak) + { + DebugBreak(); + } + } - var sleepDuration = 100; - var msToWaitRemaining = 20000; - while (!System.Diagnostics.Debugger.IsAttached) + private static void DebugBreak() { - Thread.Sleep(sleepDuration); - Console.Write('.'); + Console.Write("Waiting for debugger..."); - msToWaitRemaining -= sleepDuration; - if (msToWaitRemaining <= 0) break; - } + var sleepDuration = 100; + var msToWaitRemaining = 20000; + while (!System.Diagnostics.Debugger.IsAttached) + { + Thread.Sleep(sleepDuration); + Console.Write('.'); - Console.WriteLine("\n"); - System.Diagnostics.Debugger.Break(); - } + msToWaitRemaining -= sleepDuration; + if (msToWaitRemaining <= 0) break; + } - private Dictionary _templates = new(); - private TestInstructionCollection? _testInstructions; - private ExpectTestInstruction? _topInstructionExpect; - private string? _topInstructionSendValue; - private ManualResetEvent _topInstructionIsSend = new(false); + Console.WriteLine("\n"); + System.Diagnostics.Debugger.Break(); + } + + private Dictionary _templates = new Dictionary(); + private TestInstructionCollection? _testInstructions; + private ExpectTestInstruction? _topInstructionExpect; + private string? _topInstructionSendValue; + private ManualResetEvent _topInstructionIsSend = new ManualResetEvent(false); - Stopwatch _stopwatch = new(); - int _timeout = 60; + Stopwatch _stopwatch = new Stopwatch(); + int _timeout = 60; - private List _outputLinesNotYetChecked = new(); - private StringBuilder _outputNotYetLineTerminated = new(); + private List _outputLinesNotYetChecked = new List(); + private StringBuilder _outputNotYetLineTerminated = new StringBuilder(); - private Dictionary resolvers = new(); + private Dictionary resolvers = new Dictionary(); - private List _audioDataStreams = new(); -} + private List _audioDataStreams = new List(); + } +} \ No newline at end of file diff --git a/src/mr/ExpectTestInstruction.cs b/src/mr/ExpectTestInstruction.cs index 65a077ef..81bc9d27 100644 --- a/src/mr/ExpectTestInstruction.cs +++ b/src/mr/ExpectTestInstruction.cs @@ -1,78 +1,79 @@ -namespace macaroni; - -class ExpectTestInstruction : TestInstruction +namespace macaroni { - public override string? Kind => "expect"; - public readonly List Expect; - public bool DebugBreak = false; - - public ExpectTestInstruction(string? expect) + class ExpectTestInstruction : TestInstruction { - Expect = expect?.Split(';', StringSplitOptions.RemoveEmptyEntries).ToList() ?? new(); - } + public override string? Kind => "expect"; + public readonly List Expect; + public bool DebugBreak = false; - public ExpectTestInstruction(IEnumerable? expect) - { - Expect = expect?.ToList() ?? new(); - } - - public bool IsMatch(string? check, out string? matched) - { - matched = null; - if (Expect?.Count == 0) return false; + public ExpectTestInstruction(string? expect) + { + Expect = expect?.Split(';', StringSplitOptions.RemoveEmptyEntries).ToList() ?? new(); + } - // check to see if the line matches any of the expected values - // note: expected values are either exact matches, or if they start and end with an asterisk, they are partial matches - // note: matched is set to the expected value if it is a partial match + public ExpectTestInstruction(IEnumerable? expect) + { + Expect = expect?.ToList() ?? new(); + } - foreach (var expect in Expect!) + public bool IsMatch(string? check, out string? matched) { - if (expect.StartsWith('*') && expect.EndsWith('*')) + matched = null; + if (Expect?.Count == 0) return false; + + // check to see if the line matches any of the expected values + // note: expected values are either exact matches, or if they start and end with an asterisk, they are partial matches + // note: matched is set to the expected value if it is a partial match + + foreach (var expect in Expect!) { - if (check?.Contains(expect[1..^1]) == true) + if (expect.StartsWith('*') && expect.EndsWith('*')) { - matched = expect; - return true; + if (check?.Contains(expect[1..^1]) == true) + { + matched = expect; + return true; + } } - } - else if (expect.StartsWith('*')) - { - if (check?.EndsWith(expect[1..]) == true) + else if (expect.StartsWith('*')) { - matched = expect; - return true; + if (check?.EndsWith(expect[1..]) == true) + { + matched = expect; + return true; + } } - } - else if (expect.EndsWith('*')) - { - if (check?.StartsWith(expect[..^1]) == true) + else if (expect.EndsWith('*')) + { + if (check?.StartsWith(expect[..^1]) == true) + { + matched = expect; + return true; + } + } + else if (check == expect) { matched = expect; return true; } } - else if (check == expect) - { - matched = expect; - return true; - } - } - return false; - } + return false; + } - public override string ToString() - { - // if there are multiple expected values, join them with commas - if (Expect?.Count > 1) + public override string ToString() { - var joined = string.Join("\", \"", Expect); - return $"One of: [ \"{joined}\" ]"; - } + // if there are multiple expected values, join them with commas + if (Expect?.Count > 1) + { + var joined = string.Join("\", \"", Expect); + return $"One of: [ \"{joined}\" ]"; + } - // otherwise, just return the expected value - return Expect?.Count == 1 - ? Expect[0] - : string.Empty; - } -} + // otherwise, just return the expected value + return Expect?.Count == 1 + ? Expect[0] + : string.Empty; + } + } +} \ No newline at end of file diff --git a/src/mr/Program.cs b/src/mr/Program.cs index d91fbdbe..a6e4c772 100644 --- a/src/mr/Program.cs +++ b/src/mr/Program.cs @@ -1,347 +1,348 @@ -global using Microsoft.Extensions.Hosting; -global using Microsoft.Extensions.DependencyInjection; +global using Microsoft.Extensions.DependencyInjection; +global using Microsoft.Extensions.Hosting; using System.CommandLine; using System.CommandLine.Invocation; -namespace macaroni; - -static class Program +namespace macaroni { - public const int TimeoutException = -3; - public const int UnhandledException = -2; - public const int BadCommandLine = -1; - public const int ProgramSucceeded = 0; - public const int ParseSucceeded = 0; - public const int FileNotFound = 1; - public const int ParseFailed = 2; - - static int Main(string[] args) + static class Program { - args = UpdateArgs(args); - - var mrCommands = new RootCommand("Macaroni Runner"); - - var mrInitCommand = new Command("init", "Initializes settings for Macaroni Runner"); - - var mrParseCommand = new Command("parse", "Parse one or more command set(s)"); - mrParseCommand.Add(fileArgument); - - var mrRunCommand = new Command("run", "Run one or more command set(s)"); - mrRunCommand.Add(fileArgument); - mrRunCommand.Add(componentAssemblyOption); - mrRunCommand.Add(logOption); - mrRunCommand.Add(secretOption); - mrRunCommand.Add(defaultListeningStateOption); - mrRunCommand.Add(keywordOption); - mrRunCommand.Add(keywordModelOption); - mrRunCommand.Add(highRecallCluOption); - mrRunCommand.Add(highRecallNuggetsOption); - mrRunCommand.Add(keyVaultUriOption); - mrRunCommand.Add(keyVaultTenantIdOption); - mrRunCommand.Add(keyVaultClientIdOption); - - var mrTestCommand = new Command("test", "Test one or more command set(s)"); - mrTestCommand.Add(testArgument); - mrTestCommand.Add(fileArgument); - mrTestCommand.Add(componentAssemblyOption); - mrTestCommand.Add(logOption); - mrTestCommand.Add(secretOption); - mrTestCommand.Add(defaultListeningStateOption); - mrTestCommand.Add(keywordOption); - mrTestCommand.Add(keywordModelOption); - mrTestCommand.Add(highRecallCluOption); - mrTestCommand.Add(highRecallNuggetsOption); - mrTestCommand.Add(keyVaultUriOption); - mrTestCommand.Add(keyVaultTenantIdOption); - mrTestCommand.Add(keyVaultClientIdOption); - - mrCommands.Add(mrInitCommand); - mrCommands.Add(mrParseCommand); - mrCommands.Add(mrRunCommand); - mrCommands.Add(mrTestCommand); - - mrInitCommand.SetHandler(context => context.ExitCode = Init(context)); - mrParseCommand.SetHandler(context => context.ExitCode = Parse(context)); - mrRunCommand.SetHandler(context => context.ExitCode = Run(context)); - mrTestCommand.SetHandler(context => context.ExitCode = Test(context)); - - return mrCommands.InvokeAsync(args).Result; - } + public const int TimeoutException = -3; + public const int UnhandledException = -2; + public const int BadCommandLine = -1; + public const int ProgramSucceeded = 0; + public const int ParseSucceeded = 0; + public const int FileNotFound = 1; + public const int ParseFailed = 2; + + static int Main(string[] args) + { + args = UpdateArgs(args); + + var mrCommands = new RootCommand("Macaroni Runner"); + + var mrInitCommand = new Command("init", "Initializes settings for Macaroni Runner"); + + var mrParseCommand = new Command("parse", "Parse one or more command set(s)"); + mrParseCommand.Add(fileArgument); + + var mrRunCommand = new Command("run", "Run one or more command set(s)"); + mrRunCommand.Add(fileArgument); + mrRunCommand.Add(componentAssemblyOption); + mrRunCommand.Add(logOption); + mrRunCommand.Add(secretOption); + mrRunCommand.Add(defaultListeningStateOption); + mrRunCommand.Add(keywordOption); + mrRunCommand.Add(keywordModelOption); + mrRunCommand.Add(highRecallCluOption); + mrRunCommand.Add(highRecallNuggetsOption); + mrRunCommand.Add(keyVaultUriOption); + mrRunCommand.Add(keyVaultTenantIdOption); + mrRunCommand.Add(keyVaultClientIdOption); + + var mrTestCommand = new Command("test", "Test one or more command set(s)"); + mrTestCommand.Add(testArgument); + mrTestCommand.Add(fileArgument); + mrTestCommand.Add(componentAssemblyOption); + mrTestCommand.Add(logOption); + mrTestCommand.Add(secretOption); + mrTestCommand.Add(defaultListeningStateOption); + mrTestCommand.Add(keywordOption); + mrTestCommand.Add(keywordModelOption); + mrTestCommand.Add(highRecallCluOption); + mrTestCommand.Add(highRecallNuggetsOption); + mrTestCommand.Add(keyVaultUriOption); + mrTestCommand.Add(keyVaultTenantIdOption); + mrTestCommand.Add(keyVaultClientIdOption); + + mrCommands.Add(mrInitCommand); + mrCommands.Add(mrParseCommand); + mrCommands.Add(mrRunCommand); + mrCommands.Add(mrTestCommand); + + mrInitCommand.SetHandler(context => context.ExitCode = Init(context)); + mrParseCommand.SetHandler(context => context.ExitCode = Parse(context)); + mrRunCommand.SetHandler(context => context.ExitCode = Run(context)); + mrTestCommand.SetHandler(context => context.ExitCode = Test(context)); + + return mrCommands.InvokeAsync(args).Result; + } - private static string[] UpdateArgs(string[] args) - { - if (args.Length <= 1) return args; + private static string[] UpdateArgs(string[] args) + { + if (args.Length <= 1) return args; - var command = args.First(x => !x.StartsWith('-') && !x.StartsWith('[')); - var found = FindConfigFile($"{command}.defaults"); - if (found == null) return args; + var command = args.First(x => !x.StartsWith('-') && !x.StartsWith('[')); + var found = FindConfigFile($"{command}.defaults"); + if (found == null) return args; - var list = new List(); - foreach (var arg in args) - { - if (found != null && arg.StartsWith("--")) + var list = new List(); + foreach (var arg in args) + { + if (found != null && arg.StartsWith("--")) + { + list.Add($"@{found}"); + found = null; + } + list.Add(arg); + } + + if (found != null) { list.Add($"@{found}"); - found = null; } - list.Add(arg); - } - if (found != null) - { - list.Add($"@{found}"); + return list.ToArray(); } - return list.ToArray(); - } - - public static string? FindConfigFile(string name) - { - var dir = new DirectoryInfo(Directory.GetCurrentDirectory()); - while (dir != null && dir.Exists) + public static string? FindConfigFile(string name) { - var combined = Path.Combine(dir.FullName, name); - if (File.Exists(combined)) return combined; + var dir = new DirectoryInfo(Directory.GetCurrentDirectory()); + while (dir != null && dir.Exists) + { + var combined = Path.Combine(dir.FullName, name); + if (File.Exists(combined)) return combined; - combined = Path.Combine(dir.FullName, ".mr", name); - if (File.Exists(combined)) return combined; + combined = Path.Combine(dir.FullName, ".mr", name); + if (File.Exists(combined)) return combined; - dir = dir.Parent; + dir = dir.Parent; + } + return null; } - return null; - } - - private static int Init(InvocationContext context) - { - Console.WriteLine("Initializing Macaroni Runner settings..."); - Console.WriteLine(); - - var lines = new List(); - PromptAndReadLine(lines, "Enter Key Vault URI: ", "--keyvault-uri"); - PromptAndReadLine(lines, "Enter Key Vault Tenant ID: ", "--keyvault-tenant-id"); - PromptAndReadLine(lines, "Enter Key Vault Client ID: ", "--keyvault-client-id"); - Console.WriteLine(); - - PromptAndReadLine(lines, "Enter default listening state (\"sleep\" or \"off\"): ", "--default-listening-state"); - PromptAndReadLine(lines, "Enter keyword: ", "--keyword"); - PromptAndReadLine(lines, "Enter keyword model: ", "--keyword-model"); - Console.WriteLine(); - - PromptAndReadLine(lines, "Enter high recall CLU: ", "--high-recall-clu"); - PromptAndReadLine(lines, "Enter high recall nuggets: ", "--high-recall-nuggets"); - Console.WriteLine(); - - PromptAndReadLine(lines, "Enter secret CLU_KEY: ", "--secret CLU_KEY"); - PromptAndReadLine(lines, "Enter secret CLU_ENDPOINT: ", "--secret CLU_ENDPOINT"); - PromptAndReadLine(lines, "Enter secret CLU_DEPLOYMENT_NAME: ", "--secret CLU_DEPLOYMENT_NAME"); - PromptAndReadLine(lines, "Enter secret CLU_PROJECT_NAME: ", "--secret CLU_PROJECT_NAME"); - Console.WriteLine(); - - PromptAndReadLine(lines, "Enter secret OPEN_AI_KEY: ", "--secret OPEN_AI_KEY"); - PromptAndReadLine(lines, "Enter secret OPEN_AI_ENDPOINT: ", "--secret OPEN_AI_ENDPOINT"); - PromptAndReadLine(lines, "Enter secret OPEN_AI_DEPLOYMENT: ", "--secret OPEN_AI_DEPLOYMENT"); - Console.WriteLine(); - - PromptAndReadLine(lines, "Enter secret SPEECH_KEY: ", "--secret SPEECH_KEY"); - PromptAndReadLine(lines, "Enter secret SPEECH_REGION: ", "--secret SPEECH_REGION"); - PromptAndReadLine(lines, "Enter secret SPEECH_RECOGNITION_ENDPOINT: ", "--secret SPEECH_RECOGNITION_ENDPOINT"); - PromptAndReadLine(lines, "Enter secret SPEECH_CUSTOM_RECOGNITION_ENDPOINT_ID: ", "--secret SPEECH_CUSTOM_RECOGNITION_ENDPOINT_ID"); - PromptAndReadLine(lines, "Enter secret SPEECH_SYNTHESIS_ENDPOINT: ", "--secret SPEECH_SYNTHESIS_ENDPOINT"); - PromptAndReadLine(lines, "Enter secret SPEECH_CUSTOM_SYNTHESIS_ENDPOINT_ID: ", "--secret SPEECH_CUSTOM_SYNTHESIS_ENDPOINT_ID"); - Console.WriteLine(); - - PromptAndReadLine(lines, "Enter secret TRANSLATOR_KEY: ", "--secret TRANSLATOR_KEY"); - PromptAndReadLine(lines, "Enter secret TRANSLATOR_REGION: ", "--secret TRANSLATOR_REGION"); - PromptAndReadLine(lines, "Enter secret TRANSLATOR_ENDPOINT: ", "--secret TRANSLATOR_ENDPOINT"); - Console.WriteLine(); - - PromptAndReadLine(lines, "Enter secret VISION_KEY: ", "--secret VISION_KEY"); - PromptAndReadLine(lines, "Enter secret VISION_REGION: ", "--secret VISION_REGION"); - PromptAndReadLine(lines, "Enter secret VISION_ENDPOINT: ", "--secret VISION_ENDPOINT"); - Console.WriteLine(); - - string dir = EnsureDirectory(".mr"); - WriteAllLinesIfFileDoesntExist(lines, Path.Combine(dir, "run.defaults")); - WriteAllLinesIfFileDoesntExist(lines, Path.Combine(dir, "test.defaults")); - - Console.ForegroundColor = ConsoleColor.Cyan; - lines.ForEach(x => Console.WriteLine($" {x}")); - Console.ResetColor(); - Console.WriteLine(); - - return 0; - } - - private static void PromptAndReadLine(List lines, string prompt, string option) - { - Console.Write(prompt); - - Console.ForegroundColor = ConsoleColor.Cyan; - var input = Console.ReadLine(); - Console.ResetColor(); - if (!string.IsNullOrEmpty(input)) + private static int Init(InvocationContext context) { - lines.Add($"{option}={input}"); + Console.WriteLine("Initializing Macaroni Runner settings..."); + Console.WriteLine(); + + var lines = new List(); + PromptAndReadLine(lines, "Enter Key Vault URI: ", "--keyvault-uri"); + PromptAndReadLine(lines, "Enter Key Vault Tenant ID: ", "--keyvault-tenant-id"); + PromptAndReadLine(lines, "Enter Key Vault Client ID: ", "--keyvault-client-id"); + Console.WriteLine(); + + PromptAndReadLine(lines, "Enter default listening state (\"sleep\" or \"off\"): ", "--default-listening-state"); + PromptAndReadLine(lines, "Enter keyword: ", "--keyword"); + PromptAndReadLine(lines, "Enter keyword model: ", "--keyword-model"); + Console.WriteLine(); + + PromptAndReadLine(lines, "Enter high recall CLU: ", "--high-recall-clu"); + PromptAndReadLine(lines, "Enter high recall nuggets: ", "--high-recall-nuggets"); + Console.WriteLine(); + + PromptAndReadLine(lines, "Enter secret CLU_KEY: ", "--secret CLU_KEY"); + PromptAndReadLine(lines, "Enter secret CLU_ENDPOINT: ", "--secret CLU_ENDPOINT"); + PromptAndReadLine(lines, "Enter secret CLU_DEPLOYMENT_NAME: ", "--secret CLU_DEPLOYMENT_NAME"); + PromptAndReadLine(lines, "Enter secret CLU_PROJECT_NAME: ", "--secret CLU_PROJECT_NAME"); + Console.WriteLine(); + + PromptAndReadLine(lines, "Enter secret OPEN_AI_KEY: ", "--secret OPEN_AI_KEY"); + PromptAndReadLine(lines, "Enter secret OPEN_AI_ENDPOINT: ", "--secret OPEN_AI_ENDPOINT"); + PromptAndReadLine(lines, "Enter secret OPEN_AI_DEPLOYMENT: ", "--secret OPEN_AI_DEPLOYMENT"); + Console.WriteLine(); + + PromptAndReadLine(lines, "Enter secret SPEECH_KEY: ", "--secret SPEECH_KEY"); + PromptAndReadLine(lines, "Enter secret SPEECH_REGION: ", "--secret SPEECH_REGION"); + PromptAndReadLine(lines, "Enter secret SPEECH_RECOGNITION_ENDPOINT: ", "--secret SPEECH_RECOGNITION_ENDPOINT"); + PromptAndReadLine(lines, "Enter secret SPEECH_CUSTOM_RECOGNITION_ENDPOINT_ID: ", "--secret SPEECH_CUSTOM_RECOGNITION_ENDPOINT_ID"); + PromptAndReadLine(lines, "Enter secret SPEECH_SYNTHESIS_ENDPOINT: ", "--secret SPEECH_SYNTHESIS_ENDPOINT"); + PromptAndReadLine(lines, "Enter secret SPEECH_CUSTOM_SYNTHESIS_ENDPOINT_ID: ", "--secret SPEECH_CUSTOM_SYNTHESIS_ENDPOINT_ID"); + Console.WriteLine(); + + PromptAndReadLine(lines, "Enter secret TRANSLATOR_KEY: ", "--secret TRANSLATOR_KEY"); + PromptAndReadLine(lines, "Enter secret TRANSLATOR_REGION: ", "--secret TRANSLATOR_REGION"); + PromptAndReadLine(lines, "Enter secret TRANSLATOR_ENDPOINT: ", "--secret TRANSLATOR_ENDPOINT"); + Console.WriteLine(); + + PromptAndReadLine(lines, "Enter secret VISION_KEY: ", "--secret VISION_KEY"); + PromptAndReadLine(lines, "Enter secret VISION_REGION: ", "--secret VISION_REGION"); + PromptAndReadLine(lines, "Enter secret VISION_ENDPOINT: ", "--secret VISION_ENDPOINT"); + Console.WriteLine(); + + string dir = EnsureDirectory(".mr"); + WriteAllLinesIfFileDoesntExist(lines, Path.Combine(dir, "run.defaults")); + WriteAllLinesIfFileDoesntExist(lines, Path.Combine(dir, "test.defaults")); + + Console.ForegroundColor = ConsoleColor.Cyan; + lines.ForEach(x => Console.WriteLine($" {x}")); + Console.ResetColor(); + Console.WriteLine(); + + return 0; } - } - - private static string EnsureDirectory(string newDirectoryName) - { - var dir = new DirectoryInfo(Directory.GetCurrentDirectory()); - var combined = Path.Combine(dir.FullName, newDirectoryName); - if (!Directory.Exists(combined)) + private static void PromptAndReadLine(List lines, string prompt, string option) { - Directory.CreateDirectory(combined); - } + Console.Write(prompt); - return combined; - } + Console.ForegroundColor = ConsoleColor.Cyan; + var input = Console.ReadLine(); + Console.ResetColor(); - private static void WriteAllLinesIfFileDoesntExist(List lines, string combinedFileName) - { - if (File.Exists(combinedFileName)) - { - Console.WriteLine($"File {combinedFileName} already exists. Skipping."); - return; + if (!string.IsNullOrEmpty(input)) + { + lines.Add($"{option}={input}"); + } } - File.WriteAllLines(combinedFileName, lines); - Console.WriteLine($"Saved to {combinedFileName}"); - } - - private static int Parse(List files) - { - return files.Max(x => CommandSetParseChecker.ParseOneOrMoreFiles(x.FullName)); - } - - private static int Parse(InvocationContext context) - { - WaitForDebugger(context); + private static string EnsureDirectory(string newDirectoryName) + { + var dir = new DirectoryInfo(Directory.GetCurrentDirectory()); - var files = context.ParseResult.GetValueForArgument(fileArgument); - return Parse(files); - } + var combined = Path.Combine(dir.FullName, newDirectoryName); + if (!Directory.Exists(combined)) + { + Directory.CreateDirectory(combined); + } - private static int Run(InvocationContext context) - { - WaitForDebugger(context); + return combined; + } - var files = context.ParseResult.GetValueForArgument(fileArgument); + private static void WriteAllLinesIfFileDoesntExist(List lines, string combinedFileName) + { + if (File.Exists(combinedFileName)) + { + Console.WriteLine($"File {combinedFileName} already exists. Skipping."); + return; + } - var parsed = Parse(files); - if (parsed != ParseSucceeded) return parsed; + File.WriteAllLines(combinedFileName, lines); + Console.WriteLine($"Saved to {combinedFileName}"); + } - try + private static int Parse(List files) { - var runner = new CommandSetRunner( - context.ParseResult.GetValueForOption(keyVaultUriOption), - context.ParseResult.GetValueForOption(keyVaultTenantIdOption), - context.ParseResult.GetValueForOption(keyVaultClientIdOption)); - - var components = context.ParseResult.GetValueForOption(componentAssemblyOption); - - var runResult = runner.Run( - files.Select(x => x.FullName).ToList(), - components?.Select(x => x.FullName).ToList(), - context.ParseResult.GetValueForOption(logOption)?.FullName, - context.ParseResult.GetValueForOption(secretOption), - context.ParseResult.GetValueForOption(defaultListeningStateOption), - context.ParseResult.GetValueForOption(keywordOption), - context.ParseResult.GetValueForOption(keywordModelOption), - context.ParseResult.GetValueForOption(highRecallCluOption), - context.ParseResult.GetValueForOption(highRecallNuggetsOption)); - - System.Diagnostics.Debug.WriteLine("RUN: " + (runResult == 0 ? "PASSED" : "FAILED")); - return runResult; + return files.Max(x => CommandSetParseChecker.ParseOneOrMoreFiles(x.FullName)); } - catch (Exception ex) + + private static int Parse(InvocationContext context) { - Console.WriteLine($"\nEXCEPTION: {ex}"); - return UnhandledException; + WaitForDebugger(context); + + var files = context.ParseResult.GetValueForArgument(fileArgument); + return Parse(files); } - } - private static int Test(InvocationContext context) - { - WaitForDebugger(context); + private static int Run(InvocationContext context) + { + WaitForDebugger(context); - var files = context.ParseResult.GetValueForArgument(fileArgument); - var test = context.ParseResult.GetValueForArgument(testArgument); + var files = context.ParseResult.GetValueForArgument(fileArgument); - var parsed = Parse(files); - if (parsed != ParseSucceeded) return parsed; + var parsed = Parse(files); + if (parsed != ParseSucceeded) return parsed; - try - { - var runner = new CommandSetTestRunner( - context.ParseResult.GetValueForOption(keyVaultUriOption), - context.ParseResult.GetValueForOption(keyVaultTenantIdOption), - context.ParseResult.GetValueForOption(keyVaultClientIdOption)); - - var components = context.ParseResult.GetValueForOption(componentAssemblyOption); - - var testResult = runner.RunTest( - files.Select(x => x.FullName).ToList(), - components?.Select(x => x.FullName).ToList(), - test.FullName, - context.ParseResult.GetValueForOption(logOption)?.FullName, - context.ParseResult.GetValueForOption(secretOption), - context.ParseResult.GetValueForOption(defaultListeningStateOption), - context.ParseResult.GetValueForOption(keywordOption), - context.ParseResult.GetValueForOption(keywordModelOption), - context.ParseResult.GetValueForOption(highRecallCluOption), - context.ParseResult.GetValueForOption(highRecallNuggetsOption)); - - System.Diagnostics.Debug.WriteLine("TEST: " + (testResult == 0 ? "PASSED" : "FAILED")); - return testResult; + try + { + var runner = new CommandSetRunner( + context.ParseResult.GetValueForOption(keyVaultUriOption), + context.ParseResult.GetValueForOption(keyVaultTenantIdOption), + context.ParseResult.GetValueForOption(keyVaultClientIdOption)); + + var components = context.ParseResult.GetValueForOption(componentAssemblyOption); + + var runResult = runner.Run( + files.Select(x => x.FullName).ToList(), + components?.Select(x => x.FullName).ToList(), + context.ParseResult.GetValueForOption(logOption)?.FullName, + context.ParseResult.GetValueForOption(secretOption), + context.ParseResult.GetValueForOption(defaultListeningStateOption), + context.ParseResult.GetValueForOption(keywordOption), + context.ParseResult.GetValueForOption(keywordModelOption), + context.ParseResult.GetValueForOption(highRecallCluOption), + context.ParseResult.GetValueForOption(highRecallNuggetsOption)); + + System.Diagnostics.Debug.WriteLine("RUN: " + (runResult == 0 ? "PASSED" : "FAILED")); + return runResult; + } + catch (Exception ex) + { + Console.WriteLine($"\nEXCEPTION: {ex}"); + return UnhandledException; + } } - catch (Exception ex) + + private static int Test(InvocationContext context) { - Console.WriteLine($"\nEXCEPTION: {ex}"); - return UnhandledException; + WaitForDebugger(context); + + var files = context.ParseResult.GetValueForArgument(fileArgument); + var test = context.ParseResult.GetValueForArgument(testArgument); + + var parsed = Parse(files); + if (parsed != ParseSucceeded) return parsed; + + try + { + var runner = new CommandSetTestRunner( + context.ParseResult.GetValueForOption(keyVaultUriOption), + context.ParseResult.GetValueForOption(keyVaultTenantIdOption), + context.ParseResult.GetValueForOption(keyVaultClientIdOption)); + + var components = context.ParseResult.GetValueForOption(componentAssemblyOption); + + var testResult = runner.RunTest( + files.Select(x => x.FullName).ToList(), + components?.Select(x => x.FullName).ToList(), + test.FullName, + context.ParseResult.GetValueForOption(logOption)?.FullName, + context.ParseResult.GetValueForOption(secretOption), + context.ParseResult.GetValueForOption(defaultListeningStateOption), + context.ParseResult.GetValueForOption(keywordOption), + context.ParseResult.GetValueForOption(keywordModelOption), + context.ParseResult.GetValueForOption(highRecallCluOption), + context.ParseResult.GetValueForOption(highRecallNuggetsOption)); + + System.Diagnostics.Debug.WriteLine("TEST: " + (testResult == 0 ? "PASSED" : "FAILED")); + return testResult; + } + catch (Exception ex) + { + Console.WriteLine($"\nEXCEPTION: {ex}"); + return UnhandledException; + } } - } - private static void WaitForDebugger(InvocationContext context) - { - var waitForDebugger = context.ParseResult.Directives.Contains("debug"); - if (waitForDebugger) + private static void WaitForDebugger(InvocationContext context) { - Console.Write("Waiting for debugger..."); - - var sleepDuration = 100; - var msToWaitRemaining = 20000; - while (!System.Diagnostics.Debugger.IsAttached) + var waitForDebugger = context.ParseResult.Directives.Contains("debug"); + if (waitForDebugger) { - Thread.Sleep(sleepDuration); - Console.Write('.'); + Console.Write("Waiting for debugger..."); - msToWaitRemaining -= sleepDuration; - if (msToWaitRemaining <= 0) break; - } + var sleepDuration = 100; + var msToWaitRemaining = 20000; + while (!System.Diagnostics.Debugger.IsAttached) + { + Thread.Sleep(sleepDuration); + Console.Write('.'); - Console.WriteLine("\n"); - System.Diagnostics.Debugger.Break(); + msToWaitRemaining -= sleepDuration; + if (msToWaitRemaining <= 0) break; + } + + Console.WriteLine("\n"); + System.Diagnostics.Debugger.Break(); + } } - } - private static readonly Argument> fileArgument = new() { Name = "file", Description = "Command set file to parse, run, or test", Arity = ArgumentArity.OneOrMore }; - private static readonly Argument testArgument = new() { Name = "test", Description = "Test instructions file; send input and expect output", Arity = ArgumentArity.ExactlyOne }; + private static readonly Argument> fileArgument = new() { Name = "file", Description = "Command set file to parse, run, or test", Arity = ArgumentArity.OneOrMore }; + private static readonly Argument testArgument = new() { Name = "test", Description = "Test instructions file; send input and expect output", Arity = ArgumentArity.ExactlyOne }; - private static readonly Option logOption = new("--log", "path for command system logging"); - private static readonly Option> secretOption = new("--secret", "name=value"); - private static readonly Option> componentAssemblyOption = new Option>("--component-assembly", "Component assembly to load"); + private static readonly Option logOption = new("--log", "path for command system logging"); + private static readonly Option> secretOption = new("--secret", "name=value"); + private static readonly Option> componentAssemblyOption = new Option>("--component-assembly", "Component assembly to load"); - private static readonly Option keyVaultUriOption = new Option("--keyvault-uri" , "Azure Key Vault URI"); - private static readonly Option keyVaultClientIdOption = new Option("--keyvault-client-id", "Azure Key Vault Client ID"); - private static readonly Option keyVaultTenantIdOption = new Option("--keyvault-tenant-id", "Azure Key Vault Tenant ID"); + private static readonly Option keyVaultUriOption = new Option("--keyvault-uri", "Azure Key Vault URI"); + private static readonly Option keyVaultClientIdOption = new Option("--keyvault-client-id", "Azure Key Vault Client ID"); + private static readonly Option keyVaultTenantIdOption = new Option("--keyvault-tenant-id", "Azure Key Vault Tenant ID"); - private static readonly Option defaultListeningStateOption = new Option("--default-listening-state", "listening state to use when command system stops listening").FromAmong("off", "sleep"); - private static readonly Option keywordOption = new Option("--keyword", "keyword text (e.g. Copilot)"); - private static readonly Option keywordModelOption = new Option("--keyword-model", "keyword model file (e.g. copilot_default.table)"); + private static readonly Option defaultListeningStateOption = new Option("--default-listening-state", "listening state to use when command system stops listening").FromAmong("off", "sleep"); + private static readonly Option keywordOption = new Option("--keyword", "keyword text (e.g. Copilot)"); + private static readonly Option keywordModelOption = new Option("--keyword-model", "keyword model file (e.g. copilot_default.table)"); - private static readonly Option highRecallCluOption = new Option("--high-recall-clu", "use CLU as high recall back-off to pattern matching"); - private static readonly Option highRecallNuggetsOption = new Option("--high-recall-nuggets", "use Nuggets as high recall back-off to pattern matching"); -} + private static readonly Option highRecallCluOption = new Option("--high-recall-clu", "use CLU as high recall back-off to pattern matching"); + private static readonly Option highRecallNuggetsOption = new Option("--high-recall-nuggets", "use Nuggets as high recall back-off to pattern matching"); + } +} \ No newline at end of file diff --git a/src/mr/ResolveTestInstruction.cs b/src/mr/ResolveTestInstruction.cs index 96c9fd32..d36d815e 100644 --- a/src/mr/ResolveTestInstruction.cs +++ b/src/mr/ResolveTestInstruction.cs @@ -1,8 +1,9 @@ -namespace macaroni; - -class ResolveTestInstruction : TestInstruction +namespace macaroni { - public override string? Kind => "resolve"; - public string? Name; - public string? Value; -} + class ResolveTestInstruction : TestInstruction + { + public override string? Kind => "resolve"; + public string? Name; + public string? Value; + } +} \ No newline at end of file diff --git a/src/mr/SendTestInstruction.cs b/src/mr/SendTestInstruction.cs index 530fa58b..9cf87bf5 100644 --- a/src/mr/SendTestInstruction.cs +++ b/src/mr/SendTestInstruction.cs @@ -1,8 +1,9 @@ -namespace macaroni; - -class SendTestInstruction : TestInstruction +namespace macaroni { - public override string? Kind => "send"; - public string? Send; - public string? Format; -} + class SendTestInstruction : TestInstruction + { + public override string? Kind => "send"; + public string? Send; + public string? Format; + } +} \ No newline at end of file diff --git a/src/mr/StringHelpers.cs b/src/mr/StringHelpers.cs index 3fa7cdd3..7579dd40 100644 --- a/src/mr/StringHelpers.cs +++ b/src/mr/StringHelpers.cs @@ -1,47 +1,48 @@ using System.Text; -namespace macaroni; - -public static class StringHelpers +namespace macaroni { - public static string[] SplitOptionallyQuotedParameters(string optionallyQuotedArguments) + public static class StringHelpers { - var args = new List(); - var sb = new StringBuilder(); - var inQuotes = false; - - foreach (var ch in optionallyQuotedArguments.Trim()) + public static string[] SplitOptionallyQuotedParameters(string optionallyQuotedArguments) { - if (ch == '"') + var args = new List(); + var sb = new StringBuilder(); + var inQuotes = false; + + foreach (var ch in optionallyQuotedArguments.Trim()) { - if (inQuotes) + if (ch == '"') { - args.Add(sb.ToString()); - sb.Clear(); + if (inQuotes) + { + args.Add(sb.ToString()); + sb.Clear(); + } + inQuotes = !inQuotes; } - inQuotes = !inQuotes; - } - else if (ch == ' ' && !inQuotes) - { - if (sb.Length > 0) + else if (ch == ' ' && !inQuotes) + { + if (sb.Length > 0) + { + args.Add(sb.ToString()); + sb.Clear(); + } + } + else { - args.Add(sb.ToString()); - sb.Clear(); + sb.Append(ch); } } - else + + if (sb.Length > 0) { - sb.Append(ch); + args.Add(sb.ToString()); } - } - if (sb.Length > 0) - { - args.Add(sb.ToString()); + return args.ToArray(); } - return args.ToArray(); - } - + } } \ No newline at end of file diff --git a/src/mr/TemplateTestInstruction.cs b/src/mr/TemplateTestInstruction.cs index eee6dff9..bbf43425 100644 --- a/src/mr/TemplateTestInstruction.cs +++ b/src/mr/TemplateTestInstruction.cs @@ -1,8 +1,9 @@ -namespace macaroni; - -class TemplateTestInstruction : TestInstruction +namespace macaroni { - public override string? Kind => "template"; - public string? Name; - public string? Value; + class TemplateTestInstruction : TestInstruction + { + public override string? Kind => "template"; + public string? Name; + public string? Value; + } } \ No newline at end of file diff --git a/src/mr/TestInstruction.cs b/src/mr/TestInstruction.cs index a94b757c..ed1a5424 100644 --- a/src/mr/TestInstruction.cs +++ b/src/mr/TestInstruction.cs @@ -1,6 +1,7 @@ -namespace macaroni; - -abstract class TestInstruction +namespace macaroni { - abstract public string? Kind { get; } -} + abstract class TestInstruction + { + abstract public string? Kind { get; } + } +} \ No newline at end of file diff --git a/src/mr/TestInstructionCollection.cs b/src/mr/TestInstructionCollection.cs index d6c88bbb..a986678e 100644 --- a/src/mr/TestInstructionCollection.cs +++ b/src/mr/TestInstructionCollection.cs @@ -1,25 +1,26 @@ global using YamlDotNet.RepresentationModel; -namespace macaroni; - -class TestInstructionCollection : List +namespace macaroni { - public TestInstructionCollection(IEnumerable collection) : base(collection) + class TestInstructionCollection : List { - } + public TestInstructionCollection(IEnumerable collection) : base(collection) + { + } - public TestInstructionCollection() : base() - { - } + public TestInstructionCollection() : base() + { + } - public static TestInstructionCollection? FromFile(string path) - { - var instructions = TestInstructionTextFileParser.ParseFile(path); - if (instructions?.Count() > 0) return instructions; + public static TestInstructionCollection? FromFile(string path) + { + var instructions = TestInstructionTextFileParser.ParseFile(path); + if (instructions?.Count() > 0) return instructions; - instructions = TestInstructionYamlFileParser.ParseFile(path); - if (instructions?.Count() > 0) return instructions; + instructions = TestInstructionYamlFileParser.ParseFile(path); + if (instructions?.Count() > 0) return instructions; - return null; + return null; + } } -} +} \ No newline at end of file diff --git a/src/mr/TestInstructionTextFileParser.cs b/src/mr/TestInstructionTextFileParser.cs index d8606d5a..1e389d47 100644 --- a/src/mr/TestInstructionTextFileParser.cs +++ b/src/mr/TestInstructionTextFileParser.cs @@ -1,11 +1,12 @@ -namespace macaroni; - -class TestInstructionTextFileParser +namespace macaroni { - public static TestInstructionCollection? ParseFile(string path) + class TestInstructionTextFileParser { - var lines = File.ReadAllLines(path); - var instructions = lines.Select(TestInstructionTextLineParser.Parse).Where(x => x != null).Select(x => x!).ToList(); - return new TestInstructionCollection(instructions); + public static TestInstructionCollection? ParseFile(string path) + { + var lines = File.ReadAllLines(path); + var instructions = lines.Select(TestInstructionTextLineParser.Parse).Where(x => x != null).Select(x => x!).ToList(); + return new TestInstructionCollection(instructions); + } } -} +} \ No newline at end of file diff --git a/src/mr/TestInstructionTextLineParser.cs b/src/mr/TestInstructionTextLineParser.cs index 78d0fa00..5148d837 100644 --- a/src/mr/TestInstructionTextLineParser.cs +++ b/src/mr/TestInstructionTextLineParser.cs @@ -1,44 +1,45 @@ -namespace macaroni; - -class TestInstructionTextLineParser +namespace macaroni { - public static TestInstruction? Parse(string? line) + class TestInstructionTextLineParser { - if (line == null) return null; - - if (line.StartsWith("expect ")) + public static TestInstruction? Parse(string? line) { - var expect = line.Substring("expect ".Length).Trim(); - return expect.StartsWith("\"") && expect.EndsWith("\"") - ? new ExpectTestInstruction(expect.Trim('"')) - : new ExpectTestInstruction(expect); - } + if (line == null) return null; - if (line.StartsWith("send ")) - { - var send = line.Substring("send ".Length).Trim(); - return send.StartsWith("\"") && send.EndsWith("\"") - ? new SendTestInstruction { Send = send.Trim('"') } - : new SendTestInstruction { Send = send }; - } + if (line.StartsWith("expect ")) + { + var expect = line.Substring("expect ".Length).Trim(); + return expect.StartsWith("\"") && expect.EndsWith("\"") + ? new ExpectTestInstruction(expect.Trim('"')) + : new ExpectTestInstruction(expect); + } - if (line.StartsWith("broadcast ")) - { - var parts = StringHelpers.SplitOptionallyQuotedParameters(line.Substring("broadcast ".Length)); - return new BroadcastTestInstruction { Message = parts[0], Value = parts[1] }; - } + if (line.StartsWith("send ")) + { + var send = line.Substring("send ".Length).Trim(); + return send.StartsWith("\"") && send.EndsWith("\"") + ? new SendTestInstruction { Send = send.Trim('"') } + : new SendTestInstruction { Send = send }; + } - if (line.StartsWith("resolve ")) - { - var parts = StringHelpers.SplitOptionallyQuotedParameters(line.Substring("resolve ".Length)); - return new ResolveTestInstruction { Name = parts[0], Value = parts[1] }; - } + if (line.StartsWith("broadcast ")) + { + var parts = StringHelpers.SplitOptionallyQuotedParameters(line.Substring("broadcast ".Length)); + return new BroadcastTestInstruction { Message = parts[0], Value = parts[1] }; + } - if (line.StartsWith("set timeout ")) - { - return new TimeoutTestInstruction { Timeout = int.Parse(line.Substring("set timeout ".Length)) }; - } + if (line.StartsWith("resolve ")) + { + var parts = StringHelpers.SplitOptionallyQuotedParameters(line.Substring("resolve ".Length)); + return new ResolveTestInstruction { Name = parts[0], Value = parts[1] }; + } + + if (line.StartsWith("set timeout ")) + { + return new TimeoutTestInstruction { Timeout = int.Parse(line.Substring("set timeout ".Length)) }; + } - return null; + return null; + } } -} +} \ No newline at end of file diff --git a/src/mr/TestInstructionYamlFileParser.cs b/src/mr/TestInstructionYamlFileParser.cs index 5fc1e723..51643a38 100644 --- a/src/mr/TestInstructionYamlFileParser.cs +++ b/src/mr/TestInstructionYamlFileParser.cs @@ -1,113 +1,114 @@ -namespace macaroni; - -class TestInstructionYamlFileParser +namespace macaroni { - public static TestInstructionCollection? ParseFile(string path) + class TestInstructionYamlFileParser { - var text = File.ReadAllText(path); - return Parse(text); - } + public static TestInstructionCollection? ParseFile(string path) + { + var text = File.ReadAllText(path); + return Parse(text); + } - private static TestInstructionCollection? Parse(string text) - { - var yaml = new YamlStream(); - yaml.Load(new StringReader(text)); + private static TestInstructionCollection? Parse(string text) + { + var yaml = new YamlStream(); + yaml.Load(new StringReader(text)); - return yaml.Documents[0].RootNode is YamlSequenceNode sequence - ? ParseInstructions(sequence) - : null; - } + return yaml.Documents[0].RootNode is YamlSequenceNode sequence + ? ParseInstructions(sequence) + : null; + } - private static TestInstructionCollection ParseInstructions(YamlSequenceNode sequence) - { - var instructions = new TestInstructionCollection(); - foreach (var node in sequence.Children) + private static TestInstructionCollection ParseInstructions(YamlSequenceNode sequence) { - var instruction = ParseInstruction(node); - if (instruction != null) + var instructions = new TestInstructionCollection(); + foreach (var node in sequence.Children) { - instructions.Add(instruction); + var instruction = ParseInstruction(node); + if (instruction != null) + { + instructions.Add(instruction); + } } + return instructions; } - return instructions; - } - private static TestInstruction? ParseInstruction(YamlNode node) - { - if (node is YamlMappingNode mapping) + private static TestInstruction? ParseInstruction(YamlNode node) { - if (mapping.Children.ContainsKey("expect")) return ParseExpectInstruction(mapping); - if (mapping.Children.ContainsKey("send")) return ParseSendInstruction(mapping); - if (mapping.Children.ContainsKey("broadcast")) return ParseBroadcastInstruction(mapping); - if (mapping.Children.ContainsKey("resolve")) return ParseResolveInstruction(mapping); - if (mapping.Children.ContainsKey("timeout")) return ParseTimeoutInstruction(mapping); - if (mapping.Children.ContainsKey("template")) return ParseTemplateInstruction(mapping); + if (node is YamlMappingNode mapping) + { + if (mapping.Children.ContainsKey("expect")) return ParseExpectInstruction(mapping); + if (mapping.Children.ContainsKey("send")) return ParseSendInstruction(mapping); + if (mapping.Children.ContainsKey("broadcast")) return ParseBroadcastInstruction(mapping); + if (mapping.Children.ContainsKey("resolve")) return ParseResolveInstruction(mapping); + if (mapping.Children.ContainsKey("timeout")) return ParseTimeoutInstruction(mapping); + if (mapping.Children.ContainsKey("template")) return ParseTemplateInstruction(mapping); + } + return null; } - return null; - } - - private static ExpectTestInstruction ParseExpectInstruction(YamlMappingNode mapping) - { - var expect = mapping.Children[new YamlScalarNode("expect")]; - var debugBreak = mapping.Children.ContainsKey("debugBreak") - ? mapping.Children[new YamlScalarNode("debugBreak")] - : "false"; - var isDebugBreak = debugBreak.ToString() == "true"; - if (expect is YamlSequenceNode sequence) + private static ExpectTestInstruction ParseExpectInstruction(YamlMappingNode mapping) { - var expected = sequence.Children.Select(x => x.ToString()); - return new ExpectTestInstruction(expected) { DebugBreak = isDebugBreak }; - } + var expect = mapping.Children[new YamlScalarNode("expect")]; + var debugBreak = mapping.Children.ContainsKey("debugBreak") + ? mapping.Children[new YamlScalarNode("debugBreak")] + : "false"; + var isDebugBreak = debugBreak.ToString() == "true"; - return new ExpectTestInstruction(expect.ToString()) { DebugBreak = isDebugBreak }; - } + if (expect is YamlSequenceNode sequence) + { + var expected = sequence.Children.Select(x => x.ToString()); + return new ExpectTestInstruction(expected) { DebugBreak = isDebugBreak }; + } - private static SendTestInstruction ParseSendInstruction(YamlMappingNode mapping) - { - var send = mapping.Children[new YamlScalarNode("send")]; - var format = mapping.Children.ContainsKey("format") - ? mapping.Children[new YamlScalarNode("format")] - : "emulate"; - return new SendTestInstruction { Send = send.ToString(), Format = format.ToString() }; - } + return new ExpectTestInstruction(expect.ToString()) { DebugBreak = isDebugBreak }; + } - private static BroadcastTestInstruction ParseBroadcastInstruction(YamlMappingNode mapping) - { - var message = mapping.Children[new YamlScalarNode("broadcast")]; - var value = mapping.Children.ContainsKey(new YamlScalarNode("value")) - ? GetRequiredMappingNode(mapping, "value") - : ""; - return new BroadcastTestInstruction { Message = message.ToString(), Value = value.ToString() }; - } + private static SendTestInstruction ParseSendInstruction(YamlMappingNode mapping) + { + var send = mapping.Children[new YamlScalarNode("send")]; + var format = mapping.Children.ContainsKey("format") + ? mapping.Children[new YamlScalarNode("format")] + : "emulate"; + return new SendTestInstruction { Send = send.ToString(), Format = format.ToString() }; + } - private static ResolveTestInstruction ParseResolveInstruction(YamlMappingNode mapping) - { - var name = mapping.Children[new YamlScalarNode("resolve")]; - var value = GetRequiredMappingNode(mapping, "value"); - return new ResolveTestInstruction { Name = name.ToString(), Value = value.ToString() }; - } + private static BroadcastTestInstruction ParseBroadcastInstruction(YamlMappingNode mapping) + { + var message = mapping.Children[new YamlScalarNode("broadcast")]; + var value = mapping.Children.ContainsKey(new YamlScalarNode("value")) + ? GetRequiredMappingNode(mapping, "value") + : ""; + return new BroadcastTestInstruction { Message = message.ToString(), Value = value.ToString() }; + } - private static TimeoutTestInstruction ParseTimeoutInstruction(YamlMappingNode mapping) - { - var timeout = mapping.Children[new YamlScalarNode("timeout")]; - return new TimeoutTestInstruction { Timeout = int.Parse(timeout.ToString()) }; - } + private static ResolveTestInstruction ParseResolveInstruction(YamlMappingNode mapping) + { + var name = mapping.Children[new YamlScalarNode("resolve")]; + var value = GetRequiredMappingNode(mapping, "value"); + return new ResolveTestInstruction { Name = name.ToString(), Value = value.ToString() }; + } - private static TemplateTestInstruction ParseTemplateInstruction(YamlMappingNode mapping) - { - var template = mapping.Children[new YamlScalarNode("template")]; - var value = GetRequiredMappingNode(mapping, "value"); - return new TemplateTestInstruction { Name = template.ToString(), Value = value.ToString() }; - } + private static TimeoutTestInstruction ParseTimeoutInstruction(YamlMappingNode mapping) + { + var timeout = mapping.Children[new YamlScalarNode("timeout")]; + return new TimeoutTestInstruction { Timeout = int.Parse(timeout.ToString()) }; + } - private static YamlNode GetRequiredMappingNode(YamlMappingNode mapping, string child) - { - if (!mapping.Children.ContainsKey(new YamlScalarNode(child))) + private static TemplateTestInstruction ParseTemplateInstruction(YamlMappingNode mapping) { - throw new FormatException($"Missing `{child}`; line={mapping.Start.Line}, column={mapping.Start.Column}"); + var template = mapping.Children[new YamlScalarNode("template")]; + var value = GetRequiredMappingNode(mapping, "value"); + return new TemplateTestInstruction { Name = template.ToString(), Value = value.ToString() }; } - return mapping.Children[new YamlScalarNode(child)]; + private static YamlNode GetRequiredMappingNode(YamlMappingNode mapping, string child) + { + if (!mapping.Children.ContainsKey(new YamlScalarNode(child))) + { + throw new FormatException($"Missing `{child}`; line={mapping.Start.Line}, column={mapping.Start.Column}"); + } + + return mapping.Children[new YamlScalarNode(child)]; + } } -} +} \ No newline at end of file diff --git a/src/mr/TimeoutTestInstruction.cs b/src/mr/TimeoutTestInstruction.cs index 83f2978e..dd6a1524 100644 --- a/src/mr/TimeoutTestInstruction.cs +++ b/src/mr/TimeoutTestInstruction.cs @@ -1,7 +1,8 @@ -namespace macaroni; - -class TimeoutTestInstruction : TestInstruction +namespace macaroni { - public override string? Kind => "timeout"; - public int Timeout; -} + class TimeoutTestInstruction : TestInstruction + { + public override string? Kind => "timeout"; + public int Timeout; + } +} \ No newline at end of file diff --git a/src/win32_ui/CommandSystemBuilderPlatformExtension.cs b/src/win32_ui/CommandSystemBuilderPlatformExtension.cs index f785177d..3d382cc0 100644 --- a/src/win32_ui/CommandSystemBuilderPlatformExtension.cs +++ b/src/win32_ui/CommandSystemBuilderPlatformExtension.cs @@ -1,34 +1,34 @@ -using Microsoft.Extensions.Hosting; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; -namespace macaroni; - -public static class CommandSystemBuilderPlatformExtension +namespace macaroni { - public static ICommandSystemBuilder UseWindowsExtensions(this ICommandSystemBuilder builder, bool useWindowsExtensions = true) + public static class CommandSystemBuilderPlatformExtension { - builder.ConfigureServices((context, services) => + public static ICommandSystemBuilder UseWindowsExtensions(this ICommandSystemBuilder builder, bool useWindowsExtensions = true) { - if (useWindowsExtensions) + builder.ConfigureServices((context, services) => { - services.AddHostedService(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddTransient(); - services.AddSingleton(); - } - }); - return builder; + if (useWindowsExtensions) + { + services.AddHostedService(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddTransient(); + services.AddSingleton(); + } + }); + return builder; + } } -} - +} \ No newline at end of file diff --git a/src/win32_ui/PlatformServices/SmartKey.cs b/src/win32_ui/PlatformServices/SmartKey.cs index e79fc961..71539cda 100644 --- a/src/win32_ui/PlatformServices/SmartKey.cs +++ b/src/win32_ui/PlatformServices/SmartKey.cs @@ -1,176 +1,177 @@ -using System.Runtime.InteropServices; using System.ComponentModel; -using WORD = System.UInt16; +using System.Runtime.InteropServices; using DWORD = System.UInt32; +using WORD = System.UInt16; -namespace macaroni; - -// Class CSmartKey -// Base class for all smart key classes -// dwFlags is used to set the KEYBDINPUT.dwFlags parameter -// Press() and Release() should modify those flags appropriately. -// The default implementation of Send() is simply to call Press(); and Release(); -internal partial class SmartKey +namespace macaroni { - public SmartKey(WORD wScanCode, DWORD dwFlags, DWORD repeatCount = 1) + // Class CSmartKey + // Base class for all smart key classes + // dwFlags is used to set the KEYBDINPUT.dwFlags parameter + // Press() and Release() should modify those flags appropriately. + // The default implementation of Send() is simply to call Press(); and Release(); + internal partial class SmartKey { - m_Input = new input_interop.INPUT(); + public SmartKey(WORD wScanCode, DWORD dwFlags, DWORD repeatCount = 1) + { + m_Input = new input_interop.INPUT(); - m_Input.type = input_interop.InputType.INPUT_KEYBOARD; - m_Input.U.ki.dwFlags = dwFlags; + m_Input.type = input_interop.InputType.INPUT_KEYBOARD; + m_Input.U.ki.dwFlags = dwFlags; - m_repeatCount = repeatCount; + m_repeatCount = repeatCount; - // Set the right field depending on the flags passed in - if ((dwFlags & (input_interop.KEYEVENTF_UNICODE | input_interop.KEYEVENTF_SCANCODE)) == 0) - { - m_Input.U.ki.wVk = wScanCode; - } - else - { - m_Input.U.ki.wScan = wScanCode; + // Set the right field depending on the flags passed in + if ((dwFlags & (input_interop.KEYEVENTF_UNICODE | input_interop.KEYEVENTF_SCANCODE)) == 0) + { + m_Input.U.ki.wVk = wScanCode; + } + else + { + m_Input.U.ki.wScan = wScanCode; + } } - } - public SmartKey(char ch, DWORD repeatCount = 1) - { - m_Input = new input_interop.INPUT(); + public SmartKey(char ch, DWORD repeatCount = 1) + { + m_Input = new input_interop.INPUT(); - m_Input.type = input_interop.InputType.INPUT_KEYBOARD; - m_Input.U.ki.wScan = ch; - m_Input.U.ki.dwFlags = input_interop.KEYEVENTF_UNICODE; + m_Input.type = input_interop.InputType.INPUT_KEYBOARD; + m_Input.U.ki.wScan = ch; + m_Input.U.ki.dwFlags = input_interop.KEYEVENTF_UNICODE; - m_repeatCount = repeatCount; - } - - protected SmartKey(input_interop.INPUT input, uint repeatCount) - { - } + m_repeatCount = repeatCount; + } - public virtual void Send() - { - for (var i = 0; i < m_repeatCount; i++) + protected SmartKey(input_interop.INPUT input, uint repeatCount) { - Press(); - Thread.Sleep(0); - Release(); - Thread.Sleep(0); } - } - - public virtual void Press() - { - // Make sure the KEYEVENTF_KEYUP bit is not set - m_Input.U.ki.dwFlags &= ~input_interop.KEYEVENTF_KEYUP; - // Check to see if we have the extended key byte - if ((m_Input.U.ki.wScan & 0xE000) == 0xE000) + public virtual void Send() { - m_Input.U.ki.dwFlags |= input_interop.KEYEVENTF_EXTENDEDKEY; + for (var i = 0; i < m_repeatCount; i++) + { + Press(); + Thread.Sleep(0); + Release(); + Thread.Sleep(0); + } } - var inputs = new[] { m_Input }; - if (input_interop.SendInput(1, inputs, Marshal.SizeOf(m_Input)) == 0) + public virtual void Press() { - throw new Win32Exception(); - } - } + // Make sure the KEYEVENTF_KEYUP bit is not set + m_Input.U.ki.dwFlags &= ~input_interop.KEYEVENTF_KEYUP; - public virtual void Release() - { - // Make sure the KEYEVENTF_KEYUP bit is set - m_Input.U.ki.dwFlags |= input_interop.KEYEVENTF_KEYUP; + // Check to see if we have the extended key byte + if ((m_Input.U.ki.wScan & 0xE000) == 0xE000) + { + m_Input.U.ki.dwFlags |= input_interop.KEYEVENTF_EXTENDEDKEY; + } - // Check to see if we have the extended key byte - if ((m_Input.U.ki.wScan & 0xE000) == 0xE000) - { - m_Input.U.ki.dwFlags |= input_interop.KEYEVENTF_EXTENDEDKEY; + var inputs = new[] { m_Input }; + if (input_interop.SendInput(1, inputs, Marshal.SizeOf(m_Input)) == 0) + { + throw new Win32Exception(); + } } - var inputs = new[] { m_Input }; - if (input_interop.SendInput(1, inputs, Marshal.SizeOf(m_Input)) == 0) + public virtual void Release() { - throw new Win32Exception(); - } - } + // Make sure the KEYEVENTF_KEYUP bit is set + m_Input.U.ki.dwFlags |= input_interop.KEYEVENTF_KEYUP; - public virtual void SetRepeatCount(DWORD repeatCount) - { - m_repeatCount = repeatCount; - } - - public virtual Modifier AsModifier() - { - return new Modifier(m_Input, m_repeatCount); - } + // Check to see if we have the extended key byte + if ((m_Input.U.ki.wScan & 0xE000) == 0xE000) + { + m_Input.U.ki.dwFlags |= input_interop.KEYEVENTF_EXTENDEDKEY; + } - public virtual DWORD AsVks(out IEnumerable modifiers) - { - modifiers = Enumerable.Empty(); + var inputs = new[] { m_Input }; + if (input_interop.SendInput(1, inputs, Marshal.SizeOf(m_Input)) == 0) + { + throw new Win32Exception(); + } + } - if ((m_Input.U.ki.dwFlags & (input_interop.KEYEVENTF_UNICODE | input_interop.KEYEVENTF_SCANCODE)) == 0) + public virtual void SetRepeatCount(DWORD repeatCount) { - return m_Input.U.ki.wVk; + m_repeatCount = repeatCount; } - if ((m_Input.U.ki.dwFlags & input_interop.KEYEVENTF_SCANCODE) == input_interop.KEYEVENTF_SCANCODE) + public virtual Modifier AsModifier() { - return input_interop.MapVirtualKey(m_Input.U.ki.wScan, input_interop.MapVirtualKeyType.MAPVK_VSC_TO_VK_EX); + return new Modifier(m_Input, m_repeatCount); } - return 0; - } + public virtual DWORD AsVks(out IEnumerable modifiers) + { + modifiers = Enumerable.Empty(); - public virtual DWORD AsVk(out DWORD mods, out bool extended) - { - var vk = AsVks(out var modifiers); - extended = false; - mods = 0; + if ((m_Input.U.ki.dwFlags & (input_interop.KEYEVENTF_UNICODE | input_interop.KEYEVENTF_SCANCODE)) == 0) + { + return m_Input.U.ki.wVk; + } + + if ((m_Input.U.ki.dwFlags & input_interop.KEYEVENTF_SCANCODE) == input_interop.KEYEVENTF_SCANCODE) + { + return input_interop.MapVirtualKey(m_Input.U.ki.wScan, input_interop.MapVirtualKeyType.MAPVK_VSC_TO_VK_EX); + } + + return 0; + } - var nShift = modifiers.Count(x => x == input_interop.VK_LSHIFT || x == input_interop.VK_RSHIFT || x == input_interop.VK_SHIFT); - var nCtrl = modifiers.Count(x => x == input_interop.VK_LCONTROL || x == input_interop.VK_RCONTROL || x == input_interop.VK_CONTROL); - var nAlt = modifiers.Count(x => x == input_interop.VK_LMENU || x == input_interop.VK_RMENU || x == input_interop.VK_MENU); - var nWin = modifiers.Count(x => x == input_interop.VK_LWIN || x == input_interop.VK_RWIN); + public virtual DWORD AsVk(out DWORD mods, out bool extended) + { + var vk = AsVks(out var modifiers); + extended = false; + mods = 0; - if (nShift != 0 && nShift != 1) return 0; - if (nCtrl != 0 && nCtrl != 1) return 0; - if (nAlt != 0 && nAlt != 1) return 0; - if (nWin != 0 && nWin != 1) return 0; + var nShift = modifiers.Count(x => x == input_interop.VK_LSHIFT || x == input_interop.VK_RSHIFT || x == input_interop.VK_SHIFT); + var nCtrl = modifiers.Count(x => x == input_interop.VK_LCONTROL || x == input_interop.VK_RCONTROL || x == input_interop.VK_CONTROL); + var nAlt = modifiers.Count(x => x == input_interop.VK_LMENU || x == input_interop.VK_RMENU || x == input_interop.VK_MENU); + var nWin = modifiers.Count(x => x == input_interop.VK_LWIN || x == input_interop.VK_RWIN); - var shift = modifiers.Any(x => x == input_interop.VK_LSHIFT || x == input_interop.VK_RSHIFT || x == input_interop.VK_SHIFT) ? input_interop.MOD_SHIFT : 0; - var ctrl = modifiers.Any(x => x == input_interop.VK_LCONTROL || x == input_interop.VK_RCONTROL || x == input_interop.VK_CONTROL) ? input_interop.MOD_CONTROL : 0; - var alt = modifiers.Any(x => x == input_interop.VK_LMENU || x == input_interop.VK_RMENU || x == input_interop.VK_MENU) ? input_interop.MOD_ALT: 0; - var win = modifiers.Any(x => x == input_interop.VK_LWIN || x == input_interop.VK_RWIN) ? input_interop.MOD_WIN : 0; + if (nShift != 0 && nShift != 1) return 0; + if (nCtrl != 0 && nCtrl != 1) return 0; + if (nAlt != 0 && nAlt != 1) return 0; + if (nWin != 0 && nWin != 1) return 0; - if (nShift == 1) mods += input_interop.MOD_SHIFT; - if (nCtrl == 1) mods += input_interop.MOD_CONTROL; - if (nAlt == 1) mods += input_interop.MOD_ALT; - if (nWin == 1) mods += input_interop.MOD_WIN; + var shift = modifiers.Any(x => x == input_interop.VK_LSHIFT || x == input_interop.VK_RSHIFT || x == input_interop.VK_SHIFT) ? input_interop.MOD_SHIFT : 0; + var ctrl = modifiers.Any(x => x == input_interop.VK_LCONTROL || x == input_interop.VK_RCONTROL || x == input_interop.VK_CONTROL) ? input_interop.MOD_CONTROL : 0; + var alt = modifiers.Any(x => x == input_interop.VK_LMENU || x == input_interop.VK_RMENU || x == input_interop.VK_MENU) ? input_interop.MOD_ALT : 0; + var win = modifiers.Any(x => x == input_interop.VK_LWIN || x == input_interop.VK_RWIN) ? input_interop.MOD_WIN : 0; - extended = (m_Input.U.ki.dwFlags & input_interop.KEYEVENTF_EXTENDEDKEY) != 0; + if (nShift == 1) mods += input_interop.MOD_SHIFT; + if (nCtrl == 1) mods += input_interop.MOD_CONTROL; + if (nAlt == 1) mods += input_interop.MOD_ALT; + if (nWin == 1) mods += input_interop.MOD_WIN; - return vk; - } + extended = (m_Input.U.ki.dwFlags & input_interop.KEYEVENTF_EXTENDEDKEY) != 0; - public static bool AsVk(string keys, out DWORD vk, out DWORD mods, out bool extended) - { - var list = SmartKey.List.FromKeys(keys); - if (list.Keys.Count() == 1) + return vk; + } + + public static bool AsVk(string keys, out DWORD vk, out DWORD mods, out bool extended) { - var key = list.Keys.First(); - if (key != null) + var list = SmartKey.List.FromKeys(keys); + if (list.Keys.Count() == 1) { - vk = key.AsVk(out mods, out extended); - return true; + var key = list.Keys.First(); + if (key != null) + { + vk = key.AsVk(out mods, out extended); + return true; + } } + + vk = 0; + mods = 0; + extended = false; + return false; } - vk = 0; - mods = 0; - extended = false; - return false; + protected input_interop.INPUT m_Input; + protected DWORD m_repeatCount; } - - protected input_interop.INPUT m_Input; - protected DWORD m_repeatCount; -} +} \ No newline at end of file diff --git a/src/win32_ui/PlatformServices/SmartKey_Delay.cs b/src/win32_ui/PlatformServices/SmartKey_Delay.cs index a1bf3eaa..78ac7b79 100644 --- a/src/win32_ui/PlatformServices/SmartKey_Delay.cs +++ b/src/win32_ui/PlatformServices/SmartKey_Delay.cs @@ -1,24 +1,25 @@ using DWORD = System.UInt32; -namespace macaroni; - -internal partial class SmartKey +namespace macaroni { - // Class CDelayKey - // This "key" will sleep for wDelay ms when Send() is called - public class Delay : SmartKey + internal partial class SmartKey { - public Delay(DWORD dwDelay) : base(0, 0, 1) + // Class CDelayKey + // This "key" will sleep for wDelay ms when Send() is called + public class Delay : SmartKey { - // Just use the time member of our structure to store the delay - // since we won't be needing it for anything else. - m_Input.U.ki.time = (int)dwDelay; - } + public Delay(DWORD dwDelay) : base(0, 0, 1) + { + // Just use the time member of our structure to store the delay + // since we won't be needing it for anything else. + m_Input.U.ki.time = (int)dwDelay; + } - public override void Send() - { - Thread.Sleep((int)m_Input.U.ki.time); + public override void Send() + { + Thread.Sleep((int)m_Input.U.ki.time); + } } - } + } } \ No newline at end of file diff --git a/src/win32_ui/PlatformServices/SmartKey_Group.cs b/src/win32_ui/PlatformServices/SmartKey_Group.cs index 81294f4e..6638ddc2 100644 --- a/src/win32_ui/PlatformServices/SmartKey_Group.cs +++ b/src/win32_ui/PlatformServices/SmartKey_Group.cs @@ -1,23 +1,24 @@ -namespace macaroni; - -internal partial class SmartKey +namespace macaroni { - // Class CKeyGroup - // This class is used to hold a group of keys. - public class CKeyGroup : SmartKey + internal partial class SmartKey { - public CKeyGroup() : base(0, 0, 1) + // Class CKeyGroup + // This class is used to hold a group of keys. + public class CKeyGroup : SmartKey { - } + public CKeyGroup() : base(0, 0, 1) + { + } - public override void Send() - { - for (var i = 0; i < m_repeatCount; i++) + public override void Send() { - Keys?.SendKeys(); + for (var i = 0; i < m_repeatCount; i++) + { + Keys?.SendKeys(); + } } - } - public List Keys = new(); + public List Keys = new(); + } } } \ No newline at end of file diff --git a/src/win32_ui/PlatformServices/SmartKey_List.cs b/src/win32_ui/PlatformServices/SmartKey_List.cs index 312f0e49..1ba1c8d7 100644 --- a/src/win32_ui/PlatformServices/SmartKey_List.cs +++ b/src/win32_ui/PlatformServices/SmartKey_List.cs @@ -1,469 +1,470 @@ using System.Globalization; -using WORD = System.UInt16; -using DWORD = System.UInt32; using System.Text; +using DWORD = System.UInt32; +using WORD = System.UInt16; -namespace macaroni; - -internal partial class SmartKey +namespace macaroni { - // Class CKeyList - // This class handles managing a collection of CSmartKey objects. - // To init, call ParseKeyString() or add keys individually with Add() - // in the order you would like them to be executed. - // Then call SendKeys(). This will send all of the keys in the order they were added - // or parsed. - public class List + internal partial class SmartKey { - public List() + // Class CKeyList + // This class handles managing a collection of CSmartKey objects. + // To init, call ParseKeyString() or add keys individually with Add() + // in the order you would like them to be executed. + // Then call SendKeys(). This will send all of the keys in the order they were added + // or parsed. + public class List { - } - - public static SmartKey.List FromKeys(string keys) - { - var list = new SmartKey.List(); + public List() + { + } - int index = 0; - while (index < keys.Length) + public static SmartKey.List FromKeys(string keys) { - var key = list.GetNextKey(keys, ref index); - if (key == null) + var list = new SmartKey.List(); + + int index = 0; + while (index < keys.Length) { - throw new ApplicationException($"ERROR: Parsing key string ('{keys}') at {index}"); + var key = list.GetNextKey(keys, ref index); + if (key == null) + { + throw new ApplicationException($"ERROR: Parsing key string ('{keys}') at {index}"); + } + + list.Add(key); } - list.Add(key); + return list; } - return list; - } - - public static SmartKey.List FromText(string text) - { - return FromKeys(EscapeSendKeySpecialChars(text)); - } - - public IEnumerable Keys { get { return m_KeyList; } } + public static SmartKey.List FromText(string text) + { + return FromKeys(EscapeSendKeySpecialChars(text)); + } - public virtual void Add(SmartKey pKey) - { - m_KeyList.Add(pKey); - } + public IEnumerable Keys { get { return m_KeyList; } } - public virtual void SendKeys() - { - m_KeyList.ForEach(x => x.Send()); - } + public virtual void Add(SmartKey pKey) + { + m_KeyList.Add(pKey); + } - public virtual void RemoveAll() - { - m_KeyList.Clear(); - } + public virtual void SendKeys() + { + m_KeyList.ForEach(x => x.Send()); + } - protected SmartKey? GetNextKey(string keyString, ref int index) - { - if (index > keyString.Length) return null; + public virtual void RemoveAll() + { + m_KeyList.Clear(); + } - return keyString[index] switch + protected SmartKey? GetNextKey(string keyString, ref int index) { - '{' => EvalBrace(keyString, ref index), - '(' => EvalParen(keyString, ref index), - '%' or '^' or '+' => EvalModifier(keyString, ref index), - '~' or '\n' => EvalEnter(keyString, ref index), - _ => EvalCharKey(keyString, ref index) - }; - } + if (index > keyString.Length) return null; - protected SmartKey EvalCharKey(string keyString, ref int index) - { - var key = CreateScanCodeKeyFromChar(keyString[index]); - index += 1; - return key; - } + return keyString[index] switch + { + '{' => EvalBrace(keyString, ref index), + '(' => EvalParen(keyString, ref index), + '%' or '^' or '+' => EvalModifier(keyString, ref index), + '~' or '\n' => EvalEnter(keyString, ref index), + _ => EvalCharKey(keyString, ref index) + }; + } - protected SmartKey? EvalEnter(string keyString, ref int index) - { - index += 1; - return new SmartKey(0x1c, input_interop.KEYEVENTF_SCANCODE, 1); - } + protected SmartKey EvalCharKey(string keyString, ref int index) + { + var key = CreateScanCodeKeyFromChar(keyString[index]); + index += 1; + return key; + } - protected SmartKey? EvalBrace(string keyString, ref int index) - { - if (keyString[index + 0] != '{') throw new ApplicationException("EvalBrace() called with a string not starting with an open brace!"); - if (index + 2 >= keyString.Length) throw new ApplicationException("EvalBrace() called with string ending with '{' (needs at least 2 more characters)"); + protected SmartKey? EvalEnter(string keyString, ref int index) + { + index += 1; + return new SmartKey(0x1c, input_interop.KEYEVENTF_SCANCODE, 1); + } - var key = CheckBraceEscapedRequiredKeys(keyString, ref index); // e.g. {%} or {{} or {}} - if (key != null) return key; + protected SmartKey? EvalBrace(string keyString, ref int index) + { + if (keyString[index + 0] != '{') throw new ApplicationException("EvalBrace() called with a string not starting with an open brace!"); + if (index + 2 >= keyString.Length) throw new ApplicationException("EvalBrace() called with string ending with '{' (needs at least 2 more characters)"); - key = CheckScanCodeKeys(keyString, ref index); // e.g. {ESC}, {PGDN}, {ctrl-c} - if (key != null) return key; + var key = CheckBraceEscapedRequiredKeys(keyString, ref index); // e.g. {%} or {{} or {}} + if (key != null) return key; - key = CheckEscapedUnicodeKeys(keyString, ref index); // e.g. {U+25CE} - if (key != null) return key; + key = CheckScanCodeKeys(keyString, ref index); // e.g. {ESC}, {PGDN}, {ctrl-c} + if (key != null) return key; - key = CheckWaitOrRepeatKeys(keyString, ref index); // e.g. {10 !} or {500 WAIT} - if (key != null) return key; + key = CheckEscapedUnicodeKeys(keyString, ref index); // e.g. {U+25CE} + if (key != null) return key; - key = CheckVirtualKeys(keyString, ref index); // e.g. {VK 1} - if (key != null) return key; + key = CheckWaitOrRepeatKeys(keyString, ref index); // e.g. {10 !} or {500 WAIT} + if (key != null) return key; - key = CheckModifierKeys(keyString, ref index); // e.g. {{WIN}}D - if (key != null) return key; + key = CheckVirtualKeys(keyString, ref index); // e.g. {VK 1} + if (key != null) return key; - return null; - } + key = CheckModifierKeys(keyString, ref index); // e.g. {{WIN}}D + if (key != null) return key; - private SmartKey? CheckModifierKeys(string keyString, ref int index) - { - index += 1; // skipping over '{' + return null; + } - // A non-modifier key to be used as a modifier, e.g. {d} or {{ESC}} - var key = GetNextKey(keyString, ref index); - if (key != null) + private SmartKey? CheckModifierKeys(string keyString, ref int index) { - if (keyString.Length < index || keyString[index] != '}') + index += 1; // skipping over '{' + + // A non-modifier key to be used as a modifier, e.g. {d} or {{ESC}} + var key = GetNextKey(keyString, ref index); + if (key != null) { - throw new ApplicationException($"EvalBrace() called with modifier wo/ closing '}}' at {index}"); - } + if (keyString.Length < index || keyString[index] != '}') + { + throw new ApplicationException($"EvalBrace() called with modifier wo/ closing '}}' at {index}"); + } - // Create a modifier key - var modifierKey = key.AsModifier(); - index += 1; // skipping over '}' + // Create a modifier key + var modifierKey = key.AsModifier(); + index += 1; // skipping over '}' - // Get whatever this modifier is modifying - key = GetNextKey(keyString, ref index); - if (key == null) - { - throw new ApplicationException($"EvalBrace() called with modifier wo/ key to be modified at {index}"); - } + // Get whatever this modifier is modifying + key = GetNextKey(keyString, ref index); + if (key == null) + { + throw new ApplicationException($"EvalBrace() called with modifier wo/ key to be modified at {index}"); + } - modifierKey.SetModifiedKey(key); - return modifierKey; + modifierKey.SetModifiedKey(key); + return modifierKey; + } + return null; } - return null; - } - private SmartKey? CheckVirtualKeys(string keyString, ref int index) - { - // Checking for '{VK ####}' ... - - var spaceAt = keyString.IndexOf(' ', index + 1); - var isVKSpace = spaceAt == 3 && string.Compare("VK", 0, keyString, index + 1, 2, StringComparison.OrdinalIgnoreCase) == 0; - if (isVKSpace) + private SmartKey? CheckVirtualKeys(string keyString, ref int index) { - var closeBraceAt = keyString.IndexOf('}', spaceAt); - var cchBetweenSpaceAndCloseBrace = closeBraceAt - spaceAt - 1; + // Checking for '{VK ####}' ... - if (cchBetweenSpaceAndCloseBrace > 0) + var spaceAt = keyString.IndexOf(' ', index + 1); + var isVKSpace = spaceAt == 3 && string.Compare("VK", 0, keyString, index + 1, 2, StringComparison.OrdinalIgnoreCase) == 0; + if (isVKSpace) { - if (keyString.Skip(index + 4).Take(cchBetweenSpaceAndCloseBrace).All(x => char.IsDigit(x))) + var closeBraceAt = keyString.IndexOf('}', spaceAt); + var cchBetweenSpaceAndCloseBrace = closeBraceAt - spaceAt - 1; + + if (cchBetweenSpaceAndCloseBrace > 0) { - if (WORD.TryParse(keyString.Substring(index + 4, cchBetweenSpaceAndCloseBrace), out var virtualKeyCode)) + if (keyString.Skip(index + 4).Take(cchBetweenSpaceAndCloseBrace).All(x => char.IsDigit(x))) { - index += 5 + cchBetweenSpaceAndCloseBrace; // skipping '{VK ###'}' - return new SmartKey(virtualKeyCode, input_interop.VIRTUAL_KEY, 1); + if (WORD.TryParse(keyString.Substring(index + 4, cchBetweenSpaceAndCloseBrace), out var virtualKeyCode)) + { + index += 5 + cchBetweenSpaceAndCloseBrace; // skipping '{VK ###'}' + return new SmartKey(virtualKeyCode, input_interop.VIRTUAL_KEY, 1); + } } } } + return null; } - return null; - } - - private SmartKey? CheckWaitOrRepeatKeys(string keyString, ref int index) - { - // - An integer followed by a space followed by a non-modifier key (multiple press) {10 !} - // - OR a WAIT command - var spaceAt = keyString.IndexOf(' ', index + 1); - var cchBetweenBraceAndSpace = spaceAt - index - 1; - var allDigits = spaceAt > 0 && keyString.Skip(index + 1).Take(cchBetweenBraceAndSpace).All(x => char.IsDigit(x)); - if (allDigits) + private SmartKey? CheckWaitOrRepeatKeys(string keyString, ref int index) { - var repeatOrWait = DWORD.Parse(keyString.Substring(index + 1, spaceAt - index - 1)); - - index += cchBetweenBraceAndSpace + 2; // skipping '{### ' + // - An integer followed by a space followed by a non-modifier key (multiple press) {10 !} + // - OR a WAIT command - var isWait = string.Compare("WAIT", 0, keyString, spaceAt + 1, 4, StringComparison.OrdinalIgnoreCase) == 0; - if (isWait) + var spaceAt = keyString.IndexOf(' ', index + 1); + var cchBetweenBraceAndSpace = spaceAt - index - 1; + var allDigits = spaceAt > 0 && keyString.Skip(index + 1).Take(cchBetweenBraceAndSpace).All(x => char.IsDigit(x)); + if (allDigits) { - index += 5; // skipping 'WAIT}' - return new SmartKey.Delay(repeatOrWait); - } + var repeatOrWait = DWORD.Parse(keyString.Substring(index + 1, spaceAt - index - 1)); - var repeatedKey = GetNextKey(keyString, ref index); - if (repeatedKey == null || index > keyString.Length || keyString[index] != '}') - { - throw new ApplicationException($"EvalBrace() called with invalid key at pos {spaceAt - cchBetweenBraceAndSpace}"); - } + index += cchBetweenBraceAndSpace + 2; // skipping '{### ' + + var isWait = string.Compare("WAIT", 0, keyString, spaceAt + 1, 4, StringComparison.OrdinalIgnoreCase) == 0; + if (isWait) + { + index += 5; // skipping 'WAIT}' + return new SmartKey.Delay(repeatOrWait); + } - index += 1; // skipping the close '}' + var repeatedKey = GetNextKey(keyString, ref index); + if (repeatedKey == null || index > keyString.Length || keyString[index] != '}') + { + throw new ApplicationException($"EvalBrace() called with invalid key at pos {spaceAt - cchBetweenBraceAndSpace}"); + } - repeatedKey.SetRepeatCount(repeatOrWait); - return repeatedKey; + index += 1; // skipping the close '}' + + repeatedKey.SetRepeatCount(repeatOrWait); + return repeatedKey; + } + return null; } - return null; - } - private static SmartKey? CheckEscapedUnicodeKeys(string keyString, ref int index) - { - if ((keyString[index + 1] == 'U' || keyString[index + 1] == 'u') && keyString[index + 2] == '+') + private static SmartKey? CheckEscapedUnicodeKeys(string keyString, ref int index) { - // So far, so good. Let's grab the hex characters (and the closing brace) - var hexDigitsAndClosingBrace = keyString.Substring(index + 3); // skipping '{U+' - - // Make sure that closing brace is there - if (hexDigitsAndClosingBrace[4] != '}') + if ((keyString[index + 1] == 'U' || keyString[index + 1] == 'u') && keyString[index + 2] == '+') { - // There's nothing here that could possibly be valid. - throw new ApplicationException($"EvalBrace() called with invalid Unicode character at pos {index + 1}"); - } + // So far, so good. Let's grab the hex characters (and the closing brace) + var hexDigitsAndClosingBrace = keyString.Substring(index + 3); // skipping '{U+' - // OK. Get rid of our copy of that brace (we know it's there) and everything that follows - var hexDigitsOnly = hexDigitsAndClosingBrace.Substring(0, 4); + // Make sure that closing brace is there + if (hexDigitsAndClosingBrace[4] != '}') + { + // There's nothing here that could possibly be valid. + throw new ApplicationException($"EvalBrace() called with invalid Unicode character at pos {index + 1}"); + } - // Get the actual value by converting from HEX - WORD code = WORD.Parse(hexDigitsOnly, NumberStyles.HexNumber); + // OK. Get rid of our copy of that brace (we know it's there) and everything that follows + var hexDigitsOnly = hexDigitsAndClosingBrace.Substring(0, 4); - // We're done... - index += 8; // {U+XXXX} - return new SmartKey(code, input_interop.KEYEVENTF_UNICODE, 1); + // Get the actual value by converting from HEX + WORD code = WORD.Parse(hexDigitsOnly, NumberStyles.HexNumber); + + // We're done... + index += 8; // {U+XXXX} + return new SmartKey(code, input_interop.KEYEVENTF_UNICODE, 1); + } + return null; } - return null; - } - private input_interop.KeyMap? FindScanCodeKey(string keyString, int index) - { - foreach (var scanCode in input_interop.ScanCodeKeyMap) + private input_interop.KeyMap? FindScanCodeKey(string keyString, int index) { - var found = string.Compare(scanCode.Word, 0, keyString, index, scanCode.Word.Length, StringComparison.OrdinalIgnoreCase) == 0; - if (found) return scanCode; + foreach (var scanCode in input_interop.ScanCodeKeyMap) + { + var found = string.Compare(scanCode.Word, 0, keyString, index, scanCode.Word.Length, StringComparison.OrdinalIgnoreCase) == 0; + if (found) return scanCode; + } + return null; } - return null; - } - private SmartKey? CheckScanCodeKeys(string keyString, ref int index) - { - var scanCode = FindScanCodeKey(keyString, index + 1); - if (scanCode != null) + private SmartKey? CheckScanCodeKeys(string keyString, ref int index) { - index += 1; // skipping '{' - SmartKey key = CreateScanCodeKey(scanCode.Value, ref index); - - var modifiers = new List(); - while (index < keyString.Length && (keyString[index] == '}' || keyString[index] == '-')) + var scanCode = FindScanCodeKey(keyString, index + 1); + if (scanCode != null) { - if (keyString[index] == '}') - { - index += 1; // skipping '}' - modifiers.Reverse(); - return modifiers.Aggregate(key, (key, modifier) => modifier.SetModifiedKey(key)); - } - else if (keyString[index] == '-') + index += 1; // skipping '{' + SmartKey key = CreateScanCodeKey(scanCode.Value, ref index); + + var modifiers = new List(); + while (index < keyString.Length && (keyString[index] == '}' || keyString[index] == '-')) { - index += 1; // skipping '-' - modifiers.Add(key.AsModifier()); + if (keyString[index] == '}') + { + index += 1; // skipping '}' + modifiers.Reverse(); + return modifiers.Aggregate(key, (key, modifier) => modifier.SetModifiedKey(key)); + } + else if (keyString[index] == '-') + { + index += 1; // skipping '-' + modifiers.Add(key.AsModifier()); - scanCode = FindScanCodeKey(keyString, index); - key = scanCode != null - ? CreateScanCodeKey(scanCode.Value, ref index) - : EvalCharKey(keyString, ref index); + scanCode = FindScanCodeKey(keyString, index); + key = scanCode != null + ? CreateScanCodeKey(scanCode.Value, ref index) + : EvalCharKey(keyString, ref index); + } } + throw new ApplicationException($"Invalid scan code at index={index}"); } - throw new ApplicationException($"Invalid scan code at index={index}"); + return null; } - return null; - } - private SmartKey? CheckBraceEscapedRequiredKeys(string keyString, ref int index) - { - if (RequiresBraceEscape(keyString[index + 1]) && keyString[index + 2] == '}') - { - var key = CreateScanCodeKeyFromChar(keyString[index + 1]); - index += 3; // {k} - return key; - } - return null; - } - - protected SmartKey? EvalParen(string keyString, ref int index) - { - // Make sure we're really evaluating a paren - if (keyString.Length < index || keyString[index] != '(') + private SmartKey? CheckBraceEscapedRequiredKeys(string keyString, ref int index) { + if (RequiresBraceEscape(keyString[index + 1]) && keyString[index + 2] == '}') + { + var key = CreateScanCodeKeyFromChar(keyString[index + 1]); + index += 3; // {k} + return key; + } return null; } - CKeyGroup group = new CKeyGroup(); - index += 1; // skipping '(' - - while (keyString.Length > index && keyString[index] != ')') + protected SmartKey? EvalParen(string keyString, ref int index) { - SmartKey? pSubKey = GetNextKey(keyString, ref index); - if (pSubKey == null) + // Make sure we're really evaluating a paren + if (keyString.Length < index || keyString[index] != '(') { - index -= 1; // reversing the skipping of '(' return null; } - group.Keys.Add(pSubKey); - } + CKeyGroup group = new CKeyGroup(); + index += 1; // skipping '(' - if (keyString.Length > index && keyString[index] == ')') - { - index += 1; // skipping ')' - } + while (keyString.Length > index && keyString[index] != ')') + { + SmartKey? pSubKey = GetNextKey(keyString, ref index); + if (pSubKey == null) + { + index -= 1; // reversing the skipping of '(' + return null; + } - return group; - } + group.Keys.Add(pSubKey); + } - protected SmartKey.Modifier? EvalModifier(string keyString, ref int index) - { - var modifierKey = keyString[index] switch - { - '%' => new SmartKey.Modifier(0x0038), - '^' => new SmartKey.Modifier(0x001D), - '+' => new SmartKey.Modifier(0x002A), - _ => null - }; + if (keyString.Length > index && keyString[index] == ')') + { + index += 1; // skipping ')' + } + + return group; + } - if (modifierKey != null) + protected SmartKey.Modifier? EvalModifier(string keyString, ref int index) { - index += 1; // skipping '%', '^', or '+' + var modifierKey = keyString[index] switch + { + '%' => new SmartKey.Modifier(0x0038), + '^' => new SmartKey.Modifier(0x001D), + '+' => new SmartKey.Modifier(0x002A), + _ => null + }; - var key = GetNextKey(keyString, ref index); - if (key != null) modifierKey.SetModifiedKey(key); + if (modifierKey != null) + { + index += 1; // skipping '%', '^', or '+' - return modifierKey; - } + var key = GetNextKey(keyString, ref index); + if (key != null) modifierKey.SetModifiedKey(key); - return null; - } + return modifierKey; + } - protected SmartKey CreateScanCodeKeyFromChar(char ch) - { - SmartKey? pKey = null; + return null; + } - // Some modifiers we may or may not need: - SmartKey.Modifier? pShift = null; - SmartKey.Modifier? pCtrl = null; - SmartKey.Modifier? pAlt = null; - SmartKey.Modifier? pHankaku = null; + protected SmartKey CreateScanCodeKeyFromChar(char ch) + { + SmartKey? pKey = null; - short vKey = input_interop.VkKeyScan(ch); - //input_interop.VkKeyScanEx(ch, KeyboardPointer.Current.Pointer()); + // Some modifiers we may or may not need: + SmartKey.Modifier? pShift = null; + SmartKey.Modifier? pCtrl = null; + SmartKey.Modifier? pAlt = null; + SmartKey.Modifier? pHankaku = null; - if (vKey != -1) - { - WORD wScanCode = (WORD)input_interop.MapVirtualKey((uint)(vKey & 0xFF), input_interop.MapVirtualKeyType.MAPVK_VK_TO_VSC); - //input_interop.MapVirtualKeyEx((uint)(vKey & 0xFF), 0, KeyboardPointer.Current.Pointer()); + short vKey = input_interop.VkKeyScan(ch); + //input_interop.VkKeyScanEx(ch, KeyboardPointer.Current.Pointer()); - if (wScanCode != 0) + if (vKey != -1) { - if ((vKey & 0x0100) != 0) - { - // We need a SHIFT press. - pShift = new SmartKey.Modifier(0x2a); - } - if ((vKey & 0x0200) != 0) - { - // We need a CTRL press. - pCtrl = new SmartKey.Modifier(0x1d); - } - if ((vKey & 0x0400) != 0) - { - // We need an ALT press. - pAlt = new SmartKey.Modifier(0x38); - } - if ((vKey & 0x0800) != 0) + WORD wScanCode = (WORD)input_interop.MapVirtualKey((uint)(vKey & 0xFF), input_interop.MapVirtualKeyType.MAPVK_VK_TO_VSC); + //input_interop.MapVirtualKeyEx((uint)(vKey & 0xFF), 0, KeyboardPointer.Current.Pointer()); + + if (wScanCode != 0) { - // We need a Hankaku press. - pHankaku = new SmartKey.Modifier(0x76); - } + if ((vKey & 0x0100) != 0) + { + // We need a SHIFT press. + pShift = new SmartKey.Modifier(0x2a); + } + if ((vKey & 0x0200) != 0) + { + // We need a CTRL press. + pCtrl = new SmartKey.Modifier(0x1d); + } + if ((vKey & 0x0400) != 0) + { + // We need an ALT press. + pAlt = new SmartKey.Modifier(0x38); + } + if ((vKey & 0x0800) != 0) + { + // We need a Hankaku press. + pHankaku = new SmartKey.Modifier(0x76); + } - // Make the actual key we're interested in. - pKey = new SmartKey(wScanCode, input_interop.KEYEVENTF_SCANCODE, 1); + // Make the actual key we're interested in. + pKey = new SmartKey(wScanCode, input_interop.KEYEVENTF_SCANCODE, 1); - // Put it all together. - if (pHankaku != null) - { - pHankaku.SetModifiedKey(pKey); - pKey = pHankaku; - } - if (pAlt != null) - { - pAlt.SetModifiedKey(pKey); - pKey = pAlt; - } - if (pCtrl != null) - { - pCtrl.SetModifiedKey(pKey); - pKey = pCtrl; - } - if (pShift != null) - { - pShift.SetModifiedKey(pKey); - pKey = pShift; + // Put it all together. + if (pHankaku != null) + { + pHankaku.SetModifiedKey(pKey); + pKey = pHankaku; + } + if (pAlt != null) + { + pAlt.SetModifiedKey(pKey); + pKey = pAlt; + } + if (pCtrl != null) + { + pCtrl.SetModifiedKey(pKey); + pKey = pCtrl; + } + if (pShift != null) + { + pShift.SetModifiedKey(pKey); + pKey = pShift; + } } } + + // If all that didn't work, we have to resort to sending a + // Unicode keypress instead. + if (pKey == null) + { + pKey = new SmartKey(ch, input_interop.KEYEVENTF_UNICODE, 1); + } + + return pKey; } - // If all that didn't work, we have to resort to sending a - // Unicode keypress instead. - if (pKey == null) + protected SmartKey CreateScanCodeKey(input_interop.KeyMap scanCode, ref int index) { - pKey = new SmartKey(ch, input_interop.KEYEVENTF_UNICODE, 1); + index += scanCode.Word.Length; + return input_interop.IS_SPECIAL_SCANCODE(scanCode.Code) + ? CreateSpecialKey(scanCode.Code) + : new SmartKey(scanCode.Code, input_interop.KEYEVENTF_SCANCODE, 1); } - return pKey; - } - - protected SmartKey CreateScanCodeKey(input_interop.KeyMap scanCode, ref int index) - { - index += scanCode.Word.Length; - return input_interop.IS_SPECIAL_SCANCODE(scanCode.Code) - ? CreateSpecialKey(scanCode.Code) - : new SmartKey(scanCode.Code, input_interop.KEYEVENTF_SCANCODE, 1); - } - - protected SmartKey CreateSpecialKey(WORD code) - { - return code switch + protected SmartKey CreateSpecialKey(WORD code) { - input_interop.SCANCODE_SPECIAL_BREAK => new SmartKey((WORD)input_interop.VirtualKeyStates.VK_PAUSE, input_interop.VIRTUAL_KEY, 1), - input_interop.SCANCODE_SPECIAL_PRTSC => new SmartKey((WORD)input_interop.VirtualKeyStates.VK_PRINT, input_interop.VIRTUAL_KEY, 1), - input_interop.SCANCODE_SPECIAL_SLEEP => new SmartKey((WORD)input_interop.VirtualKeyStates.VK_SLEEP, input_interop.VIRTUAL_KEY, 1), - input_interop.SCANCODE_SPECIAL_CAPSON => new Toggle(input_interop.STATE_CAPS | input_interop.STATE_ON), - input_interop.SCANCODE_SPECIAL_CAPSOFF => new Toggle(input_interop.STATE_CAPS | input_interop.STATE_OFF), - input_interop.SCANCODE_SPECIAL_NUMON => new Toggle(input_interop.STATE_NUM | input_interop.STATE_ON), - input_interop.SCANCODE_SPECIAL_NUMOFF => new Toggle(input_interop.STATE_NUM | input_interop.STATE_OFF), - input_interop.SCANCODE_SPECIAL_SCRON => new Toggle(input_interop.STATE_SCROLL | input_interop.STATE_ON), - input_interop.SCANCODE_SPECIAL_SCROFF => new Toggle(input_interop.STATE_SCROLL | input_interop.STATE_OFF), - _ => throw new ApplicationException("Invalid special key") - }; - } + return code switch + { + input_interop.SCANCODE_SPECIAL_BREAK => new SmartKey((WORD)input_interop.VirtualKeyStates.VK_PAUSE, input_interop.VIRTUAL_KEY, 1), + input_interop.SCANCODE_SPECIAL_PRTSC => new SmartKey((WORD)input_interop.VirtualKeyStates.VK_PRINT, input_interop.VIRTUAL_KEY, 1), + input_interop.SCANCODE_SPECIAL_SLEEP => new SmartKey((WORD)input_interop.VirtualKeyStates.VK_SLEEP, input_interop.VIRTUAL_KEY, 1), + input_interop.SCANCODE_SPECIAL_CAPSON => new Toggle(input_interop.STATE_CAPS | input_interop.STATE_ON), + input_interop.SCANCODE_SPECIAL_CAPSOFF => new Toggle(input_interop.STATE_CAPS | input_interop.STATE_OFF), + input_interop.SCANCODE_SPECIAL_NUMON => new Toggle(input_interop.STATE_NUM | input_interop.STATE_ON), + input_interop.SCANCODE_SPECIAL_NUMOFF => new Toggle(input_interop.STATE_NUM | input_interop.STATE_OFF), + input_interop.SCANCODE_SPECIAL_SCRON => new Toggle(input_interop.STATE_SCROLL | input_interop.STATE_ON), + input_interop.SCANCODE_SPECIAL_SCROFF => new Toggle(input_interop.STATE_SCROLL | input_interop.STATE_OFF), + _ => throw new ApplicationException("Invalid special key") + }; + } - protected static string EscapeSendKeySpecialChars(string text) - { - var sb = new StringBuilder(); - foreach (var ch in text) + protected static string EscapeSendKeySpecialChars(string text) { - if (RequiresBraceEscape(ch)) + var sb = new StringBuilder(); + foreach (var ch in text) { - sb.Append($"{{{ch}}}"); - } - else - { - sb.Append(ch); + if (RequiresBraceEscape(ch)) + { + sb.Append($"{{{ch}}}"); + } + else + { + sb.Append(ch); + } } + return sb.ToString(); } - return sb.ToString(); - } - protected static bool RequiresBraceEscape(char c) - { - return input_interop.BraceEscapeRequiredChars.Contains(c); - } + protected static bool RequiresBraceEscape(char c) + { + return input_interop.BraceEscapeRequiredChars.Contains(c); + } - protected List m_KeyList = new(); + protected List m_KeyList = new(); + } } } \ No newline at end of file diff --git a/src/win32_ui/PlatformServices/SmartKey_Modifier.cs b/src/win32_ui/PlatformServices/SmartKey_Modifier.cs index bad197e1..9f9c3d8a 100644 --- a/src/win32_ui/PlatformServices/SmartKey_Modifier.cs +++ b/src/win32_ui/PlatformServices/SmartKey_Modifier.cs @@ -1,58 +1,59 @@ -using WORD = System.UInt16; using DWORD = System.UInt32; +using WORD = System.UInt16; -namespace macaroni; - -internal partial class SmartKey +namespace macaroni { - // Class CModifierKey - // This key will press and hold when Send() is called, press and release m_ModifiedKey, - // then release the keys. - public class Modifier : SmartKey + internal partial class SmartKey { - public Modifier(WORD wScanCode, DWORD dwFlags = input_interop.KEYEVENTF_SCANCODE) : base(wScanCode, dwFlags, 1) + // Class CModifierKey + // This key will press and hold when Send() is called, press and release m_ModifiedKey, + // then release the keys. + public class Modifier : SmartKey { - } - - public Modifier(input_interop.INPUT input, uint repeatCount) : base(input, repeatCount) - { - m_Input = input; - m_repeatCount = repeatCount; - } + public Modifier(WORD wScanCode, DWORD dwFlags = input_interop.KEYEVENTF_SCANCODE) : base(wScanCode, dwFlags, 1) + { + } - public virtual Modifier SetModifiedKey(SmartKey? modifiedKey) - { - m_ModifiedKey = modifiedKey; - return this; - } + public Modifier(input_interop.INPUT input, uint repeatCount) : base(input, repeatCount) + { + m_Input = input; + m_repeatCount = repeatCount; + } - public override void Send() - { - if (m_ModifiedKey == null) + public virtual Modifier SetModifiedKey(SmartKey? modifiedKey) { - throw new InvalidDataException("SetModifiedKey not called"); + m_ModifiedKey = modifiedKey; + return this; } - for (int i = 0; i < m_repeatCount; i++) + public override void Send() { - Press(); - m_ModifiedKey.Send(); - Release(); + if (m_ModifiedKey == null) + { + throw new InvalidDataException("SetModifiedKey not called"); + } + + for (int i = 0; i < m_repeatCount; i++) + { + Press(); + m_ModifiedKey.Send(); + Release(); + } } - } - public override DWORD AsVks(out IEnumerable modifiers) - { - if (m_ModifiedKey == null) + public override DWORD AsVks(out IEnumerable modifiers) { - throw new InvalidDataException("SetModifiedKey not called"); + if (m_ModifiedKey == null) + { + throw new InvalidDataException("SetModifiedKey not called"); + } + + var vk = m_ModifiedKey.AsVks(out modifiers); + modifiers = modifiers.Prepend(base.AsVks(out _)); + return vk; } - var vk = m_ModifiedKey.AsVks(out modifiers); - modifiers = modifiers.Prepend(base.AsVks(out _)); - return vk; + protected SmartKey? m_ModifiedKey; } - - protected SmartKey? m_ModifiedKey; } } \ No newline at end of file diff --git a/src/win32_ui/PlatformServices/SmartKey_Toggle.cs b/src/win32_ui/PlatformServices/SmartKey_Toggle.cs index 301de8cc..7fdea0e7 100644 --- a/src/win32_ui/PlatformServices/SmartKey_Toggle.cs +++ b/src/win32_ui/PlatformServices/SmartKey_Toggle.cs @@ -1,73 +1,74 @@ -using WORD = System.UInt16; using DWORD = System.UInt32; +using WORD = System.UInt16; -namespace macaroni; - -internal partial class SmartKey +namespace macaroni { - // Class CStateKey - // This key is used to explicitly set the keyboard state of one - // of the lock keys (caps, scroll, num). - public class Toggle : SmartKey + internal partial class SmartKey { - public Toggle(DWORD dwKeyType) : base(0, input_interop.KEYEVENTF_SCANCODE, 1) + // Class CStateKey + // This key is used to explicitly set the keyboard state of one + // of the lock keys (caps, scroll, num). + public class Toggle : SmartKey { - m_dwKeyType = dwKeyType; - - // Set up the scancode - switch (input_interop.KEY_VALUE(m_dwKeyType)) + public Toggle(DWORD dwKeyType) : base(0, input_interop.KEYEVENTF_SCANCODE, 1) { - case input_interop.STATE_CAPS: - m_Input.U.ki.wScan = 0x003a; - break; + m_dwKeyType = dwKeyType; - case input_interop.STATE_NUM: - m_Input.U.ki.wScan = 0x0045; - break; + // Set up the scancode + switch (input_interop.KEY_VALUE(m_dwKeyType)) + { + case input_interop.STATE_CAPS: + m_Input.U.ki.wScan = 0x003a; + break; - case input_interop.STATE_SCROLL: - m_Input.U.ki.wScan = 0x0046; - break; + case input_interop.STATE_NUM: + m_Input.U.ki.wScan = 0x0045; + break; - default: - break; - } - } + case input_interop.STATE_SCROLL: + m_Input.U.ki.wScan = 0x0046; + break; - public override void Send() - { - // Get the key state of the key we're interested in. - input_interop.VirtualKeyStates iKey = 0; - if (input_interop.KEY_VALUE(m_dwKeyType) == input_interop.STATE_CAPS) - { - iKey = input_interop.VirtualKeyStates.VK_CAPITAL; + default: + break; + } } - else if (input_interop.KEY_VALUE(m_dwKeyType) == input_interop.STATE_NUM) - { - iKey = input_interop.VirtualKeyStates.VK_NUMLOCK; - } - else if (input_interop.KEY_VALUE(m_dwKeyType) == input_interop.STATE_SCROLL) + + public override void Send() { - iKey = input_interop.VirtualKeyStates.VK_SCROLL; - } + // Get the key state of the key we're interested in. + input_interop.VirtualKeyStates iKey = 0; + if (input_interop.KEY_VALUE(m_dwKeyType) == input_interop.STATE_CAPS) + { + iKey = input_interop.VirtualKeyStates.VK_CAPITAL; + } + else if (input_interop.KEY_VALUE(m_dwKeyType) == input_interop.STATE_NUM) + { + iKey = input_interop.VirtualKeyStates.VK_NUMLOCK; + } + else if (input_interop.KEY_VALUE(m_dwKeyType) == input_interop.STATE_SCROLL) + { + iKey = input_interop.VirtualKeyStates.VK_SCROLL; + } - // The low-order bit is set if the key state is on - WORD wState = input_interop.GetKeyState(iKey); + // The low-order bit is set if the key state is on + WORD wState = input_interop.GetKeyState(iKey); - // Do we need to do anything? - if (((wState & 0x0001) != 0 && input_interop.KEY_STATE(m_dwKeyType) != 0) || - ((wState & 0x0001) == 0 && input_interop.KEY_STATE(m_dwKeyType) == 0)) - { - // Nope. - return; - } + // Do we need to do anything? + if (((wState & 0x0001) != 0 && input_interop.KEY_STATE(m_dwKeyType) != 0) || + ((wState & 0x0001) == 0 && input_interop.KEY_STATE(m_dwKeyType) == 0)) + { + // Nope. + return; + } - // Send the key + // Send the key - Press(); - Release(); - } + Press(); + Release(); + } - protected DWORD m_dwKeyType; + protected DWORD m_dwKeyType; + } } } \ No newline at end of file diff --git a/src/win32_ui/PlatformServices/WindowMonitor.cs b/src/win32_ui/PlatformServices/WindowMonitor.cs index f4f951dd..d8a337cf 100644 --- a/src/win32_ui/PlatformServices/WindowMonitor.cs +++ b/src/win32_ui/PlatformServices/WindowMonitor.cs @@ -1,118 +1,119 @@ using System.Diagnostics; -namespace macaroni; - -internal class WindowMonitor +namespace macaroni { - public WindowInfo GetCurrentWindowInfo() + internal class WindowMonitor { - return _currentInfo; - } + public WindowInfo GetCurrentWindowInfo() + { + return _currentInfo; + } - public IDictionary GetAllWindowInfo() - { - return new Dictionary(_currentWindows); - } + public IDictionary GetAllWindowInfo() + { + return new Dictionary(_currentWindows); + } - public void StartNotify(Action foregroundChanged, Action, IDictionary> backgroundChanged, int foregroundFrequency = 1000, int backgroundFrequency = 5000) - { - _timerFrequency= foregroundFrequency; - _backgroundFrequency = backgroundFrequency; + public void StartNotify(Action foregroundChanged, Action, IDictionary> backgroundChanged, int foregroundFrequency = 1000, int backgroundFrequency = 5000) + { + _timerFrequency = foregroundFrequency; + _backgroundFrequency = backgroundFrequency; - _foregroundChanged = foregroundChanged; - _backgroundChanged = backgroundChanged; + _foregroundChanged = foregroundChanged; + _backgroundChanged = backgroundChanged; - _timer = new System.Threading.Timer(s => (s as WindowMonitor)?.TimerTick(), this, _timerFrequency, _timerFrequency); - } + _timer = new System.Threading.Timer(s => (s as WindowMonitor)?.TimerTick(), this, _timerFrequency, _timerFrequency); + } - public void StopNotify() - { - _timer?.Dispose(); - _timer = null; - } + public void StopNotify() + { + _timer?.Dispose(); + _timer = null; + } - private void TimerTick() - { - lock (this) + private void TimerTick() { - var hwnd = window_interop.GetForegroundWindow(); - var info = WindowInfo.FromHwnd(hwnd); - if (info == null) return; + lock (this) + { + var hwnd = window_interop.GetForegroundWindow(); + var info = WindowInfo.FromHwnd(hwnd); + if (info == null) return; - CheckInfo(info); + CheckInfo(info); + } } - } - private void CheckInfo(WindowInfo info) - { - var hwndChanged = _currentInfo.hwnd != info.hwnd; - var titleChanged = !hwndChanged && _currentInfo?.Title != info.Title; + private void CheckInfo(WindowInfo info) + { + var hwndChanged = _currentInfo.hwnd != info.hwnd; + var titleChanged = !hwndChanged && _currentInfo?.Title != info.Title; - var foregroundChanged = hwndChanged || titleChanged; - if (foregroundChanged) ForegroundWindowChanged(info); + var foregroundChanged = hwndChanged || titleChanged; + if (foregroundChanged) ForegroundWindowChanged(info); - var checkBackground = foregroundChanged || _nextBackgroundCheck == null || DateTime.Now >= _nextBackgroundCheck; - if (checkBackground) - { - _nextBackgroundCheck = DateTime.Now.AddMilliseconds(_backgroundFrequency); - CheckBackground(); + var checkBackground = foregroundChanged || _nextBackgroundCheck == null || DateTime.Now >= _nextBackgroundCheck; + if (checkBackground) + { + _nextBackgroundCheck = DateTime.Now.AddMilliseconds(_backgroundFrequency); + CheckBackground(); + } } - } - private void CheckBackground() - { - var windows = WindowInfo.GetVisibleWindows(); + private void CheckBackground() + { + var windows = WindowInfo.GetVisibleWindows(); - var id = Process.GetCurrentProcess().Id; - var f1 = windows.Where(x => x.Value.ProcessId != id); - var f2 = _currentWindows.Where(x => x.Value.ProcessId != id); + var id = Process.GetCurrentProcess().Id; + var f1 = windows.Where(x => x.Value.ProcessId != id); + var f2 = _currentWindows.Where(x => x.Value.ProcessId != id); - var changed = f1.Count() != f2.Count(); - if (!changed) - { - if (Debugger.IsAttached) + var changed = f1.Count() != f2.Count(); + if (!changed) { - f1 = f1.Where(x => x.Value.Process == null || !x.Value.Process.EndsWith("devenv.exe")); - f2 = f2.Where(x => x.Value.Process == null || !x.Value.Process.EndsWith("devenv.exe")); + if (Debugger.IsAttached) + { + f1 = f1.Where(x => x.Value.Process == null || !x.Value.Process.EndsWith("devenv.exe")); + f2 = f2.Where(x => x.Value.Process == null || !x.Value.Process.EndsWith("devenv.exe")); + } + var s1 = string.Join('\n', f1.OrderBy(x => x.Key).Select(x => x.Value.Title)); + var s2 = string.Join('\n', f2.OrderBy(x => x.Key).Select(x => x.Value.Title)); + changed = s1 != s2; } - var s1 = string.Join('\n', f1.OrderBy(x => x.Key).Select(x => x.Value.Title)); - var s2 = string.Join('\n', f2.OrderBy(x => x.Key).Select(x => x.Value.Title)); - changed = s1 != s2; - } - if (changed) - { - BackgroundWindowsChanged(windows); + if (changed) + { + BackgroundWindowsChanged(windows); + } } - } - private void ForegroundWindowChanged(WindowInfo newInfo) - { - if (_foregroundChanged != null) + private void ForegroundWindowChanged(WindowInfo newInfo) { - _foregroundChanged(_currentInfo, newInfo); + if (_foregroundChanged != null) + { + _foregroundChanged(_currentInfo, newInfo); + } + _currentInfo = newInfo; } - _currentInfo = newInfo; - } - private void BackgroundWindowsChanged(IDictionary newSet) - { - if (_backgroundChanged != null) + private void BackgroundWindowsChanged(IDictionary newSet) { - _backgroundChanged(_currentWindows, newSet); + if (_backgroundChanged != null) + { + _backgroundChanged(_currentWindows, newSet); + } + _currentWindows = newSet; } - _currentWindows = newSet; - } - private System.Threading.Timer? _timer; - private int _timerFrequency; + private System.Threading.Timer? _timer; + private int _timerFrequency; - private WindowInfo _currentInfo = new(); - private DateTime? _nextBackgroundCheck; - private int _backgroundFrequency; + private WindowInfo _currentInfo = new(); + private DateTime? _nextBackgroundCheck; + private int _backgroundFrequency; - private IDictionary _currentWindows = new Dictionary(); + private IDictionary _currentWindows = new Dictionary(); - private Action? _foregroundChanged; - private Action, IDictionary>? _backgroundChanged; -} + private Action? _foregroundChanged; + private Action, IDictionary>? _backgroundChanged; + } +} \ No newline at end of file diff --git a/src/win32_ui/PlatformServices/WindowMonitoringService.cs b/src/win32_ui/PlatformServices/WindowMonitoringService.cs index ae95bdf4..acaad157 100644 --- a/src/win32_ui/PlatformServices/WindowMonitoringService.cs +++ b/src/win32_ui/PlatformServices/WindowMonitoringService.cs @@ -1,96 +1,97 @@ -namespace macaroni; - -internal class WindowMonitoringService : IWindowMonitoringService +namespace macaroni { - public WindowInfo GetCurrentWindowInfo() + internal class WindowMonitoringService : IWindowMonitoringService { - EnsureMonitoring(); - return _monitor!.GetCurrentWindowInfo(); - } - - public IDictionary GetAllWindowInfo() - { - EnsureMonitoring(); - return _monitor!.GetAllWindowInfo(); - } - - public void StartNotify(Action foregroundChanged, Action, IDictionary> backgroundChanged) - { - EnsureMonitoring(); + public WindowInfo GetCurrentWindowInfo() + { + EnsureMonitoring(); + return _monitor!.GetCurrentWindowInfo(); + } - _foregroundChanged = foregroundChanged; - _backgroundChanged = backgroundChanged; - _list.Add(this); - } + public IDictionary GetAllWindowInfo() + { + EnsureMonitoring(); + return _monitor!.GetAllWindowInfo(); + } - public void StopNotify() - { - _list.Remove(this); - _foregroundChanged = null; - _backgroundChanged = null; + public void StartNotify(Action foregroundChanged, Action, IDictionary> backgroundChanged) + { + EnsureMonitoring(); - CheckStopMonitoring(); - } + _foregroundChanged = foregroundChanged; + _backgroundChanged = backgroundChanged; + _list.Add(this); + } - private static void CheckStopMonitoring() - { - if (_list.Count() == 0) + public void StopNotify() { - _monitor?.StopNotify(); - _monitor = null; + _list.Remove(this); + _foregroundChanged = null; + _backgroundChanged = null; + + CheckStopMonitoring(); } - } - private static void EnsureMonitoring() - { - if (_monitor == null) + private static void CheckStopMonitoring() { - _monitor = new WindowMonitor(); - _monitor.StartNotify( - (oldForeground, newForeground) => ForegroundChanged(oldForeground, newForeground), - (oldBackground, newBackground) => BackgroundChanged(oldBackground, newBackground) - ); + if (_list.Count() == 0) + { + _monitor?.StopNotify(); + _monitor = null; + } } - } - private static void ForegroundChanged(WindowInfo oldForeground, WindowInfo newForeground) - { - var copy = _list.ToList(); - foreach (var item in copy) + private static void EnsureMonitoring() { - if (item._foregroundChanged != null) + if (_monitor == null) { - item._foregroundChanged(oldForeground, newForeground); + _monitor = new WindowMonitor(); + _monitor.StartNotify( + (oldForeground, newForeground) => ForegroundChanged(oldForeground, newForeground), + (oldBackground, newBackground) => BackgroundChanged(oldBackground, newBackground) + ); } - }; - } + } - private static void BackgroundChanged(IDictionary oldBackground, IDictionary newBackground) - { - // MR.DBG_TRACE_INFO("**********************"); - // foreach (var i in oldBackground.Values) - // { - // MR.DBG_TRACE_INFO($"Old: {i.Process}: {i.Title}"); - // } - // foreach (var i in newBackground.Values) - // { - // MR.DBG_TRACE_INFO($"New: {i.Process}: {i.Title}"); - // } - // MR.DBG_TRACE_INFO("**********************"); + private static void ForegroundChanged(WindowInfo oldForeground, WindowInfo newForeground) + { + var copy = _list.ToList(); + foreach (var item in copy) + { + if (item._foregroundChanged != null) + { + item._foregroundChanged(oldForeground, newForeground); + } + }; + } - var copy = _list.ToList(); // make a copy in case the list changes while we're in the middle of iterating - foreach (var item in copy) + private static void BackgroundChanged(IDictionary oldBackground, IDictionary newBackground) { - if (item._backgroundChanged != null) + // MR.DBG_TRACE_INFO("**********************"); + // foreach (var i in oldBackground.Values) + // { + // MR.DBG_TRACE_INFO($"Old: {i.Process}: {i.Title}"); + // } + // foreach (var i in newBackground.Values) + // { + // MR.DBG_TRACE_INFO($"New: {i.Process}: {i.Title}"); + // } + // MR.DBG_TRACE_INFO("**********************"); + + var copy = _list.ToList(); // make a copy in case the list changes while we're in the middle of iterating + foreach (var item in copy) { - item._backgroundChanged(oldBackground, newBackground); - } - }; - } + if (item._backgroundChanged != null) + { + item._backgroundChanged(oldBackground, newBackground); + } + }; + } - private static WindowMonitor? _monitor = null; - private static List _list = new(); + private static WindowMonitor? _monitor = null; + private static List _list = new(); - private Action? _foregroundChanged; - private Action, IDictionary>? _backgroundChanged; -} + private Action? _foregroundChanged; + private Action, IDictionary>? _backgroundChanged; + } +} \ No newline at end of file diff --git a/src/win32_ui/PlatformServices/WindowTitleContextResolver.cs b/src/win32_ui/PlatformServices/WindowTitleContextResolver.cs index 21440516..dee46157 100644 --- a/src/win32_ui/PlatformServices/WindowTitleContextResolver.cs +++ b/src/win32_ui/PlatformServices/WindowTitleContextResolver.cs @@ -1,47 +1,48 @@ using Microsoft.Extensions.DependencyInjection; -namespace macaroni; - -internal class WindowTitleContextResolver : ISystemContextResolver +namespace macaroni { - public WindowTitleContextResolver(IServiceProvider serviceProvider) + internal class WindowTitleContextResolver : ISystemContextResolver { - _serviceProvider = serviceProvider; - } + public WindowTitleContextResolver(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } - public object? Get(string key, object? defaultValue) - { - return key switch + public object? Get(string key, object? defaultValue) { - "window.title" => GetCurrentWindowTitle() ?? defaultValue, - "all.window.titles" => GetAllWindowTitles() ?? defaultValue, - _ => defaultValue - }; - } + return key switch + { + "window.title" => GetCurrentWindowTitle() ?? defaultValue, + "all.window.titles" => GetAllWindowTitles() ?? defaultValue, + _ => defaultValue + }; + } - private string? GetCurrentWindowTitle() - { - EnsureMonitor(); - return _monitor!.GetCurrentWindowInfo().Title; - } + private string? GetCurrentWindowTitle() + { + EnsureMonitor(); + return _monitor!.GetCurrentWindowInfo().Title; + } - private string? GetAllWindowTitles() - { - EnsureMonitor(); - var allWindows = _monitor!.GetAllWindowInfo(); - return allWindows.Count > 0 - ? string.Join('\n', allWindows.Select(x => x.Value.Title)) - : null; - } + private string? GetAllWindowTitles() + { + EnsureMonitor(); + var allWindows = _monitor!.GetAllWindowInfo(); + return allWindows.Count > 0 + ? string.Join('\n', allWindows.Select(x => x.Value.Title)) + : null; + } - private void EnsureMonitor() - { - if (_monitor == null) + private void EnsureMonitor() { - _monitor = _serviceProvider.GetRequiredService(); + if (_monitor == null) + { + _monitor = _serviceProvider.GetRequiredService(); + } } - } - private readonly IServiceProvider _serviceProvider; - private IWindowMonitoringService? _monitor = null; -} + private readonly IServiceProvider _serviceProvider; + private IWindowMonitoringService? _monitor = null; + } +} \ No newline at end of file diff --git a/src/win32_ui/PlatformServices/WindowsClipboardService.cs b/src/win32_ui/PlatformServices/WindowsClipboardService.cs index 7a047c18..7469f541 100644 --- a/src/win32_ui/PlatformServices/WindowsClipboardService.cs +++ b/src/win32_ui/PlatformServices/WindowsClipboardService.cs @@ -1,147 +1,149 @@ using System.Text; -namespace macaroni; - -internal class WindowsClipboardService : IClipboardService +namespace macaroni { - public WindowsClipboardService(IInvokeOnUiThread invoke, IImageAnalysisService analyzeImage) + internal class WindowsClipboardService : IClipboardService { - _invoke = invoke; - _analyzeImage = analyzeImage; - } + public WindowsClipboardService(IInvokeOnUiThread invoke, IImageAnalysisService analyzeImage) + { + _invoke = invoke; + _analyzeImage = analyzeImage; + } - public void Clear() - { - _invoke?.Invoke(() => Clipboard.Clear()); - } + public void Clear() + { + _invoke?.Invoke(() => Clipboard.Clear()); + } - public void Set(string value, string? format) - { - if (format == null || format == "text") + public void Set(string value, string? format) { - if (!string.IsNullOrEmpty(value)) + if (format == null || format == "text") + { + if (!string.IsNullOrEmpty(value)) + { + _invoke?.Invoke(() => Clipboard.SetText(value)); + } + } + else if (format == "html") { - _invoke?.Invoke(() => Clipboard.SetText(value)); + value = UpdateHtmlValue(value); + _invoke?.Invoke(() => Clipboard.SetText(value, TextDataFormat.Html)); + } + else + { + var matches = Enum.GetNames() + .Where(x => x.ToLower() == format.ToLower()) + .Select(x => Enum.Parse(x)); + if (matches.Any() && !string.IsNullOrEmpty(value)) + { + _invoke?.Invoke(() => Clipboard.SetText(value, matches.First())); + } + + throw new NotImplementedException($"ClipboardService format={format} not implemented!"); } } - else if (format == "html") + + public string? GetText() { - value = UpdateHtmlValue(value); - _invoke?.Invoke(() => Clipboard.SetText(value, TextDataFormat.Html)); + return GetClipboardContentAsText(); } - else + + public void SetImage(IImage image) { - var matches = Enum.GetNames() - .Where(x => x.ToLower() == format.ToLower()) - .Select(x => Enum.Parse(x)); - if (matches.Any() && !string.IsNullOrEmpty(value)) + _invoke?.Invoke(() => { - _invoke?.Invoke(() => Clipboard.SetText(value, matches.First())); - } + Clipboard.SetImage(image.GetPlatformImage() as Image); + for (int i = 0; i < 10; i++) + { + if (Clipboard.ContainsImage()) break; + Thread.Sleep(100); + } + }); + } - throw new NotImplementedException($"ClipboardService format={format} not implemented!"); + public IImage? GetImage() + { + return GetClipboardContentAsImage(); } - } - public string? GetText() - { - return GetClipboardContentAsText(); - } + private string UpdateHtmlValue(string value) + { + if (value.StartsWith("Version:0.9")) return value; - public void SetImage(IImage image) - { - _invoke?.Invoke(() => { - Clipboard.SetImage(image.GetPlatformImage() as Image); - for (int i = 0; i < 10; i++) - { - if (Clipboard.ContainsImage()) break; - Thread.Sleep(100); - } - }); - } + var startToken = "<<<<<<<<0"; + var endToken = "<<<<<<<<1"; - public IImage? GetImage() - { - return GetClipboardContentAsImage(); - } - - private string UpdateHtmlValue(string value) - { - if (value.StartsWith("Version:0.9")) return value; + var sb = new StringBuilder(); + sb.AppendLine($"Version:0.9"); + sb.AppendLine($"StartHTML:{startToken}"); + sb.AppendLine($"EndHTML:{endToken}"); + sb.AppendLine($"StartFragment:{startToken}"); + sb.AppendLine($"EndFragment:{endToken}"); + sb.AppendLine($"StartSelection:{startToken}"); + sb.AppendLine($"EndSelection:{endToken}"); - var startToken = "<<<<<<<<0"; - var endToken = "<<<<<<<<1"; + var c1 = Encoding.UTF8.GetByteCount(sb.ToString()); + sb.Append(value); + var c2 = Encoding.UTF8.GetByteCount(sb.ToString()) - 1; - var sb = new StringBuilder(); - sb.AppendLine($"Version:0.9"); - sb.AppendLine($"StartHTML:{startToken}"); - sb.AppendLine($"EndHTML:{endToken}"); - sb.AppendLine($"StartFragment:{startToken}"); - sb.AppendLine($"EndFragment:{endToken}"); - sb.AppendLine($"StartSelection:{startToken}"); - sb.AppendLine($"EndSelection:{endToken}"); + var start = c1.ToString($"D{startToken.Length}"); + var end = c2.ToString($"D{endToken.Length}"); - var c1 = Encoding.UTF8.GetByteCount(sb.ToString()); - sb.Append(value); - var c2 = Encoding.UTF8.GetByteCount(sb.ToString()) - 1; + return sb.Replace(startToken, start).Replace(endToken, end).ToString(); + } - var start = c1.ToString($"D{startToken.Length}"); - var end = c2.ToString($"D{endToken.Length}"); + private string? GetClipboardContentAsText() + { + GetClipboardContent(out var clipboard, out var image, "PNG"); + if (string.IsNullOrEmpty(clipboard) && image != null) + { + clipboard = GetTextFromImage(image); + } - return sb.Replace(startToken, start).Replace(endToken, end).ToString(); - } + return clipboard; + } - private string? GetClipboardContentAsText() - { - GetClipboardContent(out var clipboard, out var image, "PNG"); - if (string.IsNullOrEmpty(clipboard) && image != null) + private IImage? GetClipboardContentAsImage() { - clipboard = GetTextFromImage(image); + GetClipboardContent(out var clipboard, out var image, "PNG"); + if (image != null) + { + var instance = new WindowsImage(); + return instance.TryInit(image) ? instance : null; + } + return null; } - return clipboard; - } - - private IImage? GetClipboardContentAsImage() - { - GetClipboardContent(out var clipboard, out var image, "PNG"); - if (image != null) + private void GetClipboardContent(out string? clipboard, out MemoryStream? data, string? format) { - var instance = new WindowsImage(); - return instance.TryInit(image) ? instance : null; - } - return null; - } + string? text = null; + MemoryStream? stream = null; - private void GetClipboardContent(out string? clipboard, out MemoryStream? data, string? format) - { - string? text = null; - MemoryStream? stream = null; + _invoke.Invoke(() => + { + text = Clipboard.GetText(); + stream = format != null + ? Clipboard.GetData("PNG") as MemoryStream + : null; + }); + + clipboard = text; + data = stream; + } - _invoke.Invoke(() => + private string GetTextFromImage(MemoryStream image) { - text = Clipboard.GetText(); - stream = format != null - ? Clipboard.GetData("PNG") as MemoryStream - : null; - }); - - clipboard = text; - data = stream; - } - - private string GetTextFromImage(MemoryStream image) - { - var tempFile = Path.GetTempFileName() + ".png"; - File.WriteAllBytes(tempFile, image.ToArray()); + var tempFile = Path.GetTempFileName() + ".png"; + File.WriteAllBytes(tempFile, image.ToArray()); - var task = _analyzeImage.Analyze(tempFile, null, null); - task.Wait(); + var task = _analyzeImage.Analyze(tempFile, null, null); + task.Wait(); - return task.Result.AsMonospaceTable(); - } + return task.Result.AsMonospaceTable(); + } - private IImageAnalysisService _analyzeImage; + private IImageAnalysisService _analyzeImage; - private IInvokeOnUiThread _invoke; -} + private IInvokeOnUiThread _invoke; + } +} \ No newline at end of file diff --git a/src/win32_ui/PlatformServices/WindowsCommandSystemHost.cs b/src/win32_ui/PlatformServices/WindowsCommandSystemHost.cs index 3bc844ab..7dae8d72 100644 --- a/src/win32_ui/PlatformServices/WindowsCommandSystemHost.cs +++ b/src/win32_ui/PlatformServices/WindowsCommandSystemHost.cs @@ -1,9 +1,10 @@ -namespace macaroni; - -internal class WindowsCommandSystemHost : ICommandSystemHost +namespace macaroni { - public void Quit() + internal class WindowsCommandSystemHost : ICommandSystemHost { - Application.Exit(); + public void Quit() + { + Application.Exit(); + } } -} +} \ No newline at end of file diff --git a/src/win32_ui/PlatformServices/WindowsHotkeyService.cs b/src/win32_ui/PlatformServices/WindowsHotkeyService.cs index 76887fb6..271a8c13 100644 --- a/src/win32_ui/PlatformServices/WindowsHotkeyService.cs +++ b/src/win32_ui/PlatformServices/WindowsHotkeyService.cs @@ -1,250 +1,247 @@ -using WORD = System.UInt16; -using DWORD = System.UInt32; - -using Microsoft.CognitiveServices.Speech; -using Microsoft.CognitiveServices.Speech.Intent; -using Microsoft.Extensions.DependencyInjection; -using System.Diagnostics; +using Microsoft.Extensions.DependencyInjection; using System.Runtime.InteropServices; +using DWORD = System.UInt32; +using WORD = System.UInt16; -namespace macaroni; - -internal class WindowsHotkeyService : IHotkeyService +namespace macaroni { - public WindowsHotkeyService(IServiceProvider services, ISendKeysService sendKeys) - { - _serviceProvider = services; - _sendKeys = sendKeys; - } - - public Task StartAsync() + internal class WindowsHotkeyService : IHotkeyService { - return Task.CompletedTask; - } + public WindowsHotkeyService(IServiceProvider services, ISendKeysService sendKeys) + { + _serviceProvider = services; + _sendKeys = sendKeys; + } - public Task StopAsync() - { - return Task.CompletedTask; - } + public Task StartAsync() + { + return Task.CompletedTask; + } - public void StartNotify(string groupId, string id, string hotkey, Action callback) - { - lock(_groups) + public Task StopAsync() { - var fireOnPressCount = hotkey.EndsWith("...") ? CountTrailing(hotkey, '.') - 1 : 1; - if (fireOnPressCount > 1) hotkey = hotkey.Trim('.'); + return Task.CompletedTask; + } - if (fireOnPressCount == 1 && hotkey.StartsWith("{hold-")) + public void StartNotify(string groupId, string id, string hotkey, Action callback) + { + lock (_groups) { - fireOnPressCount = 2; - hotkey = hotkey.Replace("{hold-", "{"); - if (hotkey.Length == 3 && hotkey.EndsWith('}')) + var fireOnPressCount = hotkey.EndsWith("...") ? CountTrailing(hotkey, '.') - 1 : 1; + if (fireOnPressCount > 1) hotkey = hotkey.Trim('.'); + + if (fireOnPressCount == 1 && hotkey.StartsWith("{hold-")) { - hotkey = hotkey.Substring(1, 1); + fireOnPressCount = 2; + hotkey = hotkey.Replace("{hold-", "{"); + if (hotkey.Length == 3 && hotkey.EndsWith('}')) + { + hotkey = hotkey.Substring(1, 1); + } } - } - var hotkeyCallback = new HotkeyCallback() { GroupId = groupId, HotkeyId = id, Hotkey = hotkey, FireOnPressCount = fireOnPressCount, Callback = callback }; - AddHotkeyCallback(hotkeyCallback); + var hotkeyCallback = new HotkeyCallback() { GroupId = groupId, HotkeyId = id, Hotkey = hotkey, FireOnPressCount = fireOnPressCount, Callback = callback }; + AddHotkeyCallback(hotkeyCallback); + } } - } - public void StopNotify(string groupId, string? hotkeyId) - { - lock(_groups) + public void StopNotify(string groupId, string? hotkeyId) { - RemoveHotkeyCallback(groupId, hotkeyId); + lock (_groups) + { + RemoveHotkeyCallback(groupId, hotkeyId); + } } - } - private int CountTrailing(string hotkey, char ch) - { - var count = 0; - for (var i = hotkey.Length - 1; i >= 0 && hotkey[i] == ch; i--) + private int CountTrailing(string hotkey, char ch) { - count++; + var count = 0; + for (var i = hotkey.Length - 1; i >= 0 && hotkey[i] == ch; i--) + { + count++; + } + return count; } - return count; - } - private void AddHotkeyCallback(HotkeyCallback hc) - { - MR.DBG_TRACE_VERBOSE($"AddHotkeyCallback('{hc.Hotkey}')"); - RemoveHotkeyCallback(hc.GroupId, hc.HotkeyId); - EnsureHotkeyWindow(); - - if (SmartKey.AsVk(hc.Hotkey, out var vk, out var modifiers, out var extended)) + private void AddHotkeyCallback(HotkeyCallback hc) { - hc.RegisteredId = GetRegisterId(); - RegisterHotkey(hc.RegisteredId, vk, modifiers, extended); - } + MR.DBG_TRACE_VERBOSE($"AddHotkeyCallback('{hc.Hotkey}')"); + RemoveHotkeyCallback(hc.GroupId, hc.HotkeyId); + EnsureHotkeyWindow(); - RequireGroup(hc.GroupId).Add(hc.HotkeyId, hc); - } + if (SmartKey.AsVk(hc.Hotkey, out var vk, out var modifiers, out var extended)) + { + hc.RegisteredId = GetRegisterId(); + RegisterHotkey(hc.RegisteredId, vk, modifiers, extended); + } - private WORD GetRegisterId() - { - var rand = new Random(); - while (true) - { - var id = (WORD)rand.Next(WORD.MinValue, WORD.MaxValue); - var duplicate = _groups.Any(g => g.Value.Any(x => x.Value.RegisteredId == id)); - if (!duplicate) return id; + RequireGroup(hc.GroupId).Add(hc.HotkeyId, hc); } - } - private void EnsureHotkeyWindow() - { - if (_hotkeyWindow == null) + private WORD GetRegisterId() { - _hotkeyWindow = new((id, pressed) => HandleHotkey(id, pressed)); + var rand = new Random(); + while (true) + { + var id = (WORD)rand.Next(WORD.MinValue, WORD.MaxValue); + var duplicate = _groups.Any(g => g.Value.Any(x => x.Value.RegisteredId == id)); + if (!duplicate) return id; + } } - if (_hotkeyWindow.Handle == IntPtr.Zero) + private void EnsureHotkeyWindow() { - var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - _serviceProvider.GetRequiredService().Invoke(() => - _hotkeyWindow.CreateWindow() - ); - tcs.Task.Wait(1000); - } - } + if (_hotkeyWindow == null) + { + _hotkeyWindow = new((id, pressed) => HandleHotkey(id, pressed)); + } - private void RemoveHotkeyCallback(string groupId, string? hotkeyId) - { - var group = GetGroup(groupId); - if (group == null) return; + if (_hotkeyWindow.Handle == IntPtr.Zero) + { + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + _serviceProvider.GetRequiredService().Invoke(() => + _hotkeyWindow.CreateWindow() + ); + tcs.Task.Wait(1000); + } + } - if (hotkeyId == null) + private void RemoveHotkeyCallback(string groupId, string? hotkeyId) { - foreach (var hc in group.Values) + var group = GetGroup(groupId); + if (group == null) return; + + if (hotkeyId == null) { + foreach (var hc in group.Values) + { + UnregisterHotkeyCallback(hc.RegisteredId); + } + group?.Clear(); + } + else + { + var hc = group.Where(x => x.Value.HotkeyId == hotkeyId).FirstOrDefault().Value; UnregisterHotkeyCallback(hc.RegisteredId); + group?.Remove(hotkeyId); } - group?.Clear(); } - else + + private IDictionary? GetGroup(string groupId) { - var hc = group.Where(x => x.Value.HotkeyId == hotkeyId).FirstOrDefault().Value; - UnregisterHotkeyCallback(hc.RegisteredId); - group?.Remove(hotkeyId); + return _groups.ContainsKey(groupId) ? _groups[groupId] : null; } - } - private IDictionary? GetGroup(string groupId) - { - return _groups.ContainsKey(groupId) ? _groups[groupId] : null; - } - - private IDictionary RequireGroup(string groupId) - { - if (!_groups.ContainsKey(groupId)) + private IDictionary RequireGroup(string groupId) { - _groups[groupId] = new Dictionary(); + if (!_groups.ContainsKey(groupId)) + { + _groups[groupId] = new Dictionary(); + } + return _groups[groupId]; } - return _groups[groupId]; - } - private void HandleHotkey(WORD id, int pressed) - { - lock (_groups) + private void HandleHotkey(WORD id, int pressed) { - var hcs = _groups.SelectMany(g => g.Value - .Where(x => x.Value.RegisteredId == id) - .Select(x => x.Value)).ToList(); - foreach (var hc in hcs) + lock (_groups) { - if (ShouldCallCallback(pressed, hc)) - { - hc.Callback(hc.GroupId, hc.HotkeyId, hc.Hotkey); - } - else if (ShouldSendKeys(pressed, hc)) + var hcs = _groups.SelectMany(g => g.Value + .Where(x => x.Value.RegisteredId == id) + .Select(x => x.Value)).ToList(); + foreach (var hc in hcs) { - _sendKeys.SendKeys(hc.Hotkey, 1); + if (ShouldCallCallback(pressed, hc)) + { + hc.Callback(hc.GroupId, hc.HotkeyId, hc.Hotkey); + } + else if (ShouldSendKeys(pressed, hc)) + { + _sendKeys.SendKeys(hc.Hotkey, 1); + } } } } - } - private bool ShouldCallCallback(int pressed, HotkeyCallback hc) - { - if (pressed == hc.FireOnPressCount) + private bool ShouldCallCallback(int pressed, HotkeyCallback hc) { - _deferSendKeysOnPressedEq0.Add(hc); - return true; + if (pressed == hc.FireOnPressCount) + { + _deferSendKeysOnPressedEq0.Add(hc); + return true; + } + return false; } - return false; - } - - private bool ShouldSendKeys(int pressed, HotkeyCallback hc) - { - return pressed == 0 && !_deferSendKeysOnPressedEq0.Remove(hc); - } - private List _deferSendKeysOnPressedEq0 = new(); + private bool ShouldSendKeys(int pressed, HotkeyCallback hc) + { + return pressed == 0 && !_deferSendKeysOnPressedEq0.Remove(hc); + } - private readonly IServiceProvider _serviceProvider; - private readonly ISendKeysService _sendKeys; + private List _deferSendKeysOnPressedEq0 = new(); - private Dictionary> _groups = new(); + private readonly IServiceProvider _serviceProvider; + private readonly ISendKeysService _sendKeys; - internal struct HotkeyCallback - { - internal WORD RegisteredId; - internal string GroupId; - internal string HotkeyId; - internal string Hotkey; - internal int FireOnPressCount; - internal Action Callback; - } + private Dictionary> _groups = new(); - internal class HotkeyWindow : NativeMessageWindow - { - public HotkeyWindow(Action callback) + internal struct HotkeyCallback { - _callback = callback; + internal WORD RegisteredId; + internal string GroupId; + internal string HotkeyId; + internal string Hotkey; + internal int FireOnPressCount; + internal Action Callback; } - public override void DestroyHandle() + internal class HotkeyWindow : NativeMessageWindow { - //macaroni_unregister_hotkey(Handle, input_interop.WM_HOTKEY, input_interop.VK_LWIN); - base.DestroyHandle(); - } + public HotkeyWindow(Action callback) + { + _callback = callback; + } - protected override void WndProc(ref Message m) - { - if (m.Msg == input_interop.WM_HOTKEY) + public override void DestroyHandle() { - _callback((WORD)m.WParam, m.LParam.ToInt32()); + //macaroni_unregister_hotkey(Handle, input_interop.WM_HOTKEY, input_interop.VK_LWIN); + base.DestroyHandle(); } - base.WndProc(ref m); - } + protected override void WndProc(ref Message m) + { + if (m.Msg == input_interop.WM_HOTKEY) + { + _callback((WORD)m.WParam, m.LParam.ToInt32()); + } - private readonly Action _callback; - } + base.WndProc(ref m); + } - private HotkeyWindow? _hotkeyWindow; + private readonly Action _callback; + } - private void RegisterHotkey(WORD id, uint vk, uint modifiers, bool extended) - { - if (_hotkeyWindow != null) + private HotkeyWindow? _hotkeyWindow; + + private void RegisterHotkey(WORD id, uint vk, uint modifiers, bool extended) { - macaroni_register_hotkey(_hotkeyWindow.Handle, input_interop.WM_HOTKEY, id, modifiers, vk, extended); + if (_hotkeyWindow != null) + { + macaroni_register_hotkey(_hotkeyWindow.Handle, input_interop.WM_HOTKEY, id, modifiers, vk, extended); + } } - } - private void UnregisterHotkeyCallback(WORD id) - { - if (_hotkeyWindow != null) + private void UnregisterHotkeyCallback(WORD id) { - macaroni_unregister_hotkey(_hotkeyWindow.Handle, input_interop.WM_HOTKEY, id); + if (_hotkeyWindow != null) + { + macaroni_unregister_hotkey(_hotkeyWindow.Handle, input_interop.WM_HOTKEY, id); + } } - } - [DllImport("macaroni_native.dll")] - public static extern bool macaroni_register_hotkey(IntPtr hwnd, DWORD msg, WORD id, DWORD fsModifiers, DWORD vk, bool fExtended); + [DllImport("macaroni_native.dll")] + public static extern bool macaroni_register_hotkey(IntPtr hwnd, DWORD msg, WORD id, DWORD fsModifiers, DWORD vk, bool fExtended); - [DllImport("macaroni_native.dll")] - public static extern bool macaroni_unregister_hotkey(IntPtr hwnd, DWORD msg, WORD id); -} + [DllImport("macaroni_native.dll")] + public static extern bool macaroni_unregister_hotkey(IntPtr hwnd, DWORD msg, WORD id); + } +} \ No newline at end of file diff --git a/src/win32_ui/PlatformServices/WindowsImage.cs b/src/win32_ui/PlatformServices/WindowsImage.cs index a218fe3e..68fcb526 100644 --- a/src/win32_ui/PlatformServices/WindowsImage.cs +++ b/src/win32_ui/PlatformServices/WindowsImage.cs @@ -1,36 +1,37 @@ using System.Drawing.Imaging; -namespace macaroni; - -public class WindowsImage : IImage +namespace macaroni { - public bool TryInit(object? platformImageOrStream) + public class WindowsImage : IImage { - var stream = platformImageOrStream as Stream; - var image = platformImageOrStream as Image; - if (stream != null) + public bool TryInit(object? platformImageOrStream) { - _image = Image.FromStream(stream); - return true; + var stream = platformImageOrStream as Stream; + var image = platformImageOrStream as Image; + if (stream != null) + { + _image = Image.FromStream(stream); + return true; + } + else if (image != null) + { + _image = image; + return true; + } + + return false; } - else if (image != null) + + public object? GetPlatformImage() { - _image = image; - return true; + return _image; } - return false; - } - - public object? GetPlatformImage() - { - return _image; - } + public void Save(string fileName) + { + _image?.Save(fileName, ImageFormat.Png); + } - public void Save(string fileName) - { - _image?.Save(fileName, ImageFormat.Png); + private Image? _image; } - - private Image? _image; -} +} \ No newline at end of file diff --git a/src/win32_ui/PlatformServices/WindowsMessageBoxService.cs b/src/win32_ui/PlatformServices/WindowsMessageBoxService.cs index b11b096b..16c0c0b2 100644 --- a/src/win32_ui/PlatformServices/WindowsMessageBoxService.cs +++ b/src/win32_ui/PlatformServices/WindowsMessageBoxService.cs @@ -1,87 +1,87 @@ -using Microsoft.VisualBasic.Devices; using System.Diagnostics; -namespace macaroni; - -internal class WindowsMessageBoxService : IMessageBoxService +namespace macaroni { - public WindowsMessageBoxService(IInvokeOnUiThread invoke, ISendKeysService sendKeys, IMouseService mouse) + internal class WindowsMessageBoxService : IMessageBoxService { - _invoke = invoke; - _sendKeys = sendKeys; - _mouse = mouse; - } + public WindowsMessageBoxService(IInvokeOnUiThread invoke, ISendKeysService sendKeys, IMouseService mouse) + { + _invoke = invoke; + _sendKeys = sendKeys; + _mouse = mouse; + } - public bool Show(string message, string? title, string? timeout) - { - var buttons = MessageBoxButtons.OK; - var icon = MessageBoxIcon.Warning; + public bool Show(string message, string? title, string? timeout) + { + var buttons = MessageBoxButtons.OK; + var icon = MessageBoxIcon.Warning; - DelayActivateThisApp(); + DelayActivateThisApp(); - var result = MessageBox.Show(message, title, buttons, icon); - return result == DialogResult.OK; - } + var result = MessageBox.Show(message, title, buttons, icon); + return result == DialogResult.OK; + } - public bool Confirm(string message, string? title, string? timeout) - { - var buttons = MessageBoxButtons.YesNo; - var icon = MessageBoxIcon.Question; + public bool Confirm(string message, string? title, string? timeout) + { + var buttons = MessageBoxButtons.YesNo; + var icon = MessageBoxIcon.Question; - DelayActivateThisApp(); + DelayActivateThisApp(); - var result = MessageBox.Show(message, title, buttons, icon); - return result == DialogResult.Yes; - } + var result = MessageBox.Show(message, title, buttons, icon); + return result == DialogResult.Yes; + } - public bool Prompt(string message, string? title, string? timeout, ref string text) - { - var dialog = new PromptDialog(); - dialog.Message = message; - dialog.Title = title; - dialog.Text = text; + public bool Prompt(string message, string? title, string? timeout, ref string text) + { + var dialog = new PromptDialog(); + dialog.Message = message; + dialog.Title = title; + dialog.Text = text; - DelayActivateThisApp(); + DelayActivateThisApp(); - var result = dialog.ShowDialog(); - var ok = result == DialogResult.OK; - if (ok) text = dialog.Text; - return ok; - } + var result = dialog.ShowDialog(); + var ok = result == DialogResult.OK; + if (ok) text = dialog.Text; + return ok; + } - public bool Pick(IEnumerable choices, string? message, string? title, string? timeout, ref string? choice) - { - var dialog = new ListBoxDialog(); - dialog.Choices = choices; - dialog.Choice = choice; - dialog.Message = message; - dialog.Title = title; - - DelayActivateThisApp(); - - var result = dialog.ShowDialog(); - var ok = result == DialogResult.OK; - if (ok) choice = dialog.Choice; - return ok; - } + public bool Pick(IEnumerable choices, string? message, string? title, string? timeout, ref string? choice) + { + var dialog = new ListBoxDialog(); + dialog.Choices = choices; + dialog.Choice = choice; + dialog.Message = message; + dialog.Title = title; - private void DelayActivateThisApp() - { - Task.Delay(100).ContinueWith(x => + DelayActivateThisApp(); + + var result = dialog.ShowDialog(); + var ok = result == DialogResult.OK; + if (ok) choice = dialog.Choice; + return ok; + } + + private void DelayActivateThisApp() { - var currentProcessId = Process.GetCurrentProcess().Id; - var checkWindows = WindowInfo.GetVisibleWindows().Where(x => x.Value.ProcessId == currentProcessId).ToList(); - WindowHelpers.SetForegroundWindow(checkWindows.FirstOrDefault().Key); - - Thread.Sleep(50); - _sendKeys?.SendKeys("{vk 0}", 1); - Thread.Sleep(50); - _mouse?.Move("0,0", "mouse"); - Thread.Sleep(50); - }); + Task.Delay(100).ContinueWith(x => + { + var currentProcessId = Process.GetCurrentProcess().Id; + var checkWindows = WindowInfo.GetVisibleWindows().Where(x => x.Value.ProcessId == currentProcessId).ToList(); + WindowHelpers.SetForegroundWindow(checkWindows.FirstOrDefault().Key); + + Thread.Sleep(50); + _sendKeys?.SendKeys("{vk 0}", 1); + Thread.Sleep(50); + _mouse?.Move("0,0", "mouse"); + Thread.Sleep(50); + }); + } + + private IInvokeOnUiThread _invoke; + private ISendKeysService _sendKeys; + private IMouseService _mouse; } - - private IInvokeOnUiThread _invoke; - private ISendKeysService _sendKeys; - private IMouseService _mouse; -} +} \ No newline at end of file diff --git a/src/win32_ui/PlatformServices/WindowsMouseService.cs b/src/win32_ui/PlatformServices/WindowsMouseService.cs index bbd9f47b..ff12e201 100644 --- a/src/win32_ui/PlatformServices/WindowsMouseService.cs +++ b/src/win32_ui/PlatformServices/WindowsMouseService.cs @@ -1,154 +1,152 @@ -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.DependencyInjection; -using System.Diagnostics; -using System.Runtime.InteropServices; +using System.Runtime.InteropServices; -namespace macaroni; - -internal class WindowsMouseService : IMouseService +namespace macaroni { - public void Move(string? position, string? relative) - { - ParsePosition(position, relative, out var x, out var y); - SetCursorPos(x, y); - } - - public void ClickButton(string? position, string? relative, string? button) - { - DoMouseUpDown(true, true, position, relative, button); - } - - public void PressButton(string? position, string? relative, string? button) + internal class WindowsMouseService : IMouseService { - DoMouseUpDown(true, false, position, relative, button); - } - - public void ReleaseButton(string? position, string? relative, string? button) - { - DoMouseUpDown(false, true, position, relative, button); - } - - public (int, int) GetPosition() - { - if (GetCursorPos(out var current)) + public void Move(string? position, string? relative) { - return (current.X, current.Y); + ParsePosition(position, relative, out var x, out var y); + SetCursorPos(x, y); } - return (0, 0); - } - private void DoMouseUpDown(bool down, bool up, string? position, string? relative, string? button) - { - ParsePosition(position, relative, out var x, out var y); - SetCursorPos(x, y); - - ParseButton(button, down, up, out var flags); - mouse_event(flags, (uint)x, (uint)y); - } - - private void ParsePosition(string? position, string? relative, out int x, out int y) - { - var parsed = false; - x = 0; - y = 0; + public void ClickButton(string? position, string? relative, string? button) + { + DoMouseUpDown(true, true, position, relative, button); + } - if (position != null) + public void PressButton(string? position, string? relative, string? button) { - parsed = ParsePoint(position, out x, out y); + DoMouseUpDown(true, false, position, relative, button); } - if (relative != null && relative.Contains(',')) + public void ReleaseButton(string? position, string? relative, string? button) { - if (ParsePoint(relative, out var x0, out var y0)) - { - x += x0; - y += y0; - } + DoMouseUpDown(false, true, position, relative, button); } - else if (!parsed || relative == "mouse") + + public (int, int) GetPosition() { if (GetCursorPos(out var current)) { - x += current.X; - y += current.Y; + return (current.X, current.Y); } + return (0, 0); } - else if (relative == "window") + + private void DoMouseUpDown(bool down, bool up, string? position, string? relative, string? button) { - var point = new POINT(); - point.X = x; - point.Y = y; - ClientToScreen(window_interop.GetForegroundWindow(), ref point); - x = point.X; - y = point.Y; - } - } + ParsePosition(position, relative, out var x, out var y); + SetCursorPos(x, y); - private bool ParsePoint(string position, out int x, out int y) - { - x = 0; y = 0; - var parts = position.Split(','); - return parts.Length == 2 && int.TryParse(parts[0], out x) && int.TryParse(parts[1], out y); - } + ParseButton(button, down, up, out var flags); + mouse_event(flags, (uint)x, (uint)y); + } - private void ParseButton(string? button, bool down, bool up, out uint flags) - { - flags = 0; - if (button == null || button == "left" || button == "1") + private void ParsePosition(string? position, string? relative, out int x, out int y) { - if (down) flags += MOUSEEVENTF_LEFTDOWN; - if (up) flags += MOUSEEVENTF_LEFTUP; + var parsed = false; + x = 0; + y = 0; + + if (position != null) + { + parsed = ParsePoint(position, out x, out y); + } + + if (relative != null && relative.Contains(',')) + { + if (ParsePoint(relative, out var x0, out var y0)) + { + x += x0; + y += y0; + } + } + else if (!parsed || relative == "mouse") + { + if (GetCursorPos(out var current)) + { + x += current.X; + y += current.Y; + } + } + else if (relative == "window") + { + var point = new POINT(); + point.X = x; + point.Y = y; + ClientToScreen(window_interop.GetForegroundWindow(), ref point); + x = point.X; + y = point.Y; + } } - else if (button == "right" || button == "2") + + private bool ParsePoint(string position, out int x, out int y) { - if (down) flags += MOUSEEVENTF_RIGHTDOWN; - if (up) flags += MOUSEEVENTF_RIGHTUP; + x = 0; y = 0; + var parts = position.Split(','); + return parts.Length == 2 && int.TryParse(parts[0], out x) && int.TryParse(parts[1], out y); } - else if (button == "middle" || button == "3") + + private void ParseButton(string? button, bool down, bool up, out uint flags) { - if (down) flags += MOUSEEVENTF_MIDDLEDOWN; - if (up) flags += MOUSEEVENTF_MIDDLEUP; + flags = 0; + if (button == null || button == "left" || button == "1") + { + if (down) flags += MOUSEEVENTF_LEFTDOWN; + if (up) flags += MOUSEEVENTF_LEFTUP; + } + else if (button == "right" || button == "2") + { + if (down) flags += MOUSEEVENTF_RIGHTDOWN; + if (up) flags += MOUSEEVENTF_RIGHTUP; + } + else if (button == "middle" || button == "3") + { + if (down) flags += MOUSEEVENTF_MIDDLEDOWN; + if (up) flags += MOUSEEVENTF_MIDDLEUP; + } + else if (button == "x1" || button == "4") + { + if (down) flags += MOUSEEVENTF_XDOWN; + if (up) flags += MOUSEEVENTF_XUP; + } } - else if (button == "x1" || button == "4") + + [StructLayout(LayoutKind.Sequential)] + struct POINT { - if (down) flags += MOUSEEVENTF_XDOWN; - if (up) flags += MOUSEEVENTF_XUP; + public Int32 X; + public Int32 Y; } - } - [StructLayout(LayoutKind.Sequential)] - struct POINT - { - public Int32 X; - public Int32 Y; + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + static extern bool GetCursorPos(out POINT point); + + [DllImport("user32.dll")] + static extern bool SetCursorPos(int x, int y); + + [DllImport("user32.dll")] + static extern bool ClientToScreen(IntPtr hWnd, ref POINT lpPoint); + + [DllImport("user32.dll")] + static extern bool ScreenToClient(IntPtr hWnd, ref POINT lpPoint); + + [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] + public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData = 0, uint dwExtraInfo = 0); + + private const uint MOUSEEVENTF_ABSOLUTE = 0x8000; + private const uint MOUSEEVENTF_LEFTDOWN = 0x0002; + private const uint MOUSEEVENTF_LEFTUP = 0x0004; + private const uint MOUSEEVENTF_MIDDLEDOWN = 0x0020; + private const uint MOUSEEVENTF_MIDDLEUP = 0x0040; + private const uint MOUSEEVENTF_MOVE = 0x0001; + private const uint MOUSEEVENTF_RIGHTDOWN = 0x0008; + private const uint MOUSEEVENTF_RIGHTUP = 0x0010; + private const uint MOUSEEVENTF_XDOWN = 0x0080; + private const uint MOUSEEVENTF_XUP = 0x0100; + private const uint MOUSEEVENTF_WHEEL = 0x0800; + private const uint MOUSEEVENTF_HWHEEL = 0x01000; } - - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - static extern bool GetCursorPos(out POINT point); - - [DllImport("user32.dll")] - static extern bool SetCursorPos(int x, int y); - - [DllImport("user32.dll")] - static extern bool ClientToScreen(IntPtr hWnd, ref POINT lpPoint); - - [DllImport("user32.dll")] - static extern bool ScreenToClient(IntPtr hWnd, ref POINT lpPoint); - - [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] - public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData = 0, uint dwExtraInfo = 0); - - private const uint MOUSEEVENTF_ABSOLUTE = 0x8000; - private const uint MOUSEEVENTF_LEFTDOWN = 0x0002; - private const uint MOUSEEVENTF_LEFTUP = 0x0004; - private const uint MOUSEEVENTF_MIDDLEDOWN = 0x0020; - private const uint MOUSEEVENTF_MIDDLEUP = 0x0040; - private const uint MOUSEEVENTF_MOVE = 0x0001; - private const uint MOUSEEVENTF_RIGHTDOWN = 0x0008; - private const uint MOUSEEVENTF_RIGHTUP = 0x0010; - private const uint MOUSEEVENTF_XDOWN = 0x0080; - private const uint MOUSEEVENTF_XUP = 0x0100; - private const uint MOUSEEVENTF_WHEEL = 0x0800; - private const uint MOUSEEVENTF_HWHEEL = 0x01000; -} +} \ No newline at end of file diff --git a/src/win32_ui/PlatformServices/WindowsOnScreenDisplayService.cs b/src/win32_ui/PlatformServices/WindowsOnScreenDisplayService.cs index 077fad06..0f84f834 100644 --- a/src/win32_ui/PlatformServices/WindowsOnScreenDisplayService.cs +++ b/src/win32_ui/PlatformServices/WindowsOnScreenDisplayService.cs @@ -1,59 +1,60 @@ -namespace macaroni; - -internal class WindowsOnScreenDisplayService : IOnScreenDisplayService +namespace macaroni { - public WindowsOnScreenDisplayService(IServiceProvider serviceProvider, IInvokeOnUiThread invoke, ICommandSystemSettings settings) + internal class WindowsOnScreenDisplayService : IOnScreenDisplayService { - _serviceProvider = serviceProvider; - _invoke = invoke; - _settings = settings; - } + public WindowsOnScreenDisplayService(IServiceProvider serviceProvider, IInvokeOnUiThread invoke, ICommandSystemSettings settings) + { + _serviceProvider = serviceProvider; + _invoke = invoke; + _settings = settings; + } - public void DisplayText(string text, string from, bool? pending, int timeout) - { - UpdateText(text, from, pending, timeout); - } + public void DisplayText(string text, string from, bool? pending, int timeout) + { + UpdateText(text, from, pending, timeout); + } - public void DisplayTips(IEnumerable? tips, Func?>? moreTips) - { - _invoke.Invoke(() => + public void DisplayTips(IEnumerable? tips, Func?>? moreTips) { - if (_ostips == null || !_ostips.Visible) + _invoke.Invoke(() => { - _ostips = new AlphaTips(_serviceProvider, tips, moreTips); - _ostips.Show(); - } - }); - } + if (_ostips == null || !_ostips.Visible) + { + _ostips = new AlphaTips(_serviceProvider, tips, moreTips); + _ostips.Show(); + } + }); + } - private void UpdateText(string text, string from, bool? pending, int timeInMs) - { - _invoke.Invoke(() => + private void UpdateText(string text, string from, bool? pending, int timeInMs) { - if (!_cdShownAtLeastOnce) + _invoke.Invoke(() => { - _cdShownAtLeastOnce = true; - var cd = new ConversationDialog(_serviceProvider); - cd.Show(); - } + if (!_cdShownAtLeastOnce) + { + _cdShownAtLeastOnce = true; + var cd = new ConversationDialog(_serviceProvider); + cd.Show(); + } - if (!ConversationDialog.DisplayText(text, from, pending, timeInMs)) - { - if (_osd == null || !_osd.Visible) + if (!ConversationDialog.DisplayText(text, from, pending, timeInMs)) { - _osd = new AlphaTextStatusOSD(); - _osd.Show(); + if (_osd == null || !_osd.Visible) + { + _osd = new AlphaTextStatusOSD(); + _osd.Show(); + } + _osd?.SetText(text, timeInMs); } - _osd?.SetText(text, timeInMs); - } - }); - } + }); + } - private bool _cdShownAtLeastOnce = false; - private AlphaTextStatusOSD? _osd; - private AlphaTips? _ostips; - - private readonly IInvokeOnUiThread _invoke; - private readonly IServiceProvider _serviceProvider; - private readonly ICommandSystemSettings _settings; -} + private bool _cdShownAtLeastOnce = false; + private AlphaTextStatusOSD? _osd; + private AlphaTips? _ostips; + + private readonly IInvokeOnUiThread _invoke; + private readonly IServiceProvider _serviceProvider; + private readonly ICommandSystemSettings _settings; + } +} \ No newline at end of file diff --git a/src/win32_ui/PlatformServices/WindowsPlayMediaService.cs b/src/win32_ui/PlatformServices/WindowsPlayMediaService.cs index 6ce8e44c..d7bfea51 100644 --- a/src/win32_ui/PlatformServices/WindowsPlayMediaService.cs +++ b/src/win32_ui/PlatformServices/WindowsPlayMediaService.cs @@ -1,156 +1,158 @@ -namespace macaroni; - -using System; -using System.Text; -using System.Runtime.InteropServices; - -internal class WindowsPlayMediaService : IPlayMediaService +namespace macaroni { - public WindowsPlayMediaService(IInvokeOnUiThread invoke) - { - _invoke = invoke; - _invoke.Invoke(() => { - _notify = new MciNotifyWindow((wp, lp) => OnNotify(wp, lp)); - _notify.CreateWindow(); - }); - } + using System; + using System.Runtime.InteropServices; + using System.Text; - public void Beep() + internal class WindowsPlayMediaService : IPlayMediaService { - Console.Beep(); - } + public WindowsPlayMediaService(IInvokeOnUiThread invoke) + { + _invoke = invoke; + _invoke.Invoke(() => + { + _notify = new MciNotifyWindow((wp, lp) => OnNotify(wp, lp)); + _notify.CreateWindow(); + }); + } - public void Beep(int frequency, int duration) - { - Console.Beep(frequency, duration); - } + public void Beep() + { + Console.Beep(); + } - public void Play(string file, int pos = 0) - { - _invoke.Invoke(() => + public void Beep(int frequency, int duration) { - MciOpen(file); - MciPlay(pos); - }); - } + Console.Beep(frequency, duration); + } - public void Pause() - { - _invoke.Invoke(() => MciPause()); - } + public void Play(string file, int pos = 0) + { + _invoke.Invoke(() => + { + MciOpen(file); + MciPlay(pos); + }); + } - public void Resume() - { - _invoke.Invoke(() => MciResume()); - } + public void Pause() + { + _invoke.Invoke(() => MciPause()); + } - public void Stop() - { - _invoke.Invoke(() => + public void Resume() { - MciStop(); - MciClose(); - }); - } + _invoke.Invoke(() => MciResume()); + } - private void MciOpen(string file) - { - MciClose(); + public void Stop() + { + _invoke.Invoke(() => + { + MciStop(); + MciClose(); + }); + } + + private void MciOpen(string file) + { + MciClose(); - var open = "open \"" + file + "\" alias " + _alias; - mciSendString(open, null, 0, IntPtr.Zero); + var open = "open \"" + file + "\" alias " + _alias; + mciSendString(open, null, 0, IntPtr.Zero); - string format = $"set {_alias} time format milliseconds"; - mciSendString(format, null, 0, IntPtr.Zero); + string format = $"set {_alias} time format milliseconds"; + mciSendString(format, null, 0, IntPtr.Zero); - _opened = true; - } + _opened = true; + } - private void MciClose() - { - if (_opened) + private void MciClose() { - var close = "close " + _alias; - mciSendString(close, null, 0, IntPtr.Zero); - _opened = false; + if (_opened) + { + var close = "close " + _alias; + mciSendString(close, null, 0, IntPtr.Zero); + _opened = false; + } } - } - private void MciPlay(int pos = 0) - { - if (_opened) + private void MciPlay(int pos = 0) { - string play = pos == 0 - ? $"play {_alias} notify" - : $"play {_alias} from {pos} notify"; - mciSendString(play, null, 0, _notify?.Handle ?? IntPtr.Zero); + if (_opened) + { + string play = pos == 0 + ? $"play {_alias} notify" + : $"play {_alias} from {pos} notify"; + mciSendString(play, null, 0, _notify?.Handle ?? IntPtr.Zero); + } } - } - private void MciPause() - { - if (_opened) + private void MciPause() { - string pause = $"pause {_alias}"; - mciSendString(pause, null, 0, IntPtr.Zero); + if (_opened) + { + string pause = $"pause {_alias}"; + mciSendString(pause, null, 0, IntPtr.Zero); + } } - } - private void MciResume() - { - if (_opened) + private void MciResume() { - string resume = $"resume {_alias}"; - mciSendString(resume, null, 0, IntPtr.Zero); + if (_opened) + { + string resume = $"resume {_alias}"; + mciSendString(resume, null, 0, IntPtr.Zero); + } } - } - private void MciStop() - { - if (_opened) + private void MciStop() { - var stop = "stop " + _alias; - mciSendString(stop, null, 0, IntPtr.Zero); + if (_opened) + { + var stop = "stop " + _alias; + mciSendString(stop, null, 0, IntPtr.Zero); + } } - } - - private void OnNotify(IntPtr wp, IntPtr lp) - { - // TODO: ... - } - class MciNotifyWindow : NativeMessageWindow - { - public MciNotifyWindow(Action notify) + private void OnNotify(IntPtr wp, IntPtr lp) { - _notify = notify; + // TODO: ... } - protected override void WndProc(ref Message m) + class MciNotifyWindow : NativeMessageWindow { - if (m.Msg == MM_MCINOTIFY) + public MciNotifyWindow(Action notify) { - _notify(m.WParam, m.LParam); + _notify = notify; } - base.WndProc(ref m); - } + protected override void WndProc(ref Message m) + { + if (m.Msg == MM_MCINOTIFY) + { + _notify(m.WParam, m.LParam); + } + + base.WndProc(ref m); + } - private Action _notify; - }; + private Action _notify; + }; - private const string _alias = "media"; - private bool _opened = false; + private const string _alias = "media"; + private bool _opened = false; - private IInvokeOnUiThread _invoke; - private MciNotifyWindow? _notify; + private IInvokeOnUiThread _invoke; + private MciNotifyWindow? _notify; - public const int MM_MCINOTIFY = 0x3B9; + public const int MM_MCINOTIFY = 0x3B9; - [DllImport("winmm.dll")] - private static extern long mciSendString( - string command, - StringBuilder? returnValue, - int returnLength, - IntPtr winHandle); -} + [DllImport("winmm.dll")] + private static extern long mciSendString( + string command, + StringBuilder? returnValue, + int returnLength, + IntPtr winHandle); + } +} \ No newline at end of file diff --git a/src/win32_ui/PlatformServices/WindowsPositionContextResolver.cs b/src/win32_ui/PlatformServices/WindowsPositionContextResolver.cs index f8b109e2..35bae3ef 100644 --- a/src/win32_ui/PlatformServices/WindowsPositionContextResolver.cs +++ b/src/win32_ui/PlatformServices/WindowsPositionContextResolver.cs @@ -1,60 +1,61 @@ using Microsoft.Extensions.DependencyInjection; using System.Runtime.InteropServices; -namespace macaroni; - -internal class WindowsPositionContextResolver : ISystemContextResolver +namespace macaroni { - public WindowsPositionContextResolver(IServiceProvider serviceProvider) + internal class WindowsPositionContextResolver : ISystemContextResolver { - _serviceProvider = serviceProvider; - } + public WindowsPositionContextResolver(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } - public object? Get(string key, object? defaultValue) - { - return key switch + public object? Get(string key, object? defaultValue) { - "window.position" => GetCurrentWindowPosition() ?? defaultValue, - "mouse.position" => GetCurrentMousePosition() ?? defaultValue, - _ => defaultValue - }; - } + return key switch + { + "window.position" => GetCurrentWindowPosition() ?? defaultValue, + "mouse.position" => GetCurrentMousePosition() ?? defaultValue, + _ => defaultValue + }; + } + + private string? GetCurrentWindowPosition() + { + GetWindowPosition(out var x, out var y); + return $"{x},{y}"; + } - private string? GetCurrentWindowPosition() - { - GetWindowPosition(out var x, out var y); - return $"{x},{y}"; - } + private string? GetCurrentMousePosition() + { + GetMousePosition(out var x, out var y); + return $"{x},{y}"; + } - private string? GetCurrentMousePosition() - { - GetMousePosition(out var x, out var y); - return $"{x},{y}"; - } + private void GetMousePosition(out int x, out int y) + { + var mouse = _serviceProvider.GetRequiredService(); + (x, y) = mouse.GetPosition(); + } - private void GetMousePosition(out int x, out int y) - { - var mouse = _serviceProvider.GetRequiredService(); - (x, y) = mouse.GetPosition(); - } + private void GetWindowPosition(out int x, out int y) + { + var point = new POINT() { X = 0, Y = 0 }; + ClientToScreen(window_interop.GetForegroundWindow(), ref point); + x = point.X; + y = point.Y; + } - private void GetWindowPosition(out int x, out int y) - { - var point = new POINT() { X = 0, Y = 0}; - ClientToScreen(window_interop.GetForegroundWindow(), ref point); - x = point.X; - y = point.Y; - } + private readonly IServiceProvider _serviceProvider; - private readonly IServiceProvider _serviceProvider; + [StructLayout(LayoutKind.Sequential)] + struct POINT + { + public Int32 X; + public Int32 Y; + } - [StructLayout(LayoutKind.Sequential)] - struct POINT - { - public Int32 X; - public Int32 Y; + [DllImport("user32.dll")] + static extern bool ClientToScreen(IntPtr hWnd, ref POINT lpPoint); } - - [DllImport("user32.dll")] - static extern bool ClientToScreen(IntPtr hWnd, ref POINT lpPoint); -} +} \ No newline at end of file diff --git a/src/win32_ui/PlatformServices/WindowsProtectedSecretSettingsCache.cs b/src/win32_ui/PlatformServices/WindowsProtectedSecretSettingsCache.cs index a28acd83..15bca8fa 100644 --- a/src/win32_ui/PlatformServices/WindowsProtectedSecretSettingsCache.cs +++ b/src/win32_ui/PlatformServices/WindowsProtectedSecretSettingsCache.cs @@ -1,106 +1,107 @@ using System.Security.Cryptography; using System.Text; -namespace macaroni; - -internal class WindowsProtectedSecretSettingsCache : IProtectedSecretSettingsCache +namespace macaroni { - public bool TryGet(string name, out string? value) - { - return TryGetFromMemory(name, out value) || TryGetFromDisk(name, out value); - } - - public void Set(string name, string? value) + internal class WindowsProtectedSecretSettingsCache : IProtectedSecretSettingsCache { - CacheInMemory(name, value); - CacheOnDisk(name, value); - } + public bool TryGet(string name, out string? value) + { + return TryGetFromMemory(name, out value) || TryGetFromDisk(name, out value); + } - private void CacheInMemory(string name, string? value) - { - _memoryCache.Set(name, value); - } + public void Set(string name, string? value) + { + CacheInMemory(name, value); + CacheOnDisk(name, value); + } - private bool TryGetFromMemory(string name, out string? value) - { - return _memoryCache.TryGet(name, out value); - } + private void CacheInMemory(string name, string? value) + { + _memoryCache.Set(name, value); + } - private static void CacheOnDisk(string name, string? value) - { - var file = GetFileName(name); - if (value == null && File.Exists(file)) + private bool TryGetFromMemory(string name, out string? value) { - File.Delete(file); + return _memoryCache.TryGet(name, out value); } - else if (value != null) + + private static void CacheOnDisk(string name, string? value) { - var data = ProtectData(Encoding.UTF8.GetBytes(value)); - if (data != null) + var file = GetFileName(name); + if (value == null && File.Exists(file)) { - MR.DBG_TRACE_INFO($"PROTECTED SET: {name}={value}"); - File.WriteAllBytes(file, data); + File.Delete(file); + } + else if (value != null) + { + var data = ProtectData(Encoding.UTF8.GetBytes(value)); + if (data != null) + { + MR.DBG_TRACE_INFO($"PROTECTED SET: {name}={value}"); + File.WriteAllBytes(file, data); + } } } - } - private static bool TryGetFromDisk(string name, out string? value) - { - var file = GetFileName(name); - if (File.Exists(file)) + private static bool TryGetFromDisk(string name, out string? value) { - var data = UnprotectData(File.ReadAllBytes(file)); - if (data != null) + var file = GetFileName(name); + if (File.Exists(file)) { - value = Encoding.UTF8.GetString(data); - MR.DBG_TRACE_INFO($"PROTECTED GET: {name}={value}"); - return true; + var data = UnprotectData(File.ReadAllBytes(file)); + if (data != null) + { + value = Encoding.UTF8.GetString(data); + MR.DBG_TRACE_INFO($"PROTECTED GET: {name}={value}"); + return true; + } } - } - value = null; - return false; - } - - private static string GetFileName(string name) - { - var path1 = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "macaroni"); - var path2 = Path.Combine(path1, "protected"); + value = null; + return false; + } - Directory.CreateDirectory(path1); - Directory.CreateDirectory(path2); + private static string GetFileName(string name) + { + var path1 = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "macaroni"); + var path2 = Path.Combine(path1, "protected"); - return Path.Combine(path2, name); - } + Directory.CreateDirectory(path1); + Directory.CreateDirectory(path2); - private static byte[]? ProtectData(byte[] data) - { - try - { - // Encrypt the data using DataProtectionScope.CurrentUser. The result can be decrypted - // only by the same current user. - return ProtectedData.Protect(data, null, DataProtectionScope.CurrentUser); - } - catch (CryptographicException ex) - { - MR.DBG_TRACE_ERROR($"CRYPTOGRAPHIC EXCEPTION: {ex}"); - return null; + return Path.Combine(path2, name); } - } - private static byte[]? UnprotectData(byte [] data) - { - try + private static byte[]? ProtectData(byte[] data) { - //Decrypt the data using DataProtectionScope.CurrentUser. - return ProtectedData.Unprotect(data, null, DataProtectionScope.CurrentUser); + try + { + // Encrypt the data using DataProtectionScope.CurrentUser. The result can be decrypted + // only by the same current user. + return ProtectedData.Protect(data, null, DataProtectionScope.CurrentUser); + } + catch (CryptographicException ex) + { + MR.DBG_TRACE_ERROR($"CRYPTOGRAPHIC EXCEPTION: {ex}"); + return null; + } } - catch (CryptographicException ex) + + private static byte[]? UnprotectData(byte[] data) { - MR.DBG_TRACE_ERROR($"CRYPTOGRAPHIC EXCEPTION: {ex}"); - return null; + try + { + //Decrypt the data using DataProtectionScope.CurrentUser. + return ProtectedData.Unprotect(data, null, DataProtectionScope.CurrentUser); + } + catch (CryptographicException ex) + { + MR.DBG_TRACE_ERROR($"CRYPTOGRAPHIC EXCEPTION: {ex}"); + return null; + } } - } - private ProtectedSettingsMemoryCache _memoryCache = new(); -} + private ProtectedSettingsMemoryCache _memoryCache = new(); + } +} \ No newline at end of file diff --git a/src/win32_ui/PlatformServices/WindowsScreenCaptureService.cs b/src/win32_ui/PlatformServices/WindowsScreenCaptureService.cs index 53c80ebc..fc5aa9bd 100644 --- a/src/win32_ui/PlatformServices/WindowsScreenCaptureService.cs +++ b/src/win32_ui/PlatformServices/WindowsScreenCaptureService.cs @@ -1,102 +1,102 @@ using Microsoft.Extensions.DependencyInjection; using System.Drawing.Imaging; -using System.Text; -namespace macaroni; - -internal class WindowsScreenCaptureService : IScreenCaptureService +namespace macaroni { - public WindowsScreenCaptureService(IServiceProvider serviceProvider, IImageAnalysisService analyzeImage) - { - _serviceProvider = serviceProvider; - _analyzeImage = analyzeImage; - } - - public string? GetScreenText() + internal class WindowsScreenCaptureService : IScreenCaptureService { - var image = GetScreenImage(); - if (image != null) + public WindowsScreenCaptureService(IServiceProvider serviceProvider, IImageAnalysisService analyzeImage) { - return TextFromImage(image); + _serviceProvider = serviceProvider; + _analyzeImage = analyzeImage; } - return null; - } - public string? GetWindowText() - { - var image = GetWindowImage(); - if (image != null) + public string? GetScreenText() { - return TextFromImage(image); + var image = GetScreenImage(); + if (image != null) + { + return TextFromImage(image); + } + return null; } - return null; - } - public string? GetFocusText() - { - var image = GetFocusImage(); - if (image != null) + public string? GetWindowText() { - return TextFromImage(image); + var image = GetWindowImage(); + if (image != null) + { + return TextFromImage(image); + } + return null; } - return null; - } - - public IImage? GetScreenImage() - { - var bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb); - var rect = Screen.AllScreens[0].Bounds; - - var g = Graphics.FromImage(bitmap); - g.CopyFromScreen(rect.Left, rect.Top, 0, 0, rect.Size); - var instance = new WindowsImage(); - return instance.TryInit(bitmap) ? instance : null; - } + public string? GetFocusText() + { + var image = GetFocusImage(); + if (image != null) + { + return TextFromImage(image); + } + return null; + } - public IImage? GetWindowImage() - { - var uia = _serviceProvider.GetService(); - if (uia != null && uia.GetWindowPosition(out var rect)) + public IImage? GetScreenImage() { - var bitmap = new Bitmap(rect.Width, rect.Height, PixelFormat.Format32bppArgb); + var bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb); + var rect = Screen.AllScreens[0].Bounds; var g = Graphics.FromImage(bitmap); - g.CopyFromScreen(rect.Left, rect.Top, 0, 0, new System.Drawing.Size(rect.Width, rect.Height)); + g.CopyFromScreen(rect.Left, rect.Top, 0, 0, rect.Size); var instance = new WindowsImage(); return instance.TryInit(bitmap) ? instance : null; } - return null; - } - public IImage? GetFocusImage() - { - var uia = _serviceProvider.GetService(); - if (uia != null && uia.GetFocusPosition(out var rect)) + public IImage? GetWindowImage() { - var bitmap = new Bitmap(rect.Width, rect.Height, PixelFormat.Format32bppArgb); - - var g = Graphics.FromImage(bitmap); - g.CopyFromScreen(rect.Left, rect.Top, 0, 0, new System.Drawing.Size(rect.Width, rect.Height)); + var uia = _serviceProvider.GetService(); + if (uia != null && uia.GetWindowPosition(out var rect)) + { + var bitmap = new Bitmap(rect.Width, rect.Height, PixelFormat.Format32bppArgb); + + var g = Graphics.FromImage(bitmap); + g.CopyFromScreen(rect.Left, rect.Top, 0, 0, new System.Drawing.Size(rect.Width, rect.Height)); + + var instance = new WindowsImage(); + return instance.TryInit(bitmap) ? instance : null; + } + return null; + } - var instance = new WindowsImage(); - return instance.TryInit(bitmap) ? instance : null; + public IImage? GetFocusImage() + { + var uia = _serviceProvider.GetService(); + if (uia != null && uia.GetFocusPosition(out var rect)) + { + var bitmap = new Bitmap(rect.Width, rect.Height, PixelFormat.Format32bppArgb); + + var g = Graphics.FromImage(bitmap); + g.CopyFromScreen(rect.Left, rect.Top, 0, 0, new System.Drawing.Size(rect.Width, rect.Height)); + + var instance = new WindowsImage(); + return instance.TryInit(bitmap) ? instance : null; + } + return null; } - return null; - } - private string TextFromImage(IImage? image) - { - var tempFile = Path.GetTempFileName() + ".png"; - image?.Save(tempFile); + private string TextFromImage(IImage? image) + { + var tempFile = Path.GetTempFileName() + ".png"; + image?.Save(tempFile); - var task = _analyzeImage.Analyze(tempFile, null, null); - task.Wait(); + var task = _analyzeImage.Analyze(tempFile, null, null); + task.Wait(); - return task.Result.AsMonospaceTable(); - } + return task.Result.AsMonospaceTable(); + } - private IServiceProvider _serviceProvider; - private IImageAnalysisService _analyzeImage; -} + private IServiceProvider _serviceProvider; + private IImageAnalysisService _analyzeImage; + } +} \ No newline at end of file diff --git a/src/win32_ui/PlatformServices/WindowsSendKeysService.cs b/src/win32_ui/PlatformServices/WindowsSendKeysService.cs index cf719a39..7041430f 100644 --- a/src/win32_ui/PlatformServices/WindowsSendKeysService.cs +++ b/src/win32_ui/PlatformServices/WindowsSendKeysService.cs @@ -1,22 +1,21 @@ -using System.Diagnostics; - -namespace macaroni; - -internal class WindowsSendKeysService : ISendKeysService +namespace macaroni { - public void SendKeys(string keys, int times) + internal class WindowsSendKeysService : ISendKeysService { - var list = SmartKey.List.FromKeys(keys); - while (times > 0) + public void SendKeys(string keys, int times) { - list.SendKeys(); - times--; + var list = SmartKey.List.FromKeys(keys); + while (times > 0) + { + list.SendKeys(); + times--; + } } - } - public void InsertText(string text) - { - var list = SmartKey.List.FromText(text); - list.SendKeys(); + public void InsertText(string text) + { + var list = SmartKey.List.FromText(text); + list.SendKeys(); + } } -} +} \ No newline at end of file diff --git a/src/win32_ui/PlatformServices/WindowsUIAutomationServiceHost.cs b/src/win32_ui/PlatformServices/WindowsUIAutomationServiceHost.cs index fcffc18d..79ef17d8 100644 --- a/src/win32_ui/PlatformServices/WindowsUIAutomationServiceHost.cs +++ b/src/win32_ui/PlatformServices/WindowsUIAutomationServiceHost.cs @@ -1,21 +1,17 @@ -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.DependencyInjection; -using System.Diagnostics; +//using Windows.Win32.UI.Accessibility; -using UIAutomationClient; -//using Windows.Win32.UI.Accessibility; - -namespace macaroni; - -internal class WindowsUIAutomationServiceHost : StartStopHelperBackgroundService +namespace macaroni { - public WindowsUIAutomationServiceHost(IServiceProvider services, IUiAutomationService automation) : base(services) + internal class WindowsUIAutomationServiceHost : StartStopHelperBackgroundService { - _automation = automation; - } + public WindowsUIAutomationServiceHost(IServiceProvider services, IUiAutomationService automation) : base(services) + { + _automation = automation; + } - override protected Task StartAsync() => _automation.StartAsync(); - override protected Task StopAsync() => _automation.StopAsync(); + override protected Task StartAsync() => _automation.StartAsync(); + override protected Task StopAsync() => _automation.StopAsync(); - private readonly IUiAutomationService _automation; -} + private readonly IUiAutomationService _automation; + } +} \ No newline at end of file diff --git a/src/win32_ui/PlatformServices/WindowsUiAutomationService.cs b/src/win32_ui/PlatformServices/WindowsUiAutomationService.cs index 3767b9a9..a6b6cc49 100644 --- a/src/win32_ui/PlatformServices/WindowsUiAutomationService.cs +++ b/src/win32_ui/PlatformServices/WindowsUiAutomationService.cs @@ -1,470 +1,469 @@ -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.DependencyInjection; -using System.Diagnostics; +using System.Diagnostics; using UIAutomationClient; -namespace macaroni; - -internal class WindowsUiAutomationService : IUiAutomationService +namespace macaroni { - public WindowsUiAutomationService() + internal class WindowsUiAutomationService : IUiAutomationService { - } + public WindowsUiAutomationService() + { + } - public Task StartAsync() - { - InitThread(); - return Task.CompletedTask; - } + public Task StartAsync() + { + InitThread(); + return Task.CompletedTask; + } - public Task StopAsync() - { - TermThread(); - return Task.CompletedTask; - } + public Task StopAsync() + { + TermThread(); + return Task.CompletedTask; + } - public bool GetPosition(string element, out PAL.Rectangle rect) - { - var stopWatch = StartStopWatch(); - do + public bool GetPosition(string element, out PAL.Rectangle rect) { - TraceRetryStart(stopWatch); - DemandRefreshSoon(); + var stopWatch = StartStopWatch(); + do + { + TraceRetryStart(stopWatch); + DemandRefreshSoon(); + + if (TryGetPosition(element, out rect)) + { + return TraceRetryFoundIt(stopWatch); + } + } + while (WaitForNewGeneration(stopWatch)); if (TryGetPosition(element, out rect)) { return TraceRetryFoundIt(stopWatch); } + + return TraceRetryNotFound(stopWatch); } - while (WaitForNewGeneration(stopWatch)); - if (TryGetPosition(element, out rect)) + private static Stopwatch StartStopWatch() { - return TraceRetryFoundIt(stopWatch); + var stopWatch = new Stopwatch(); + stopWatch.Start(); + return stopWatch; } - return TraceRetryNotFound(stopWatch); - } - - private static Stopwatch StartStopWatch() - { - var stopWatch = new Stopwatch(); - stopWatch.Start(); - return stopWatch; - } - - private void TraceRetryStart(Stopwatch stopWatch) - { - if (_verbose) MR.DBG_TRACE_VERBOSE($"UIA Retry: {stopWatch.ElapsedMilliseconds} (gen={_generation}..."); - } - - private bool TraceRetryFoundIt(Stopwatch stopWatch) - { - if (_verbose) MR.DBG_TRACE_VERBOSE($"UIA Retry: {stopWatch.ElapsedMilliseconds} (gen={_generation})... found!"); - return true; - } - - private bool TraceRetryNotFound(Stopwatch stopWatch) - { - if (_verbose) MR.DBG_TRACE_VERBOSE($"UIA Retry: {stopWatch.ElapsedMilliseconds} (gen={_generation}... NOT FOUND!"); - return false; - } + private void TraceRetryStart(Stopwatch stopWatch) + { + if (_verbose) MR.DBG_TRACE_VERBOSE($"UIA Retry: {stopWatch.ElapsedMilliseconds} (gen={_generation}..."); + } - private bool WaitForNewGeneration(Stopwatch stopWatch) - { - var generation = _generation; - while (_generation == generation && stopWatch.ElapsedMilliseconds < _maxWaitForGenerationChange) + private bool TraceRetryFoundIt(Stopwatch stopWatch) { - if (_verbose) MR.DBG_TRACE_VERBOSE($"UIA Retry: sleeping..."); - Thread.Sleep(10); - if (_verbose) MR.DBG_TRACE_VERBOSE($"UIA Retry: sleeping... Done!"); + if (_verbose) MR.DBG_TRACE_VERBOSE($"UIA Retry: {stopWatch.ElapsedMilliseconds} (gen={_generation})... found!"); + return true; } - return _generation != generation && stopWatch.ElapsedMilliseconds < _maxWaitForGenerationChange; - } + private bool TraceRetryNotFound(Stopwatch stopWatch) + { + if (_verbose) MR.DBG_TRACE_VERBOSE($"UIA Retry: {stopWatch.ElapsedMilliseconds} (gen={_generation}... NOT FOUND!"); + return false; + } - public bool GetWindowPosition(out PAL.Rectangle rect) - { - var stopWatch = StartStopWatch(); - do + private bool WaitForNewGeneration(Stopwatch stopWatch) { - TraceRetryStart(stopWatch); - DemandRefreshSoon(); - if (_topRect != null) + var generation = _generation; + while (_generation == generation && stopWatch.ElapsedMilliseconds < _maxWaitForGenerationChange) { - var bounds = _topRect.Value; - rect = new PAL.Rectangle(bounds.left, bounds.top, bounds.right - bounds.left + 1, bounds.bottom - bounds.top + 1); - return TraceRetryFoundIt(stopWatch); + if (_verbose) MR.DBG_TRACE_VERBOSE($"UIA Retry: sleeping..."); + Thread.Sleep(10); + if (_verbose) MR.DBG_TRACE_VERBOSE($"UIA Retry: sleeping... Done!"); } - } - while (WaitForNewGeneration(stopWatch)); - rect = new PAL.Rectangle(); - return TraceRetryNotFound(stopWatch); - } + return _generation != generation && stopWatch.ElapsedMilliseconds < _maxWaitForGenerationChange; + } - public bool GetFocusPosition(out PAL.Rectangle rect) - { - var stopWatch = StartStopWatch(); - do + public bool GetWindowPosition(out PAL.Rectangle rect) { - TraceRetryStart(stopWatch); - if (_focusRect != null) + var stopWatch = StartStopWatch(); + do { - var bounds = _focusRect.Value; - rect = new PAL.Rectangle(bounds.left, bounds.top, bounds.right - bounds.left + 1, bounds.bottom - bounds.top + 1); - return TraceRetryFoundIt(stopWatch); + TraceRetryStart(stopWatch); + DemandRefreshSoon(); + if (_topRect != null) + { + var bounds = _topRect.Value; + rect = new PAL.Rectangle(bounds.left, bounds.top, bounds.right - bounds.left + 1, bounds.bottom - bounds.top + 1); + return TraceRetryFoundIt(stopWatch); + } } - } - while (WaitForNewGeneration(stopWatch)); + while (WaitForNewGeneration(stopWatch)); - rect = new PAL.Rectangle(); - return TraceRetryNotFound(stopWatch); - } + rect = new PAL.Rectangle(); + return TraceRetryNotFound(stopWatch); + } - private bool TryGetPosition(string element, out PAL.Rectangle rect) - { - var items = _allFoundItems.ToList(); - if (items != null) + public bool GetFocusPosition(out PAL.Rectangle rect) { - var matches = items.FindAll(x => x.Name == element); - if (matches.Count == 0) matches = items.FindAll(x => x.Name!.ToLower() == element.ToLower()); - if (matches.Count == 0) matches = items.FindAll(x => x.Name!.ToLower() == element.ToLower().Trim('.')); - if (matches.Count == 0) matches = items.FindAll(x => x.Name != null && x.Name!.Contains(element)); - if (matches.Count == 0) matches = items.FindAll(x => x.Name != null && x.Name!.ToLower().Contains(element.ToLower())); - if (matches.Count == 0) matches = items.FindAll(x => x.Name != null && x.Name!.ToLower().Contains(element.ToLower().Trim('.'))); - - var match = matches?.LastOrDefault(); - if (match?.Rect != null) + var stopWatch = StartStopWatch(); + do { - MR.DBG_TRACE_VERBOSE($"UIA: Element '{element}' FOUND!!! (gen={_generation}, count={items?.Count()}) ******************************"); - var bounds = match.Rect.Value; - rect = new PAL.Rectangle(bounds.left, bounds.top, bounds.right - bounds.left + 1, bounds.bottom - bounds.top + 1); - return true; + TraceRetryStart(stopWatch); + if (_focusRect != null) + { + var bounds = _focusRect.Value; + rect = new PAL.Rectangle(bounds.left, bounds.top, bounds.right - bounds.left + 1, bounds.bottom - bounds.top + 1); + return TraceRetryFoundIt(stopWatch); + } } - } + while (WaitForNewGeneration(stopWatch)); - MR.DBG_TRACE_WARNING($"UIA: Element '{element}' not found!!! (gen={_generation}, count={items?.Count()}) ******************************"); - //var msg = string.Join('\n', items?.Select(x => $"{x.Name}: {x.Rect!.Value.left},{x.Rect.Value.top}")); - //MR.DBG_TRACE_WARNING($"****\ncount={items?.Count()}\n*****\n{msg}\n*****\n*****\n*****\n*****\n*****\n*****\n*****\n"); + rect = new PAL.Rectangle(); + return TraceRetryNotFound(stopWatch); + } - rect = new PAL.Rectangle(); - return false; - } + private bool TryGetPosition(string element, out PAL.Rectangle rect) + { + var items = _allFoundItems.ToList(); + if (items != null) + { + var matches = items.FindAll(x => x.Name == element); + if (matches.Count == 0) matches = items.FindAll(x => x.Name!.ToLower() == element.ToLower()); + if (matches.Count == 0) matches = items.FindAll(x => x.Name!.ToLower() == element.ToLower().Trim('.')); + if (matches.Count == 0) matches = items.FindAll(x => x.Name != null && x.Name!.Contains(element)); + if (matches.Count == 0) matches = items.FindAll(x => x.Name != null && x.Name!.ToLower().Contains(element.ToLower())); + if (matches.Count == 0) matches = items.FindAll(x => x.Name != null && x.Name!.ToLower().Contains(element.ToLower().Trim('.'))); + + var match = matches?.LastOrDefault(); + if (match?.Rect != null) + { + MR.DBG_TRACE_VERBOSE($"UIA: Element '{element}' FOUND!!! (gen={_generation}, count={items?.Count()}) ******************************"); + var bounds = match.Rect.Value; + rect = new PAL.Rectangle(bounds.left, bounds.top, bounds.right - bounds.left + 1, bounds.bottom - bounds.top + 1); + return true; + } + } - private void DemandRefreshSoon() - { - var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - var message = new ThreadMessage() { kind = MessageKind.DemandRefreshSoon, tcs = tcs }; - QueueThreadMessage(message); - tcs.Task.Wait(); - } + MR.DBG_TRACE_WARNING($"UIA: Element '{element}' not found!!! (gen={_generation}, count={items?.Count()}) ******************************"); + //var msg = string.Join('\n', items?.Select(x => $"{x.Name}: {x.Rect!.Value.left},{x.Rect.Value.top}")); + //MR.DBG_TRACE_WARNING($"****\ncount={items?.Count()}\n*****\n{msg}\n*****\n*****\n*****\n*****\n*****\n*****\n*****\n"); - private void InitThread() - { - if (_thread == null) - { - StartThread(); + rect = new PAL.Rectangle(); + return false; } - } - private void TermThread() - { - if (_thread != null) + private void DemandRefreshSoon() { - var message = new ThreadMessage() { kind = MessageKind.StopThread }; + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var message = new ThreadMessage() { kind = MessageKind.DemandRefreshSoon, tcs = tcs }; QueueThreadMessage(message); + tcs.Task.Wait(); } - } - - private void StartThread() - { - // In order to prevent any possibility of the calls to UIA below leading to delays while a - // a UIA event handler is also running, all calls to UIA below will run on a background MTA - // thread. This means that the app's main UI thread makes no calls to UIA at all. - _messageInQueueEvent = new AutoResetEvent(false); - _threadStartCompleteEvent = new AutoResetEvent(false); - - _thread = new Thread(new ParameterizedThreadStart(ThreadProcStatic)); - _thread.SetApartmentState(ApartmentState.MTA); // **MUST** be MTA thread - _thread.Start(this); - - _threadStartCompleteEvent.WaitOne(); - } - - private void QueueThreadMessage(ThreadMessage message) - { - Monitor.Enter(_messageQueue); - try + private void InitThread() { - _messageQueue.Enqueue(message); + if (_thread == null) + { + StartThread(); + } } - finally + + private void TermThread() { - Monitor.Exit(_messageQueue); + if (_thread != null) + { + var message = new ThreadMessage() { kind = MessageKind.StopThread }; + QueueThreadMessage(message); + } } - _messageInQueueEvent!.Set(); - } - private static void ThreadProcStatic(object? data) - { - var processor = (WindowsUiAutomationService)data!; - processor.ThreadProc(); - } + private void StartThread() + { + // In order to prevent any possibility of the calls to UIA below leading to delays while a + // a UIA event handler is also running, all calls to UIA below will run on a background MTA + // thread. This means that the app's main UI thread makes no calls to UIA at all. - private void ThreadProc() - { - InitUiaOnThread(); + _messageInQueueEvent = new AutoResetEvent(false); + _threadStartCompleteEvent = new AutoResetEvent(false); - _threadStartCompleteEvent!.Set(); + _thread = new Thread(new ParameterizedThreadStart(ThreadProcStatic)); + _thread.SetApartmentState(ApartmentState.MTA); // **MUST** be MTA thread + _thread.Start(this); - bool stopThreadRequested = false; - while (!stopThreadRequested) + _threadStartCompleteEvent.WaitOne(); + } + + private void QueueThreadMessage(ThreadMessage message) { - var subtract = 0; - if (DateTime.Now < _noRefreshAfterDateTime) + Monitor.Enter(_messageQueue); + try { - subtract = TryRefreshRightNow(true); + _messageQueue.Enqueue(message); } - var maxWait = subtract < 750 ? 750 - subtract : 0; - - if (_verbose) MR.DBG_TRACE_VERBOSE($"UIA Thread: Waiting {maxWait}..."); - var found = _messageInQueueEvent!.WaitOne(maxWait); - if (_verbose) MR.DBG_TRACE_VERBOSE($"UIA Thread: Waiting {maxWait}... (found={found}) ... Done."); - - while (true) + finally { - Monitor.Enter(_messageQueue); - var messageInQueue = _messageQueue.TryDequeue(out var message); Monitor.Exit(_messageQueue); + } + _messageInQueueEvent!.Set(); + } + + private static void ThreadProcStatic(object? data) + { + var processor = (WindowsUiAutomationService)data!; + processor.ThreadProc(); + } + + private void ThreadProc() + { + InitUiaOnThread(); + + _threadStartCompleteEvent!.Set(); - if (!messageInQueue) + bool stopThreadRequested = false; + while (!stopThreadRequested) + { + var subtract = 0; + if (DateTime.Now < _noRefreshAfterDateTime) { - break; + subtract = TryRefreshRightNow(true); } - else if (message.kind == MessageKind.StopThread) + var maxWait = subtract < 750 ? 750 - subtract : 0; + + if (_verbose) MR.DBG_TRACE_VERBOSE($"UIA Thread: Waiting {maxWait}..."); + var found = _messageInQueueEvent!.WaitOne(maxWait); + if (_verbose) MR.DBG_TRACE_VERBOSE($"UIA Thread: Waiting {maxWait}... (found={found}) ... Done."); + + while (true) { - stopThreadRequested = true; - break; - } + Monitor.Enter(_messageQueue); + var messageInQueue = _messageQueue.TryDequeue(out var message); + Monitor.Exit(_messageQueue); + + if (!messageInQueue) + { + break; + } + else if (message.kind == MessageKind.StopThread) + { + stopThreadRequested = true; + break; + } - ProcessThreadMessage(message); + ProcessThreadMessage(message); + } } } - } - private void InitUiaOnThread() - { - _automation = new CUIAutomation(); - _root = _automation.GetRootElement(); - _walker = _automation.ControlViewWalker; - } + private void InitUiaOnThread() + { + _automation = new CUIAutomation(); + _root = _automation.GetRootElement(); + _walker = _automation.ControlViewWalker; + } - private void ProcessThreadMessage(ThreadMessage message) - { - try + private void ProcessThreadMessage(ThreadMessage message) { - if (message.kind == MessageKind.DemandRefreshSoon) + try + { + if (message.kind == MessageKind.DemandRefreshSoon) + { + ProcessDemandRefreshSoon(); + } + } + catch (Exception ex) { - ProcessDemandRefreshSoon(); + MR.DBG_TRACE_ERROR($"UIA: {ex}"); } + + message.tcs?.TrySetResult(); } - catch (Exception ex) + + private void ProcessDemandRefreshSoon() { - MR.DBG_TRACE_ERROR($"UIA: {ex}"); + _noRefreshAfterDateTime = DateTime.Now.AddSeconds(_refreshTimesoutAfterSeconds); } - message.tcs?.TrySetResult(); - } + private int TryRefreshRightNow(bool fUseCache) + { + if (_refreshingListRightNow) return 0; + _refreshingListRightNow = true; - private void ProcessDemandRefreshSoon() - { - _noRefreshAfterDateTime = DateTime.Now.AddSeconds(_refreshTimesoutAfterSeconds); - } + try + { + MR.DBG_TRACE_VERBOSE("UIA: DoRefreshList ..."); - private int TryRefreshRightNow(bool fUseCache) - { - if (_refreshingListRightNow) return 0; - _refreshingListRightNow = true; + var stopWatch = new Stopwatch(); + stopWatch.Start(); - try - { - MR.DBG_TRACE_VERBOSE("UIA: DoRefreshList ..."); + var focus = _automation!.GetFocusedElement(); + if (focus == null) MR.DBG_TRACE_WARNING($"UIA: DoRefreshList focus==NULL"); - var stopWatch = new Stopwatch(); - stopWatch.Start(); + var top = GetTopElement(focus); + if (top == null) MR.DBG_TRACE_WARNING($"UIA: DoRefreshList top==NULL"); - var focus = _automation!.GetFocusedElement(); - if (focus == null) MR.DBG_TRACE_WARNING($"UIA: DoRefreshList focus==NULL"); + if (top != null && focus != null) + { + FindAllElementsUnderElement(focus, top, fUseCache); + } - var top = GetTopElement(focus); - if (top == null) MR.DBG_TRACE_WARNING($"UIA: DoRefreshList top==NULL"); + stopWatch.Stop(); + MR.DBG_TRACE_VERBOSE($"UIA: DoRefreshList took {stopWatch.ElapsedMilliseconds} ms; found {_allFoundItems?.Count()} items..."); - if (top != null && focus != null) + _refreshingListRightNow = false; + return (int)stopWatch.ElapsedMilliseconds; + } + catch (Exception) { - FindAllElementsUnderElement(focus, top, fUseCache); } - stopWatch.Stop(); - MR.DBG_TRACE_VERBOSE($"UIA: DoRefreshList took {stopWatch.ElapsedMilliseconds} ms; found {_allFoundItems?.Count()} items..."); - _refreshingListRightNow = false; - return (int)stopWatch.ElapsedMilliseconds; - } - catch (Exception) - { + return 0; } - _refreshingListRightNow = false; - return 0; - } + private IUIAutomationElement? GetTopElement(IUIAutomationElement? node) + { + _root = _automation?.GetRootElement(); + if (node == _root) return null; - private IUIAutomationElement? GetTopElement(IUIAutomationElement? node) - { - _root = _automation?.GetRootElement(); - if (node == _root) return null; + while (true) + { + var parent = _walker!.GetParentElement(node); + if (parent == null) break; - while (true) - { - var parent = _walker!.GetParentElement(node); - if (parent == null) break; + var compare = _automation!.CompareElements(parent, _root); + if (compare != 0) break; - var compare = _automation!.CompareElements(parent, _root); - if (compare != 0) break; + node = parent; + } - node = parent; + return node; } - return node; - } - - private IUIAutomationCacheRequest InitUiaCacheRequest() - { - var cacheRequest = _automation!.CreateCacheRequest(); - cacheRequest.AddProperty(_propertyIdName); - cacheRequest.AddProperty(_propertyIdBoundingRectangle); - cacheRequest.TreeScope = TreeScope.TreeScope_Element; - - // If we specified a Mode of None for the cache request here, then the results only include - // cached data, with no connection at all after the call returns to the source elements. If - // only data is required, then it would be preference to use a Mode of None, as less work is - // required by UIA. (Also, if a reference to the element is returned in the cache and kept - // around for a non-trivial time, then it increases the chances that the target process - // attempts to free the element, but it can't do so in a clean manner as it would like, - // due to the client app here holding a reference to it.) To specify that we want a Mode of - // None, we'd make this call here: - - // cacheRequest.AutomationElementMode = AutomationElementMode.AutomationElementMode_None; - - return cacheRequest; - } + private IUIAutomationCacheRequest InitUiaCacheRequest() + { + var cacheRequest = _automation!.CreateCacheRequest(); + cacheRequest.AddProperty(_propertyIdName); + cacheRequest.AddProperty(_propertyIdBoundingRectangle); + cacheRequest.TreeScope = TreeScope.TreeScope_Element; + + // If we specified a Mode of None for the cache request here, then the results only include + // cached data, with no connection at all after the call returns to the source elements. If + // only data is required, then it would be preference to use a Mode of None, as less work is + // required by UIA. (Also, if a reference to the element is returned in the cache and kept + // around for a non-trivial time, then it increases the chances that the target process + // attempts to free the element, but it can't do so in a clean manner as it would like, + // due to the client app here holding a reference to it.) To specify that we want a Mode of + // None, we'd make this call here: + + // cacheRequest.AutomationElementMode = AutomationElementMode.AutomationElementMode_None; + + return cacheRequest; + } - private IUIAutomationCondition InitUiaCondition() - { - var UIA_IsEnabledPropertyId = 30010U; - var UIA_IsOffscreenPropertyId = 30022U; + private IUIAutomationCondition InitUiaCondition() + { + var UIA_IsEnabledPropertyId = 30010U; + var UIA_IsOffscreenPropertyId = 30022U; - var enabled = _automation!.CreatePropertyCondition((int)UIA_IsEnabledPropertyId, true); - var visible = _automation!.CreatePropertyCondition((int)UIA_IsOffscreenPropertyId, false); - var condition = _automation!.CreateAndCondition(enabled, visible); - return condition; - } + var enabled = _automation!.CreatePropertyCondition((int)UIA_IsEnabledPropertyId, true); + var visible = _automation!.CreatePropertyCondition((int)UIA_IsOffscreenPropertyId, false); + var condition = _automation!.CreateAndCondition(enabled, visible); + return condition; + } - private void FindAllElementsUnderElement(IUIAutomationElement focusElement, IUIAutomationElement topElement, bool fUseCache) - { - var condition = InitUiaCondition(); - var allElements = fUseCache - ? topElement.FindAllBuildCache(TreeScope.TreeScope_Descendants, condition, InitUiaCacheRequest()) - : topElement.FindAll(TreeScope.TreeScope_Descendants, condition); + private void FindAllElementsUnderElement(IUIAutomationElement focusElement, IUIAutomationElement topElement, bool fUseCache) + { + var condition = InitUiaCondition(); + var allElements = fUseCache + ? topElement.FindAllBuildCache(TreeScope.TreeScope_Descendants, condition, InitUiaCacheRequest()) + : topElement.FindAll(TreeScope.TreeScope_Descendants, condition); - var list = new List(); + var list = new List(); - if (allElements != null) - { - var count = allElements.Length; - MR.DBG_TRACE_VERBOSE($"UIA: Checking {count} items..."); - for (int i = 0; i < count; ++i) + if (allElements != null) { - var element = allElements.GetElement(i); - - var rect = fUseCache ? element.CachedBoundingRectangle : element.CurrentBoundingRectangle; - if (rect.right > rect.left && rect.bottom > rect.top) + var count = allElements.Length; + MR.DBG_TRACE_VERBOSE($"UIA: Checking {count} items..."); + for (int i = 0; i < count; ++i) { - var name = fUseCache ? element.CachedName : element.CurrentName; - if (!string.IsNullOrEmpty(name)) + var element = allElements.GetElement(i); + + var rect = fUseCache ? element.CachedBoundingRectangle : element.CurrentBoundingRectangle; + if (rect.right > rect.left && rect.bottom > rect.top) { - name = name.Trim(); - if (name.Length > 0) + var name = fUseCache ? element.CachedName : element.CurrentName; + if (!string.IsNullOrEmpty(name)) { - var found = new FoundElement(); - found.Name = name; - found.Element = element; - found.Rect = rect; - - list.Add(found); + name = name.Trim(); + if (name.Length > 0) + { + var found = new FoundElement(); + found.Name = name; + found.Element = element; + found.Rect = rect; + + list.Add(found); + } } } } - } - _allFoundItems.Clear(); - _allFoundItems.AddRange(list); + _allFoundItems.Clear(); + _allFoundItems.AddRange(list); - _topRect = topElement.CurrentBoundingRectangle; - _focusRect = focusElement.CurrentBoundingRectangle; + _topRect = topElement.CurrentBoundingRectangle; + _focusRect = focusElement.CurrentBoundingRectangle; - _generation++; + _generation++; + } } - } - #region data/structs/enums + #region data/structs/enums - private IUIAutomation? _automation; - private IUIAutomationElement? _root; - private IUIAutomationTreeWalker? _walker; - private bool _refreshingListRightNow = false; + private IUIAutomation? _automation; + private IUIAutomationElement? _root; + private IUIAutomationTreeWalker? _walker; + private bool _refreshingListRightNow = false; - private Thread? _thread; - private AutoResetEvent? _threadStartCompleteEvent; + private Thread? _thread; + private AutoResetEvent? _threadStartCompleteEvent; - private enum MessageKind - { - None, - DemandRefreshSoon, - StopThread - }; + private enum MessageKind + { + None, + DemandRefreshSoon, + StopThread + }; - private struct ThreadMessage - { - public MessageKind kind; - public TaskCompletionSource? tcs; - }; + private struct ThreadMessage + { + public MessageKind kind; + public TaskCompletionSource? tcs; + }; - private AutoResetEvent? _messageInQueueEvent; - private Queue _messageQueue = new Queue(); + private AutoResetEvent? _messageInQueueEvent; + private Queue _messageQueue = new Queue(); - public class FoundElement - { - public string? Name; - public object? Element; - public tagRECT? Rect; - } + public class FoundElement + { + public string? Name; + public object? Element; + public tagRECT? Rect; + } - volatile int _generation; - private List _allFoundItems = new List(); - private tagRECT? _topRect; - private tagRECT? _focusRect; + volatile int _generation; + private List _allFoundItems = new List(); + private tagRECT? _topRect; + private tagRECT? _focusRect; - private int _propertyIdBoundingRectangle = 30001; - private int _propertyIdName = 30005; + private int _propertyIdBoundingRectangle = 30001; + private int _propertyIdName = 30005; - private DateTime _noRefreshAfterDateTime = DateTime.Now; - private int _refreshTimesoutAfterSeconds = 10; - private const int _maxWaitForGenerationChange = 10000; + private DateTime _noRefreshAfterDateTime = DateTime.Now; + private int _refreshTimesoutAfterSeconds = 10; + private const int _maxWaitForGenerationChange = 10000; - private bool _verbose = false; - - #endregion -} + private bool _verbose = false; + + #endregion + } +} \ No newline at end of file diff --git a/src/win32_ui/Ui/AlphaTextStatusOSD.Designer.cs b/src/win32_ui/Ui/AlphaTextStatusOSD.Designer.cs index 001b2b44..1ed63e96 100644 --- a/src/win32_ui/Ui/AlphaTextStatusOSD.Designer.cs +++ b/src/win32_ui/Ui/AlphaTextStatusOSD.Designer.cs @@ -1,33 +1,34 @@ -namespace macaroni; - -partial class AlphaTextStatusOSD +namespace macaroni { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) + partial class AlphaTextStatusOSD { - if (disposing && (components != null)) + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) { - components.Dispose(); + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); } - base.Dispose(disposing); - } - #region Windows Form Designer generated code + #region Windows Form Designer generated code - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { this.components = new System.ComponentModel.Container(); this._timer = new System.Windows.Forms.Timer(this.components); this.SuspendLayout(); @@ -45,9 +46,10 @@ private void InitializeComponent() this.Text = "Form1"; this.ResumeLayout(false); - } + } - #endregion + #endregion - private System.Windows.Forms.Timer _timer; -} + private System.Windows.Forms.Timer _timer; + } +} \ No newline at end of file diff --git a/src/win32_ui/Ui/AlphaTextStatusOSD.cs b/src/win32_ui/Ui/AlphaTextStatusOSD.cs index 192e490e..9204e2a0 100644 --- a/src/win32_ui/Ui/AlphaTextStatusOSD.cs +++ b/src/win32_ui/Ui/AlphaTextStatusOSD.cs @@ -1,267 +1,268 @@ +using macaroni.interop; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.Drawing.Text; -using macaroni.interop; -namespace macaroni; - -public partial class AlphaTextStatusOSD : Form +namespace macaroni { - public AlphaTextStatusOSD() + public partial class AlphaTextStatusOSD : Form { - InitializeComponent(); + public AlphaTextStatusOSD() + { + InitializeComponent(); - FontSize1 = _defaultFontSize1; - FontName1 = _defaultFontName1; - FontColor1 = _defaultFontColor1; - BackgroundColor1 = _defaultBackgroundColor1; + FontSize1 = _defaultFontSize1; + FontName1 = _defaultFontName1; + FontColor1 = _defaultFontColor1; + BackgroundColor1 = _defaultBackgroundColor1; - FontSize2 = _defaultFontSize2; - FontName2 = _defaultFontName2; - FontColor2 = _defaultFontColor2; - BackgroundColor2 = _defaultBackgroundColor2; + FontSize2 = _defaultFontSize2; + FontName2 = _defaultFontName2; + FontColor2 = _defaultFontColor2; + BackgroundColor2 = _defaultBackgroundColor2; - Text = _defaultText; + Text = _defaultText; - TopMost = true; - ShowInTaskbar = false; - } + TopMost = true; + ShowInTaskbar = false; + } - public override string Text - { - get => base.Text; - set + public override string Text { - SetText(value, _nonFadeTimeMs); + get => base.Text; + set + { + SetText(value, _nonFadeTimeMs); + } } - } - public void SetText(string text, int nonFadeTimeInMs) - { - base.Text = text; - UpdateText(text, nonFadeTimeInMs); - } + public void SetText(string text, int nonFadeTimeInMs) + { + base.Text = text; + UpdateText(text, nonFadeTimeInMs); + } - public Point TextPos { get; set; } - public Size TextSize { get; set; } + public Point TextPos { get; set; } + public Size TextSize { get; set; } - public string FontName1 { get; private set; } - public float FontSize1 { get; private set; } - public string FontColor1 { get; private set; } - public string BackgroundColor1 { get; private set; } + public string FontName1 { get; private set; } + public float FontSize1 { get; private set; } + public string FontColor1 { get; private set; } + public string BackgroundColor1 { get; private set; } - public string FontName2 { get; private set; } - public float FontSize2 { get; private set; } - public string FontColor2 { get; private set; } - public string BackgroundColor2 { get; private set; } + public string FontName2 { get; private set; } + public float FontSize2 { get; private set; } + public string FontColor2 { get; private set; } + public string BackgroundColor2 { get; private set; } - protected override CreateParams CreateParams - { - get + protected override CreateParams CreateParams { - var screen = Screen.PrimaryScreen; - var bounds = screen.Bounds; - bounds.Y = screen.WorkingArea.Bottom; - bounds.Height = screen.Bounds.Bottom - screen.WorkingArea.Bottom + 1; + get + { + var screen = Screen.PrimaryScreen; + var bounds = screen.Bounds; + bounds.Y = screen.WorkingArea.Bottom; + bounds.Height = screen.Bounds.Bottom - screen.WorkingArea.Bottom + 1; - bounds.Height = Math.Max(bounds.Height, 49); - bounds.Y = screen.Bounds.Bottom - bounds.Height + 1; + bounds.Height = Math.Max(bounds.Height, 49); + bounds.Y = screen.Bounds.Bottom - bounds.Height + 1; - var cp = base.CreateParams; - cp.X = bounds.X; - cp.Y = bounds.Y; - cp.Height = bounds.Height; - cp.Width = bounds.Width; + var cp = base.CreateParams; + cp.X = bounds.X; + cp.Y = bounds.Y; + cp.Height = bounds.Height; + cp.Width = bounds.Width; - cp.ExStyle |= 0x00080000 | // This form has to have the WS_EX_LAYERED extended style - 0x08000000 | // WS_EX_NOACTIVATE - 0x00000080; // WS_EX_TOOLWINDOW + cp.ExStyle |= 0x00080000 | // This form has to have the WS_EX_LAYERED extended style + 0x08000000 | // WS_EX_NOACTIVATE + 0x00000080; // WS_EX_TOOLWINDOW - return cp; + return cp; + } } - } - - protected override bool ShowWithoutActivation => true; - protected override void OnLoad(EventArgs e) - { - TextPos = new Point(this.Height / 2, 0); - TextSize = this.Size; - UpdateText(Text, _nonFadeTimeMs); - - base.OnLoad(e); - } + protected override bool ShowWithoutActivation => true; - protected override void WndProc(ref Message m) - { - if (m.Msg == 0x0084 /*WM_NCHITTEST*/) + protected override void OnLoad(EventArgs e) { - m.Result = (IntPtr)2; // HTCAPTION - return; - } - base.WndProc(ref m); - } + TextPos = new Point(this.Height / 2, 0); + TextSize = this.Size; + UpdateText(Text, _nonFadeTimeMs); - private void StartFade(int nonFadeTimeMs = 0) - { - _fadeFrame = 0; - _timer.Interval = nonFadeTimeMs > 0 ? nonFadeTimeMs : _nonFadeTimeMs; - _timer.Start(); - } + base.OnLoad(e); + } - private void timer_Tick(object sender, EventArgs e) - { - if (_lastBitmap != null) + protected override void WndProc(ref Message m) { - if (_fadeFrame == 0) - { - _timer.Stop(); - _timer.Interval = _msPerFrame; - _timer.Start(); - } - - _fadeFrame++; - byte newAlpha = (byte)(_alpha * InOutQuadBlend(1.0f - (float)_fadeFrame / _fadeFrameCount)); - if (newAlpha == 0) + if (m.Msg == 0x0084 /*WM_NCHITTEST*/) { - Close(); + m.Result = (IntPtr)2; // HTCAPTION return; } - - SetBitmap(new Bitmap(_lastBitmap), newAlpha); + base.WndProc(ref m); } - } - private float InOutQuadBlend(float t) - { - if (t <= 0.5f) - return 2.0f * t * t; - t -= 0.5f; - return 2.0f * t * (1.0f - t) + 0.5f; - } - - private void UpdateText(string text, int nonFadeTimeMs) - { - if (this.TextSize.Height > 0) + private void StartFade(int nonFadeTimeMs = 0) { - StartFade(nonFadeTimeMs); - SetBitmap(OverlayText(text, StringAlignment.Near), _alpha); - Show(); + _fadeFrame = 0; + _timer.Interval = nonFadeTimeMs > 0 ? nonFadeTimeMs : _nonFadeTimeMs; + _timer.Start(); } - } - private Bitmap OverlayText(string text, StringAlignment alignment = StringAlignment.Center, StringAlignment lineAlignment = StringAlignment.Center) - { - var newImg = new Bitmap(this.Width, this.Height, PixelFormat.Format32bppArgb); - using (var graphics = Graphics.FromImage(newImg)) + private void timer_Tick(object sender, EventArgs e) { - graphics.SmoothingMode = SmoothingMode.AntiAlias; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.TextRenderingHint = TextRenderingHint.AntiAlias; - - var brush1 = new SolidBrush(ColorTranslator.FromHtml(BackgroundColor1)); - graphics.FillRectangle(brush1, -1, -1, this.Width + 1, this.Height + 1); - - var brush2 = new SolidBrush(ColorTranslator.FromHtml(BackgroundColor2)); - graphics.FillRectangle(brush2, -1, -1, this.Height / 4, this.Height + 1); - - graphics.DrawString(text, - new Font(FontName1, FontSize1), - new SolidBrush(ColorTranslator.FromHtml(FontColor1)), - new System.Drawing.Rectangle(TextPos, TextSize), - new StringFormat(StringFormatFlags.LineLimit) { Alignment = alignment, LineAlignment = lineAlignment }); - return newImg; + if (_lastBitmap != null) + { + if (_fadeFrame == 0) + { + _timer.Stop(); + _timer.Interval = _msPerFrame; + _timer.Start(); + } + + _fadeFrame++; + byte newAlpha = (byte)(_alpha * InOutQuadBlend(1.0f - (float)_fadeFrame / _fadeFrameCount)); + if (newAlpha == 0) + { + Close(); + return; + } + + SetBitmap(new Bitmap(_lastBitmap), newAlpha); + } } - } - private void SetBitmap(Bitmap bitmap, byte opacity) - { - if (_lastBitmap != null) + private float InOutQuadBlend(float t) { - _lastBitmap.Dispose(); - _lastBitmap = null; + if (t <= 0.5f) + return 2.0f * t * t; + t -= 0.5f; + return 2.0f * t * (1.0f - t) + 0.5f; } - _lastBitmap = bitmap; - if (bitmap.PixelFormat != PixelFormat.Format32bppArgb) + private void UpdateText(string text, int nonFadeTimeMs) { - throw new ApplicationException("The bitmap must be 32ppp with alpha-channel."); + if (this.TextSize.Height > 0) + { + StartFade(nonFadeTimeMs); + SetBitmap(OverlayText(text, StringAlignment.Near), _alpha); + Show(); + } } - // The idea of this is very simple, - // (1) Create a compatible DC with screen; - // (2) Select the bitmap with 32bpp with alpha-channel in the compatible DC; - // (3) Call the UpdateLayeredWindow. - - var screenDc = Win32.GetDC(IntPtr.Zero); - var memDc = Win32.CreateCompatibleDC(screenDc); - var hBitmap = IntPtr.Zero; - var oldBitmap = IntPtr.Zero; + private Bitmap OverlayText(string text, StringAlignment alignment = StringAlignment.Center, StringAlignment lineAlignment = StringAlignment.Center) + { + var newImg = new Bitmap(this.Width, this.Height, PixelFormat.Format32bppArgb); + using (var graphics = Graphics.FromImage(newImg)) + { + graphics.SmoothingMode = SmoothingMode.AntiAlias; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.TextRenderingHint = TextRenderingHint.AntiAlias; + + var brush1 = new SolidBrush(ColorTranslator.FromHtml(BackgroundColor1)); + graphics.FillRectangle(brush1, -1, -1, this.Width + 1, this.Height + 1); + + var brush2 = new SolidBrush(ColorTranslator.FromHtml(BackgroundColor2)); + graphics.FillRectangle(brush2, -1, -1, this.Height / 4, this.Height + 1); + + graphics.DrawString(text, + new Font(FontName1, FontSize1), + new SolidBrush(ColorTranslator.FromHtml(FontColor1)), + new System.Drawing.Rectangle(TextPos, TextSize), + new StringFormat(StringFormatFlags.LineLimit) { Alignment = alignment, LineAlignment = lineAlignment }); + return newImg; + } + } - try + private void SetBitmap(Bitmap bitmap, byte opacity) { - hBitmap = bitmap.GetHbitmap(Color.FromArgb(0)); // grab a GDI handle from this GDI+ bitmap - oldBitmap = Win32.SelectObject(memDc, hBitmap); + if (_lastBitmap != null) + { + _lastBitmap.Dispose(); + _lastBitmap = null; + } + _lastBitmap = bitmap; - var size = new Win32.Size(bitmap.Width, bitmap.Height); - var pointSource = new Win32.Point(0, 0); - var topPos = new Win32.Point(Left, Top); - var blend = new Win32.BLENDFUNCTION + if (bitmap.PixelFormat != PixelFormat.Format32bppArgb) { - BlendOp = Win32.AC_SRC_OVER, - BlendFlags = 0, - SourceConstantAlpha = opacity, - AlphaFormat = Win32.AC_SRC_ALPHA - }; + throw new ApplicationException("The bitmap must be 32ppp with alpha-channel."); + } + + // The idea of this is very simple, + // (1) Create a compatible DC with screen; + // (2) Select the bitmap with 32bpp with alpha-channel in the compatible DC; + // (3) Call the UpdateLayeredWindow. + + var screenDc = Win32.GetDC(IntPtr.Zero); + var memDc = Win32.CreateCompatibleDC(screenDc); + var hBitmap = IntPtr.Zero; + var oldBitmap = IntPtr.Zero; try { - Win32.UpdateLayeredWindow(Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, 0, ref blend, Win32.ULW_ALPHA); + hBitmap = bitmap.GetHbitmap(Color.FromArgb(0)); // grab a GDI handle from this GDI+ bitmap + oldBitmap = Win32.SelectObject(memDc, hBitmap); + + var size = new Win32.Size(bitmap.Width, bitmap.Height); + var pointSource = new Win32.Point(0, 0); + var topPos = new Win32.Point(Left, Top); + var blend = new Win32.BLENDFUNCTION + { + BlendOp = Win32.AC_SRC_OVER, + BlendFlags = 0, + SourceConstantAlpha = opacity, + AlphaFormat = Win32.AC_SRC_ALPHA + }; + + try + { + Win32.UpdateLayeredWindow(Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, 0, ref blend, Win32.ULW_ALPHA); + } + catch { } } - catch { } - } - finally - { - Win32.ReleaseDC(IntPtr.Zero, screenDc); - if (hBitmap != IntPtr.Zero) + finally { - Win32.SelectObject(memDc, oldBitmap); - Win32.DeleteObject(hBitmap); + Win32.ReleaseDC(IntPtr.Zero, screenDc); + if (hBitmap != IntPtr.Zero) + { + Win32.SelectObject(memDc, oldBitmap); + Win32.DeleteObject(hBitmap); + } + Win32.DeleteDC(memDc); } - Win32.DeleteDC(memDc); } - } - #region constants + #region constants - private const int _defaultFontSize1 = 26; - private const string _defaultFontName1 = "Tahoma"; - private const string _defaultFontColor1 = "#ffffffff"; - private const string _defaultBackgroundColor1 = "#ff000000"; - private const string _defaultText = ""; + private const int _defaultFontSize1 = 26; + private const string _defaultFontName1 = "Tahoma"; + private const string _defaultFontColor1 = "#ffffffff"; + private const string _defaultBackgroundColor1 = "#ff000000"; + private const string _defaultText = ""; - private const int _defaultFontSize2 = 18; - private const string _defaultFontName2 = "Tahoma"; - private const string _defaultFontColor2 = "#ff000000"; - private const string _defaultBackgroundColor2 = "#ffffc90e"; + private const int _defaultFontSize2 = 18; + private const string _defaultFontName2 = "Tahoma"; + private const string _defaultFontColor2 = "#ff000000"; + private const string _defaultBackgroundColor2 = "#ffffc90e"; - private const byte _alpha = 200; + private const byte _alpha = 200; - private const int _framesPerSecond = 60; - private const int _msPerFrame = 1000 / _framesPerSecond; + private const int _framesPerSecond = 60; + private const int _msPerFrame = 1000 / _framesPerSecond; - private const int _nonFadeTimeMs = 1250; - private const int _fadeTimeMs = 800; - private const float _fadeFrameCount = (float)_fadeTimeMs / _msPerFrame; - private const float _fadeAlphaPerFrame = _alpha / _fadeFrameCount; + private const int _nonFadeTimeMs = 1250; + private const int _fadeTimeMs = 800; + private const float _fadeFrameCount = (float)_fadeTimeMs / _msPerFrame; + private const float _fadeAlphaPerFrame = _alpha / _fadeFrameCount; - #endregion + #endregion - #region private data + #region private data - private int _fadeFrame = 0; - private Bitmap? _lastBitmap; + private int _fadeFrame = 0; + private Bitmap? _lastBitmap; - #endregion -} + #endregion + } +} \ No newline at end of file diff --git a/src/win32_ui/Ui/AlphaTips.Designer.cs b/src/win32_ui/Ui/AlphaTips.Designer.cs index 093d7a40..a50c45f6 100644 --- a/src/win32_ui/Ui/AlphaTips.Designer.cs +++ b/src/win32_ui/Ui/AlphaTips.Designer.cs @@ -1,33 +1,34 @@ -namespace macaroni; - -partial class AlphaTips +namespace macaroni { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) + partial class AlphaTips { - if (disposing && (components != null)) + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) { - components.Dispose(); + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); } - base.Dispose(disposing); - } - #region Windows Form Designer generated code + #region Windows Form Designer generated code - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { this.components = new System.ComponentModel.Container(); this._timer = new System.Windows.Forms.Timer(this.components); this.SuspendLayout(); @@ -45,9 +46,10 @@ private void InitializeComponent() this.Text = "Form1"; this.ResumeLayout(false); - } + } - #endregion + #endregion - private System.Windows.Forms.Timer _timer; -} + private System.Windows.Forms.Timer _timer; + } +} \ No newline at end of file diff --git a/src/win32_ui/Ui/AlphaTips.cs b/src/win32_ui/Ui/AlphaTips.cs index b95fda89..b229987b 100644 --- a/src/win32_ui/Ui/AlphaTips.cs +++ b/src/win32_ui/Ui/AlphaTips.cs @@ -1,470 +1,471 @@ -using System; -using System.Drawing; +using macaroni.interop; +using Microsoft.Extensions.DependencyInjection; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.Drawing.Text; -using macaroni.interop; -using Microsoft.Extensions.DependencyInjection; -namespace macaroni; - -public partial class AlphaTips : Form +namespace macaroni { - public interface ITipProvider - { - IEnumerable? GetTips(); - } - public AlphaTips(IServiceProvider serviceProvider, IEnumerable? tips, Func?>? moreTips) + public partial class AlphaTips : Form { - InitializeComponent(); - - FontSize1 = _defaultFontSize1; - FontName1 = _defaultFontName1; - FontColor1 = _defaultFontColor1; - BackgroundColor1 = _defaultBackgroundColor1; - - FontSize2 = _defaultFontSize2; - FontName2 = _defaultFontName2; - FontColor2 = _defaultFontColor2; - BackgroundColor2 = _defaultBackgroundColor2; - - FontSize3 = _defaultFontSize3; - FontName3 = _defaultFontName3; - FontColor3 = _defaultFontColor3; - BackgroundColor3 = _defaultBackgroundColor3; - - FontColor4 = _defaultFontColor4; - BackgroundColor4 = _defaultBackgroundColor4; - - _tips = tips ?? new string[] { _defaultText}; - moreTips ??= () => { - var provider = serviceProvider.GetService(); - return provider?.GetTips(); - }; - _getTips = moreTips; - NextTip(); - - TopMost = true; - ShowInTaskbar = false; - } - - public AlphaTips(IServiceProvider serviceProvider) : this(serviceProvider, null, null) - { - } - - public override string Text - { - get => base.Text; - set + public interface ITipProvider { - SetText(value, _nonFadeTimeMs); + IEnumerable? GetTips(); } - } - public void SetText(string text, int nonFadeTimeInMs) - { - base.Text = text; - UpdateText(text, nonFadeTimeInMs); - } + public AlphaTips(IServiceProvider serviceProvider, IEnumerable? tips, Func?>? moreTips) + { + InitializeComponent(); - public Point TextPos { get; set; } - public Size TextSize { get; set; } + FontSize1 = _defaultFontSize1; + FontName1 = _defaultFontName1; + FontColor1 = _defaultFontColor1; + BackgroundColor1 = _defaultBackgroundColor1; - public string FontName1 { get; private set; } - public float FontSize1 { get; private set; } - public string FontColor1 { get; private set; } - public string BackgroundColor1 { get; private set; } + FontSize2 = _defaultFontSize2; + FontName2 = _defaultFontName2; + FontColor2 = _defaultFontColor2; + BackgroundColor2 = _defaultBackgroundColor2; - public string FontName2 { get; private set; } - public float FontSize2 { get; private set; } - public string FontColor2 { get; private set; } - public string BackgroundColor2 { get; private set; } + FontSize3 = _defaultFontSize3; + FontName3 = _defaultFontName3; + FontColor3 = _defaultFontColor3; + BackgroundColor3 = _defaultBackgroundColor3; - public string FontName3 { get; private set; } - public float FontSize3 { get; private set; } - public string FontColor3 { get; private set; } - public string BackgroundColor3 { get; private set; } + FontColor4 = _defaultFontColor4; + BackgroundColor4 = _defaultBackgroundColor4; - public string FontColor4 { get; private set; } - public string BackgroundColor4 { get; private set; } + _tips = tips ?? new string[] { _defaultText }; + moreTips ??= () => + { + var provider = serviceProvider.GetService(); + return provider?.GetTips(); + }; + _getTips = moreTips; + NextTip(); - protected override CreateParams CreateParams - { - get - { - var screen = Screen.PrimaryScreen; - var bounds = screen.WorkingArea; + TopMost = true; + ShowInTaskbar = false; + } - var cy = bounds.Height * 30 / 100; - var cx = cy * 100 / 40; + public AlphaTips(IServiceProvider serviceProvider) : this(serviceProvider, null, null) + { + } - var padw = bounds.Width / 2 - cx / 2; - var padh = bounds.Height / 2 - cy / 2; + public override string Text + { + get => base.Text; + set + { + SetText(value, _nonFadeTimeMs); + } + } - bounds.X = padw; - bounds.Y = padh; - bounds.Height = cy; - bounds.Width = cx; + public void SetText(string text, int nonFadeTimeInMs) + { + base.Text = text; + UpdateText(text, nonFadeTimeInMs); + } - var cp = base.CreateParams; - cp.X = bounds.X; - cp.Y = bounds.Y; - cp.Height = bounds.Height; - cp.Width = bounds.Width; + public Point TextPos { get; set; } + public Size TextSize { get; set; } - cp.ExStyle |= 0x00080000 | // This form has to have the WS_EX_LAYERED extended style - 0x08000000 | // WS_EX_NOACTIVATE - 0x00000080; // WS_EX_TOOLWINDOW + public string FontName1 { get; private set; } + public float FontSize1 { get; private set; } + public string FontColor1 { get; private set; } + public string BackgroundColor1 { get; private set; } - return cp; - } - } + public string FontName2 { get; private set; } + public float FontSize2 { get; private set; } + public string FontColor2 { get; private set; } + public string BackgroundColor2 { get; private set; } - protected override bool ShowWithoutActivation => true; + public string FontName3 { get; private set; } + public float FontSize3 { get; private set; } + public string FontColor3 { get; private set; } + public string BackgroundColor3 { get; private set; } - protected override void OnLoad(EventArgs e) - { - var x1 = this.Height * 3 / 8; - var x2 = this.Width * 9 / 10; - var cx = x2 - x1; - var cy = this.Height; + public string FontColor4 { get; private set; } + public string BackgroundColor4 { get; private set; } - TextPos = new Point(x1, 0); - TextSize = new Size(cx, cy); - UpdateText(Text, _nonFadeTimeMs); + protected override CreateParams CreateParams + { + get + { + var screen = Screen.PrimaryScreen; + var bounds = screen.WorkingArea; - base.OnLoad(e); - } + var cy = bounds.Height * 30 / 100; + var cx = cy * 100 / 40; - protected override void OnMouseMove(MouseEventArgs e) - { - if (e.X >= this.Width * 9 / 10) - { - UpdateText(Text); - } + var padw = bounds.Width / 2 - cx / 2; + var padh = bounds.Height / 2 - cy / 2; - base.OnMouseMove(e); - } + bounds.X = padw; + bounds.Y = padh; + bounds.Height = cy; + bounds.Width = cx; - protected override void OnMouseClick(MouseEventArgs e) - { - if (e.Button == MouseButtons.Left) - { - var which = e.Y / (this.Height / 3); - switch (which) - { - case 0: // close - this.Close(); - break; + var cp = base.CreateParams; + cp.X = bounds.X; + cp.Y = bounds.Y; + cp.Height = bounds.Height; + cp.Width = bounds.Width; - case 1: // settings - Text = "SETTINGS: not yet implemented"; - break; + cp.ExStyle |= 0x00080000 | // This form has to have the WS_EX_LAYERED extended style + 0x08000000 | // WS_EX_NOACTIVATE + 0x00000080; // WS_EX_TOOLWINDOW - default: // next - NextTip(); - break; + return cp; } } - base.OnMouseClick(e); - } + protected override bool ShowWithoutActivation => true; - protected override void OnMouseDoubleClick(MouseEventArgs e) - { - if (e.Button == MouseButtons.Left) + protected override void OnLoad(EventArgs e) { - var which = e.Y / (this.Height / 3); - switch (which) - { - case 0: // close - this.Close(); - break; + var x1 = this.Height * 3 / 8; + var x2 = this.Width * 9 / 10; + var cx = x2 - x1; + var cy = this.Height; - case 1: // settings - Text = "SETTINGS: not yet implemented"; - break; + TextPos = new Point(x1, 0); + TextSize = new Size(cx, cy); + UpdateText(Text, _nonFadeTimeMs); - default: // next - NextTip(); - break; - } + base.OnLoad(e); } - base.OnMouseDoubleClick(e); - } - - private void NextTip() - { - var text = _tips?.FirstOrDefault(); - if (text == null && _getTips != null) + protected override void OnMouseMove(MouseEventArgs e) { - _tips = _getTips(); - text = _tips?.FirstOrDefault(); - } + if (e.X >= this.Width * 9 / 10) + { + UpdateText(Text); + } - Text = text ?? _defaultText; - if (text != null) _tips = _tips!.Skip(1); - } + base.OnMouseMove(e); + } - protected override void WndProc(ref Message m) - { - if (m.Msg == 0x0084 /*WM_NCHITTEST*/) + protected override void OnMouseClick(MouseEventArgs e) { - var pos = PointToClient(new Point(m.LParam.ToInt32())); - if (pos.X > this.Width * 9 / 10) + if (e.Button == MouseButtons.Left) { - m.Result = (IntPtr)1; // HTCLIENT + var which = e.Y / (this.Height / 3); + switch (which) + { + case 0: // close + this.Close(); + break; + + case 1: // settings + Text = "SETTINGS: not yet implemented"; + break; + + default: // next + NextTip(); + break; + } } - else + + base.OnMouseClick(e); + } + + protected override void OnMouseDoubleClick(MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) { - m.Result = (IntPtr)2; // HTCAPTION + var which = e.Y / (this.Height / 3); + switch (which) + { + case 0: // close + this.Close(); + break; + + case 1: // settings + Text = "SETTINGS: not yet implemented"; + break; + + default: // next + NextTip(); + break; + } } - return; + base.OnMouseDoubleClick(e); } - base.WndProc(ref m); - } - private void StartFade(int nonFadeTimeMs = 0) - { - _fadeFrame = 0; - _timer.Interval = nonFadeTimeMs > 0 ? nonFadeTimeMs : _nonFadeTimeMs; - _timer.Start(); - } - - private void timer_Tick(object sender, EventArgs e) - { - if (_lastBitmap != null) + private void NextTip() { - if (_fadeFrame == 0) + var text = _tips?.FirstOrDefault(); + if (text == null && _getTips != null) { - _timer.Stop(); - _timer.Interval = _msPerFrame; - _timer.Start(); + _tips = _getTips(); + text = _tips?.FirstOrDefault(); } - _fadeFrame++; - byte newAlpha = (byte)(_alpha * InOutQuadBlend(1.0f - (float)_fadeFrame / _fadeFrameCount)); - if (newAlpha == 0) + Text = text ?? _defaultText; + if (text != null) _tips = _tips!.Skip(1); + } + + protected override void WndProc(ref Message m) + { + if (m.Msg == 0x0084 /*WM_NCHITTEST*/) { - Close(); + var pos = PointToClient(new Point(m.LParam.ToInt32())); + if (pos.X > this.Width * 9 / 10) + { + m.Result = (IntPtr)1; // HTCLIENT + } + else + { + m.Result = (IntPtr)2; // HTCAPTION + } + return; } - - SetBitmap(new Bitmap(_lastBitmap), newAlpha); + base.WndProc(ref m); } - } - private float InOutQuadBlend(float t) - { - if (t <= 0.5f) - return 2.0f * t * t; - t -= 0.5f; - return 2.0f * t * (1.0f - t) + 0.5f; - } - - private void UpdateText(string text, int nonFadeTimeMs = 0) - { - if (this.TextSize.Height > 0) + private void StartFade(int nonFadeTimeMs = 0) { - StartFade(nonFadeTimeMs); - SetBitmap(OverlayText(text, StringAlignment.Near), _alpha); - Show(); + _fadeFrame = 0; + _timer.Interval = nonFadeTimeMs > 0 ? nonFadeTimeMs : _nonFadeTimeMs; + _timer.Start(); } - } - private Bitmap OverlayText(string text, StringAlignment alignment = StringAlignment.Center, StringAlignment lineAlignment = StringAlignment.Center) - { - var newImg = new Bitmap(this.Width, this.Height, PixelFormat.Format32bppArgb); - using (var graphics = Graphics.FromImage(newImg)) + private void timer_Tick(object sender, EventArgs e) { - graphics.SmoothingMode = SmoothingMode.AntiAlias; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.TextRenderingHint = TextRenderingHint.AntiAlias; - - DrawMainText(graphics, text, alignment, lineAlignment); - DrawButton(graphics, "🗙", 0); // "🗙" - DrawButton(graphics, "⚙", 1); - DrawButton(graphics, "🢥", 2); // "🢥" - DrawTitleText(graphics); - - return newImg; + if (_lastBitmap != null) + { + if (_fadeFrame == 0) + { + _timer.Stop(); + _timer.Interval = _msPerFrame; + _timer.Start(); + } + + _fadeFrame++; + byte newAlpha = (byte)(_alpha * InOutQuadBlend(1.0f - (float)_fadeFrame / _fadeFrameCount)); + if (newAlpha == 0) + { + Close(); + return; + } + + SetBitmap(new Bitmap(_lastBitmap), newAlpha); + } } - } - private void DrawButton(Graphics graphics, string text, int button) - { - var b = 5; - var width = this.Width; - var height = this.Height - 4 * b; - - var x = width * 9 / 10; - var y = height * button / 3; - var cx = width - x; - var cy = height / 3 + 1; - - x += b; - y += b * (button + 1); - cx -= 2 * b; - - var rect = new System.Drawing.Rectangle(x, y, cx, cy); - var mouse = PointToClient(Cursor.Position); - var inRect = rect.Contains(mouse); - - var bg = inRect - ? ColorTranslator.FromHtml(BackgroundColor4) - : ColorTranslator.FromHtml(BackgroundColor3); - var fg = inRect - ? ColorTranslator.FromHtml(FontColor4) - : ColorTranslator.FromHtml(FontColor3); - - var brush = new SolidBrush(bg); - graphics.FillRectangle(brush, rect); - - graphics.DrawString(text, - new Font(FontName3, FontSize3), - new SolidBrush(fg), - rect, - new StringFormat(StringFormatFlags.LineLimit) { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center }); - } + private float InOutQuadBlend(float t) + { + if (t <= 0.5f) + return 2.0f * t * t; + t -= 0.5f; + return 2.0f * t * (1.0f - t) + 0.5f; + } - private void DrawMainText(Graphics graphics, string text, StringAlignment alignment, StringAlignment lineAlignment) - { - var brush1 = new SolidBrush(ColorTranslator.FromHtml(BackgroundColor1)); - graphics.FillRectangle(brush1, -1, -1, this.Width + 1, this.Height + 1); + private void UpdateText(string text, int nonFadeTimeMs = 0) + { + if (this.TextSize.Height > 0) + { + StartFade(nonFadeTimeMs); + SetBitmap(OverlayText(text, StringAlignment.Near), _alpha); + Show(); + } + } - var font = new Font(FontName1, FontSize1); - while (font.Size > 8) + private Bitmap OverlayText(string text, StringAlignment alignment = StringAlignment.Center, StringAlignment lineAlignment = StringAlignment.Center) { - var check = TextRenderer.MeasureText(text, font); - if (check.Width <= TextSize.Width * 9 / 10 && check.Height < TextSize.Height) break; + var newImg = new Bitmap(this.Width, this.Height, PixelFormat.Format32bppArgb); + using (var graphics = Graphics.FromImage(newImg)) + { + graphics.SmoothingMode = SmoothingMode.AntiAlias; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.TextRenderingHint = TextRenderingHint.AntiAlias; + + DrawMainText(graphics, text, alignment, lineAlignment); + DrawButton(graphics, "🗙", 0); // "🗙" + DrawButton(graphics, "⚙", 1); + DrawButton(graphics, "🢥", 2); // "🢥" + DrawTitleText(graphics); + + return newImg; + } + } - font = new Font(FontName1, font.Size - 1); + private void DrawButton(Graphics graphics, string text, int button) + { + var b = 5; + var width = this.Width; + var height = this.Height - 4 * b; + + var x = width * 9 / 10; + var y = height * button / 3; + var cx = width - x; + var cy = height / 3 + 1; + + x += b; + y += b * (button + 1); + cx -= 2 * b; + + var rect = new System.Drawing.Rectangle(x, y, cx, cy); + var mouse = PointToClient(Cursor.Position); + var inRect = rect.Contains(mouse); + + var bg = inRect + ? ColorTranslator.FromHtml(BackgroundColor4) + : ColorTranslator.FromHtml(BackgroundColor3); + var fg = inRect + ? ColorTranslator.FromHtml(FontColor4) + : ColorTranslator.FromHtml(FontColor3); + + var brush = new SolidBrush(bg); + graphics.FillRectangle(brush, rect); + + graphics.DrawString(text, + new Font(FontName3, FontSize3), + new SolidBrush(fg), + rect, + new StringFormat(StringFormatFlags.LineLimit) { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center }); } - graphics.DrawString(text, - font, - new SolidBrush(ColorTranslator.FromHtml(FontColor1)), - new System.Drawing.Rectangle(TextPos, TextSize), - new StringFormat(StringFormatFlags.LineLimit) { Alignment = alignment, LineAlignment = lineAlignment }); - } + private void DrawMainText(Graphics graphics, string text, StringAlignment alignment, StringAlignment lineAlignment) + { + var brush1 = new SolidBrush(ColorTranslator.FromHtml(BackgroundColor1)); + graphics.FillRectangle(brush1, -1, -1, this.Width + 1, this.Height + 1); - private void DrawTitleText(Graphics graphics) - { - graphics.TranslateTransform(0, this.Height); - graphics.RotateTransform(-90); - - var rect2 = new System.Drawing.Rectangle(0, 0, this.Height, this.Height / 4 + 1); - var brush2 = new SolidBrush(ColorTranslator.FromHtml(BackgroundColor2)); - graphics.FillRectangle(brush2, rect2); - - graphics.DrawString("macaroni", - new Font(FontName2, FontSize2), - new SolidBrush(ColorTranslator.FromHtml(FontColor2)), - rect2, - new StringFormat(StringFormatFlags.LineLimit) { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center }); - } + var font = new Font(FontName1, FontSize1); + while (font.Size > 8) + { + var check = TextRenderer.MeasureText(text, font); + if (check.Width <= TextSize.Width * 9 / 10 && check.Height < TextSize.Height) break; - private void SetBitmap(Bitmap bitmap, byte opacity) - { - if (_lastBitmap != null) - { - _lastBitmap.Dispose(); - _lastBitmap = null; + font = new Font(FontName1, font.Size - 1); + } + + graphics.DrawString(text, + font, + new SolidBrush(ColorTranslator.FromHtml(FontColor1)), + new System.Drawing.Rectangle(TextPos, TextSize), + new StringFormat(StringFormatFlags.LineLimit) { Alignment = alignment, LineAlignment = lineAlignment }); } - _lastBitmap = bitmap; - if (bitmap.PixelFormat != PixelFormat.Format32bppArgb) + private void DrawTitleText(Graphics graphics) { - throw new ApplicationException("The bitmap must be 32ppp with alpha-channel."); + graphics.TranslateTransform(0, this.Height); + graphics.RotateTransform(-90); + + var rect2 = new System.Drawing.Rectangle(0, 0, this.Height, this.Height / 4 + 1); + var brush2 = new SolidBrush(ColorTranslator.FromHtml(BackgroundColor2)); + graphics.FillRectangle(brush2, rect2); + + graphics.DrawString("macaroni", + new Font(FontName2, FontSize2), + new SolidBrush(ColorTranslator.FromHtml(FontColor2)), + rect2, + new StringFormat(StringFormatFlags.LineLimit) { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center }); } - // The idea of this is very simple, - // (1) Create a compatible DC with screen; - // (2) Select the bitmap with 32bpp with alpha-channel in the compatible DC; - // (3) Call the UpdateLayeredWindow. - - var screenDc = Win32.GetDC(IntPtr.Zero); - var memDc = Win32.CreateCompatibleDC(screenDc); - var hBitmap = IntPtr.Zero; - var oldBitmap = IntPtr.Zero; - - try + private void SetBitmap(Bitmap bitmap, byte opacity) { - hBitmap = bitmap.GetHbitmap(Color.FromArgb(0)); // grab a GDI handle from this GDI+ bitmap - oldBitmap = Win32.SelectObject(memDc, hBitmap); + if (_lastBitmap != null) + { + _lastBitmap.Dispose(); + _lastBitmap = null; + } + _lastBitmap = bitmap; - var size = new Win32.Size(bitmap.Width, bitmap.Height); - var pointSource = new Win32.Point(0, 0); - var topPos = new Win32.Point(Left, Top); - var blend = new Win32.BLENDFUNCTION + if (bitmap.PixelFormat != PixelFormat.Format32bppArgb) { - BlendOp = Win32.AC_SRC_OVER, - BlendFlags = 0, - SourceConstantAlpha = opacity, - AlphaFormat = Win32.AC_SRC_ALPHA - }; + throw new ApplicationException("The bitmap must be 32ppp with alpha-channel."); + } + + // The idea of this is very simple, + // (1) Create a compatible DC with screen; + // (2) Select the bitmap with 32bpp with alpha-channel in the compatible DC; + // (3) Call the UpdateLayeredWindow. + + var screenDc = Win32.GetDC(IntPtr.Zero); + var memDc = Win32.CreateCompatibleDC(screenDc); + var hBitmap = IntPtr.Zero; + var oldBitmap = IntPtr.Zero; try { - Win32.UpdateLayeredWindow(Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, 0, ref blend, Win32.ULW_ALPHA); + hBitmap = bitmap.GetHbitmap(Color.FromArgb(0)); // grab a GDI handle from this GDI+ bitmap + oldBitmap = Win32.SelectObject(memDc, hBitmap); + + var size = new Win32.Size(bitmap.Width, bitmap.Height); + var pointSource = new Win32.Point(0, 0); + var topPos = new Win32.Point(Left, Top); + var blend = new Win32.BLENDFUNCTION + { + BlendOp = Win32.AC_SRC_OVER, + BlendFlags = 0, + SourceConstantAlpha = opacity, + AlphaFormat = Win32.AC_SRC_ALPHA + }; + + try + { + Win32.UpdateLayeredWindow(Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, 0, ref blend, Win32.ULW_ALPHA); + } + catch { } } - catch { } - } - finally - { - Win32.ReleaseDC(IntPtr.Zero, screenDc); - if (hBitmap != IntPtr.Zero) + finally { - Win32.SelectObject(memDc, oldBitmap); - Win32.DeleteObject(hBitmap); + Win32.ReleaseDC(IntPtr.Zero, screenDc); + if (hBitmap != IntPtr.Zero) + { + Win32.SelectObject(memDc, oldBitmap); + Win32.DeleteObject(hBitmap); + } + Win32.DeleteDC(memDc); } - Win32.DeleteDC(memDc); } - } - #region constants + #region constants - private const int _defaultFontSize1 = 26; - private const string _defaultFontName1 = "Tahoma"; - private const string _defaultFontColor1 = "#ffffffff"; - private const string _defaultBackgroundColor1 = "#ff000000"; - private const string _defaultText = "Tips\n\n① {ctrl-shift-space} to start/stop continuous listening\n\n② {ctrl-shift-period} to start single shot listening\n\n③ Use tray icon to return here"; + private const int _defaultFontSize1 = 26; + private const string _defaultFontName1 = "Tahoma"; + private const string _defaultFontColor1 = "#ffffffff"; + private const string _defaultBackgroundColor1 = "#ff000000"; + private const string _defaultText = "Tips\n\n① {ctrl-shift-space} to start/stop continuous listening\n\n② {ctrl-shift-period} to start single shot listening\n\n③ Use tray icon to return here"; - private const int _defaultFontSize2 = 26; - private const string _defaultFontName2 = "Tahoma"; - private const string _defaultFontColor2 = "#ffffffff"; - private const string _defaultBackgroundColor2 = "#ffffc90e"; + private const int _defaultFontSize2 = 26; + private const string _defaultFontName2 = "Tahoma"; + private const string _defaultFontColor2 = "#ffffffff"; + private const string _defaultBackgroundColor2 = "#ffffc90e"; - private const int _defaultFontSize3 = 20; - private const string _defaultFontName3 = "Segoe UI Symbol"; - private const string _defaultFontColor3 = "#ffffffff"; - private const string _defaultBackgroundColor3 = "#ff181818"; + private const int _defaultFontSize3 = 20; + private const string _defaultFontName3 = "Segoe UI Symbol"; + private const string _defaultFontColor3 = "#ffffffff"; + private const string _defaultBackgroundColor3 = "#ff181818"; - private const string _defaultFontColor4 = "#ff000000"; - private const string _defaultBackgroundColor4 = "#ffe0e0e0"; + private const string _defaultFontColor4 = "#ff000000"; + private const string _defaultBackgroundColor4 = "#ffe0e0e0"; - private const byte _alpha = 255; + private const byte _alpha = 255; - private const int _framesPerSecond = 60; - private const int _msPerFrame = 1000 / _framesPerSecond; + private const int _framesPerSecond = 60; + private const int _msPerFrame = 1000 / _framesPerSecond; - private const int _nonFadeTimeMs = 30000; - private const int _fadeTimeMs = 800; - private const float _fadeFrameCount = (float)_fadeTimeMs / _msPerFrame; - private const float _fadeAlphaPerFrame = _alpha / _fadeFrameCount; + private const int _nonFadeTimeMs = 30000; + private const int _fadeTimeMs = 800; + private const float _fadeFrameCount = (float)_fadeTimeMs / _msPerFrame; + private const float _fadeAlphaPerFrame = _alpha / _fadeFrameCount; - #endregion + #endregion - #region private data + #region private data - private int _fadeFrame = 0; - private Bitmap? _lastBitmap; - private IEnumerable? _tips; - private Func?>? _getTips; + private int _fadeFrame = 0; + private Bitmap? _lastBitmap; + private IEnumerable? _tips; + private Func?>? _getTips; - #endregion -} + #endregion + } +} \ No newline at end of file diff --git a/src/win32_ui/Ui/Controls/CustomPathButton.cs b/src/win32_ui/Ui/Controls/CustomPathButton.cs index 6779a7a8..3c0f2ea8 100644 --- a/src/win32_ui/Ui/Controls/CustomPathButton.cs +++ b/src/win32_ui/Ui/Controls/CustomPathButton.cs @@ -1,105 +1,106 @@ using System.Drawing.Drawing2D; -namespace macaroni.Ui.Controls; - -public abstract class CustomPathButton : Button +namespace macaroni.Ui.Controls { - public CustomPathButton() - { - MouseEnter += CustomRoundButton_MouseEnter; - MouseLeave += CustomRoundButton_MouseLeave; - MouseDown += CustomRoundButton_MouseDown; - MouseUp += CustomRoundButton_MouseUp; - - ButtonFaceBrush = Brushes.GhostWhite; - ButtonFaceHoverBrush = Brushes.LightGray; - ButtonFacePressedBrush = Brushes.Gray; - - ButtonOutlineBrush = Brushes.LightGray; - ButtonOutlineFocusBrush = Brushes.Gray; - } - - public Brush ButtonFaceBrush { get; set; } - public Brush ButtonFaceHoverBrush { get; set; } - public Brush ButtonFacePressedBrush { get; set; } - - public Brush ButtonOutlineBrush { get; set; } - public Brush ButtonOutlineFocusBrush { get; set; } - - protected abstract void AddCustomPath(GraphicsPath path, Rectangle rect); - - private void CustomRoundButton_MouseEnter(object? sender, EventArgs e) - { - isHovering = true; - Invalidate(); // Redraw the button - } - - private void CustomRoundButton_MouseLeave(object? sender, EventArgs e) - { - isHovering = false; - Invalidate(); // Redraw the button - } - - private void CustomRoundButton_MouseDown(object? sender, MouseEventArgs e) - { - isPressed = true; - Invalidate(); // Redraw the button - } - - private void CustomRoundButton_MouseUp(object? sender, MouseEventArgs e) + public abstract class CustomPathButton : Button { - Capture = false; - isPressed = false; - Invalidate(); // Redraw the button + public CustomPathButton() + { + MouseEnter += CustomRoundButton_MouseEnter; + MouseLeave += CustomRoundButton_MouseLeave; + MouseDown += CustomRoundButton_MouseDown; + MouseUp += CustomRoundButton_MouseUp; + + ButtonFaceBrush = Brushes.GhostWhite; + ButtonFaceHoverBrush = Brushes.LightGray; + ButtonFacePressedBrush = Brushes.Gray; + + ButtonOutlineBrush = Brushes.LightGray; + ButtonOutlineFocusBrush = Brushes.Gray; + } + + public Brush ButtonFaceBrush { get; set; } + public Brush ButtonFaceHoverBrush { get; set; } + public Brush ButtonFacePressedBrush { get; set; } + + public Brush ButtonOutlineBrush { get; set; } + public Brush ButtonOutlineFocusBrush { get; set; } + + protected abstract void AddCustomPath(GraphicsPath path, Rectangle rect); + + private void CustomRoundButton_MouseEnter(object? sender, EventArgs e) + { + isHovering = true; + Invalidate(); // Redraw the button + } + + private void CustomRoundButton_MouseLeave(object? sender, EventArgs e) + { + isHovering = false; + Invalidate(); // Redraw the button + } + + private void CustomRoundButton_MouseDown(object? sender, MouseEventArgs e) + { + isPressed = true; + Invalidate(); // Redraw the button + } + + private void CustomRoundButton_MouseUp(object? sender, MouseEventArgs e) + { + Capture = false; + isPressed = false; + Invalidate(); // Redraw the button + } + + protected override void OnCreateControl() + { + base.OnCreateControl(); + + var rect = new Rectangle(0, 0, Width, Height); + + var path = new GraphicsPath(); + AddCustomPath(path, rect); + Region = new Region(path); + + rect.Inflate(-3, -3); + + _buttonPath = new GraphicsPath(); + AddCustomPath(_buttonPath, rect); + } + + protected override void OnPaint(PaintEventArgs e) + { + // Get the Graphics object from the PaintEventArgs + Graphics g = e.Graphics; + + g.SmoothingMode = SmoothingMode.HighQuality; + g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; + g.PixelOffsetMode = PixelOffsetMode.HighQuality; + + g.Clear(Color.White); + + var fillBrush = isPressed + ? ButtonFacePressedBrush + : isHovering + ? ButtonFaceHoverBrush + : ButtonFaceBrush; + g.FillPath(fillBrush, _buttonPath!); + + var penBrush = Focused ? ButtonOutlineFocusBrush : ButtonOutlineBrush; + using var pen = new Pen(penBrush, 2); + g.DrawPath(pen, _buttonPath!); + + StringFormat fmt = new StringFormat(); + fmt.Alignment = StringAlignment.Center; + fmt.LineAlignment = StringAlignment.Center; + + var textBrush = Focused ? Brushes.Black : Brushes.Gray; + g.DrawString(Text, Font, textBrush, e.ClipRectangle, fmt); + } + + private bool isHovering; + private bool isPressed; + private GraphicsPath? _buttonPath; } - - protected override void OnCreateControl() - { - base.OnCreateControl(); - - var rect = new Rectangle(0, 0, Width, Height); - - var path = new GraphicsPath(); - AddCustomPath(path, rect); - Region = new Region(path); - - rect.Inflate(-3, -3); - - _buttonPath = new GraphicsPath(); - AddCustomPath(_buttonPath, rect); - } - - protected override void OnPaint(PaintEventArgs e) - { - // Get the Graphics object from the PaintEventArgs - Graphics g = e.Graphics; - - g.SmoothingMode = SmoothingMode.HighQuality; - g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; - g.PixelOffsetMode = PixelOffsetMode.HighQuality; - - g.Clear(Color.White); - - var fillBrush = isPressed - ? ButtonFacePressedBrush - : isHovering - ? ButtonFaceHoverBrush - : ButtonFaceBrush; - g.FillPath(fillBrush, _buttonPath!); - - var penBrush = Focused ? ButtonOutlineFocusBrush : ButtonOutlineBrush; - using var pen = new Pen(penBrush, 2); - g.DrawPath(pen, _buttonPath!); - - StringFormat fmt = new StringFormat(); - fmt.Alignment = StringAlignment.Center; - fmt.LineAlignment = StringAlignment.Center; - - var textBrush = Focused ? Brushes.Black : Brushes.Gray; - g.DrawString(Text, Font, textBrush, e.ClipRectangle, fmt); - } - - private bool isHovering; - private bool isPressed; - private GraphicsPath? _buttonPath; -} +} \ No newline at end of file diff --git a/src/win32_ui/Ui/Controls/CustomRectangleButton.cs b/src/win32_ui/Ui/Controls/CustomRectangleButton.cs index 5780012a..c9372121 100644 --- a/src/win32_ui/Ui/Controls/CustomRectangleButton.cs +++ b/src/win32_ui/Ui/Controls/CustomRectangleButton.cs @@ -1,11 +1,12 @@ using System.Drawing.Drawing2D; -namespace macaroni.Ui.Controls; - -public class CustomRectangleButton : CustomPathButton +namespace macaroni.Ui.Controls { - protected override void AddCustomPath(GraphicsPath path, Rectangle rect) + public class CustomRectangleButton : CustomPathButton { - path.AddRectangle(rect); + protected override void AddCustomPath(GraphicsPath path, Rectangle rect) + { + path.AddRectangle(rect); + } } -} +} \ No newline at end of file diff --git a/src/win32_ui/Ui/Controls/CustomRoundButton.cs b/src/win32_ui/Ui/Controls/CustomRoundButton.cs index c13f0e01..48ca36dd 100644 --- a/src/win32_ui/Ui/Controls/CustomRoundButton.cs +++ b/src/win32_ui/Ui/Controls/CustomRoundButton.cs @@ -1,14 +1,12 @@ -using System.Drawing; -using System.Drawing.Drawing2D; -using System.IO; -using static System.Net.Mime.MediaTypeNames; +using System.Drawing.Drawing2D; -namespace macaroni.Ui.Controls; - -public class CustomRoundButton : CustomPathButton +namespace macaroni.Ui.Controls { - protected override void AddCustomPath(GraphicsPath path, Rectangle rect) + public class CustomRoundButton : CustomPathButton { - path.AddEllipse(rect); + protected override void AddCustomPath(GraphicsPath path, Rectangle rect) + { + path.AddEllipse(rect); + } } -} +} \ No newline at end of file diff --git a/src/win32_ui/Ui/Controls/DoubleBufferedListBox.cs b/src/win32_ui/Ui/Controls/DoubleBufferedListBox.cs index 2d3dafc8..c6dcd3fa 100644 --- a/src/win32_ui/Ui/Controls/DoubleBufferedListBox.cs +++ b/src/win32_ui/Ui/Controls/DoubleBufferedListBox.cs @@ -1,9 +1,10 @@ -namespace macaroni.Ui.Controls; - -public class DoubleBufferedListBox : ListBox +namespace macaroni.Ui.Controls { - public DoubleBufferedListBox() + public class DoubleBufferedListBox : ListBox { - SetStyle(ControlStyles.DoubleBuffer, true); + public DoubleBufferedListBox() + { + SetStyle(ControlStyles.DoubleBuffer, true); + } } -} +} \ No newline at end of file diff --git a/src/win32_ui/Ui/ConversationDialog.cs b/src/win32_ui/Ui/ConversationDialog.cs index 8258487b..9726a355 100644 --- a/src/win32_ui/Ui/ConversationDialog.cs +++ b/src/win32_ui/Ui/ConversationDialog.cs @@ -1,330 +1,321 @@ using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Linq; -using System.Reflection; using System.Runtime.InteropServices; -using System.Threading.Tasks; -using System.Windows.Forms; -using static System.Windows.Forms.VisualStyles.VisualStyleElement; -namespace macaroni; - -public partial class ConversationDialog : Form +namespace macaroni { - public static ConversationDialog? Current; - - public static bool DisplayText(string text, string from, bool? pending, int timeout) + public partial class ConversationDialog : Form { - var cd = ConversationDialog.Current; - try + public static ConversationDialog? Current; + + public static bool DisplayText(string text, string from, bool? pending, int timeout) { - if (Current != null && Current.Visible) + var cd = ConversationDialog.Current; + try { - Current.BeginInvoke(new Action(() => - AddOrUpdateListBox(text, from, pending, Current.listBox) - )); - return true; + if (Current != null && Current.Visible) + { + Current.BeginInvoke(new Action(() => + AddOrUpdateListBox(text, from, pending, Current.listBox) + )); + return true; + } + else + { + AddOrUpdateListBox(text, from, pending, null); + } } - else + catch (Exception) { - AddOrUpdateListBox(text, from, pending, null); } - } - catch (Exception) - { - } - return false; - } + return false; + } - public ConversationDialog(IServiceProvider services) - { - _services = services; + public ConversationDialog(IServiceProvider services) + { + _services = services; - InitializeComponent(); - this.BackColor = Color.White; + InitializeComponent(); + this.BackColor = Color.White; - this.KeyPreview = true; - this.KeyDown += HandleKeyDown; + this.KeyPreview = true; + this.KeyDown += HandleKeyDown; - this.AutoScaleMode = AutoScaleMode.Dpi; - } + this.AutoScaleMode = AutoScaleMode.Dpi; + } - protected override void OnLoad(EventArgs e) - { - base.OnLoad(e); - ExtendFrameIntoClientArea(); - } + protected override void OnLoad(EventArgs e) + { + base.OnLoad(e); + ExtendFrameIntoClientArea(); + } - protected override void WndProc(ref Message m) - { - const int WM_NCPAINT = 0x0085; + protected override void WndProc(ref Message m) + { + const int WM_NCPAINT = 0x0085; - base.WndProc(ref m); + base.WndProc(ref m); - if (m.Msg == WM_NCPAINT) - { - Handle_WM_NCPAINT(); + if (m.Msg == WM_NCPAINT) + { + Handle_WM_NCPAINT(); + } } - } - private void Handle_WM_NCPAINT() - { - int isDwmEnabled = 0; - DwmIsCompositionEnabled(ref isDwmEnabled); - if (isDwmEnabled == 1) + private void Handle_WM_NCPAINT() { - using (Graphics g = Graphics.FromHwnd(this.Handle)) + int isDwmEnabled = 0; + DwmIsCompositionEnabled(ref isDwmEnabled); + if (isDwmEnabled == 1) { - g.Clear(Color.White); + using (Graphics g = Graphics.FromHwnd(this.Handle)) + { + g.Clear(Color.White); + } } } - } - private void Form_Load(object sender, EventArgs e) - { - Current?.Close(); - - _ownerDraw = new ConversationDialogListBoxOwnerDrawHelper(listBox); - CheckResizeTextBox(true); - - this.Activate(); - - listBox.Items.AddRange(_choices.ToArray()); - if (listBox.Items.Count > 0) + private void Form_Load(object sender, EventArgs e) { - listBox.SelectedIndex = listBox.Items.Count - 1; - } + Current?.Close(); - listBox.Select(); - listBox.Focus(); + _ownerDraw = new ConversationDialogListBoxOwnerDrawHelper(listBox); + CheckResizeTextBox(true); - Current = this; - } + this.Activate(); - private void TextBox_TextChanged(object sender, EventArgs e) - { - CheckResizeTextBox(); - buttonOK.Text = textBox1.Text.Length > 0 ? "⏎" : "🎙"; - } + listBox.Items.AddRange(_choices.ToArray()); + if (listBox.Items.Count > 0) + { + listBox.SelectedIndex = listBox.Items.Count - 1; + } - private void Button_Click(object sender, EventArgs e) - { - var service = _services.GetRequiredService(); + listBox.Select(); + listBox.Focus(); - var textOk = textBox1.Text.Length > 0; - if (textOk) - { - service.Emulate(textBox1.Text); + Current = this; } - else + + private void TextBox_TextChanged(object sender, EventArgs e) { - Task.Run(() => - { - var state = service.GetState(); - service.SetState(ListeningStateHelpers.ToggleState(state)); - }); + CheckResizeTextBox(); + buttonOK.Text = textBox1.Text.Length > 0 ? "⏎" : "🎙"; } - ClearTextBox(); - - if (textOk) textBox1.Focus(); - if (!textOk) buttonOK.Focus(); - } + private void Button_Click(object sender, EventArgs e) + { + var service = _services.GetRequiredService(); - private void optionsButton_Click(object sender, EventArgs e) - { - buttonOK.Focus(); + var textOk = textBox1.Text.Length > 0; + if (textOk) + { + service.Emulate(textBox1.Text); + } + else + { + Task.Run(() => + { + var state = service.GetState(); + service.SetState(ListeningStateHelpers.ToggleState(state)); + }); + } - var display = _services.GetRequiredService(); - display.DisplayTips(null, null); - } + ClearTextBox(); - private void HandleKeyDown(object? sender, KeyEventArgs e) - { - if (e.KeyCode == Keys.Escape) - { - e.Handled = HandleKey_Escape(e); - } - else if (e.KeyCode == Keys.Up && e.Modifiers == Keys.None) - { - e.Handled = HandleKey_UpArrow(e); + if (textOk) textBox1.Focus(); + if (!textOk) buttonOK.Focus(); } - else if (e.KeyCode == Keys.Down && e.Modifiers == Keys.None) - { - e.Handled = HandleKey_DownArrow(e); - } - else if (e.KeyCode == Keys.W && e.Modifiers == Keys.Control) + + private void optionsButton_Click(object sender, EventArgs e) { - e.Handled = HandleKey_Close(e); + buttonOK.Focus(); + + var display = _services.GetRequiredService(); + display.DisplayTips(null, null); } - else if (((e.KeyCode >= Keys.A && e.KeyCode <= Keys.Z) || e.KeyCode == Keys.Space) && e.Modifiers == Keys.None) + + private void HandleKeyDown(object? sender, KeyEventArgs e) { - e.Handled = HandleKey_LetterOrSpace(e); + if (e.KeyCode == Keys.Escape) + { + e.Handled = HandleKey_Escape(e); + } + else if (e.KeyCode == Keys.Up && e.Modifiers == Keys.None) + { + e.Handled = HandleKey_UpArrow(e); + } + else if (e.KeyCode == Keys.Down && e.Modifiers == Keys.None) + { + e.Handled = HandleKey_DownArrow(e); + } + else if (e.KeyCode == Keys.W && e.Modifiers == Keys.Control) + { + e.Handled = HandleKey_Close(e); + } + else if (((e.KeyCode >= Keys.A && e.KeyCode <= Keys.Z) || e.KeyCode == Keys.Space) && e.Modifiers == Keys.None) + { + e.Handled = HandleKey_LetterOrSpace(e); + } } - } - private bool HandleKey_Escape(KeyEventArgs e) - { - ClearTextBox(); - buttonOK.Focus(); - return true; - } - - private bool HandleKey_UpArrow(KeyEventArgs e) - { - if (!listBox.Focused) + private bool HandleKey_Escape(KeyEventArgs e) { - listBox.SelectedIndex = listBox.Items.Count - 1; - listBox.Focus(); + ClearTextBox(); + buttonOK.Focus(); return true; } - if (listBox.SelectedIndex == 0) + private bool HandleKey_UpArrow(KeyEventArgs e) { - textBox1.Focus(); - return true; - } + if (!listBox.Focused) + { + listBox.SelectedIndex = listBox.Items.Count - 1; + listBox.Focus(); + return true; + } - return false; - } + if (listBox.SelectedIndex == 0) + { + textBox1.Focus(); + return true; + } - private bool HandleKey_DownArrow(KeyEventArgs e) - { - if (!listBox.Focused) - { - listBox.SelectedIndex = 0; - listBox.Focus(); - return true; + return false; } - if (listBox.SelectedIndex == listBox.Items.Count - 1) + private bool HandleKey_DownArrow(KeyEventArgs e) { - textBox1.Focus(); - return true; - } + if (!listBox.Focused) + { + listBox.SelectedIndex = 0; + listBox.Focus(); + return true; + } - return false; - } + if (listBox.SelectedIndex == listBox.Items.Count - 1) + { + textBox1.Focus(); + return true; + } - private bool HandleKey_Close(KeyEventArgs e) - { - this.Close(); - return true; - } + return false; + } - private bool HandleKey_LetterOrSpace(KeyEventArgs e) - { - var moveFocus = !textBox1.Focused && (e.KeyCode != Keys.Space || listBox.Focused); - if (moveFocus) + private bool HandleKey_Close(KeyEventArgs e) { - textBox1.Focus(); + this.Close(); return true; } - return false; - } - - private static void AddOrUpdateListBox(string text, string from, bool? pending, ListBox? listBox) - { - if (pending != null && pending.Value) + private bool HandleKey_LetterOrSpace(KeyEventArgs e) { - from = from + "..."; - } + var moveFocus = !textBox1.Focused && (e.KeyCode != Keys.Space || listBox.Focused); + if (moveFocus) + { + textBox1.Focus(); + return true; + } - var updateLast = false; - var addNew = true; + return false; + } - var previous = _choices.LastOrDefault(); - if (previous != null) + private static void AddOrUpdateListBox(string text, string from, bool? pending, ListBox? listBox) { - var previousFrom = previous.Before(':'); - if (previousFrom.EndsWith("...")) + if (pending != null && pending.Value) { - updateLast = from == previousFrom || from == previousFrom.Before('.'); + from = from + "..."; } - } - text = from + ':' + text; - addNew = !updateLast && text != previous; + var updateLast = false; + var addNew = true; - var lastIndex = _choices.Count - 1; - if (updateLast) - { - _choices[lastIndex] = text; - if (listBox != null) + var previous = _choices.LastOrDefault(); + if (previous != null) { - listBox.Items[lastIndex] = text; - listBox.SelectedIndex = lastIndex; + var previousFrom = previous.Before(':'); + if (previousFrom.EndsWith("...")) + { + updateLast = from == previousFrom || from == previousFrom.Before('.'); + } } - } - else if (addNew) - { - _choices.Add(text); - if (listBox != null) + + text = from + ':' + text; + addNew = !updateLast && text != previous; + + var lastIndex = _choices.Count - 1; + if (updateLast) { - listBox.Items.Add(text); - listBox.SelectedIndex = lastIndex + 1; + _choices[lastIndex] = text; + if (listBox != null) + { + listBox.Items[lastIndex] = text; + listBox.SelectedIndex = lastIndex; + } + } + else if (addNew) + { + _choices.Add(text); + if (listBox != null) + { + listBox.Items.Add(text); + listBox.SelectedIndex = lastIndex + 1; + } } } - } - private void CheckResizeTextBox(bool updateCacheHeight = false) - { - using (Graphics g = textBox1.CreateGraphics()) + private void CheckResizeTextBox(bool updateCacheHeight = false) { - if (updateCacheHeight) + using (Graphics g = textBox1.CreateGraphics()) { - var cacheSize = g.MeasureString("a", textBox1.Font, textBox1.Width); - _cacheTextBoxHeight = (int)(Math.Ceiling(cacheSize.Height)); + if (updateCacheHeight) + { + var cacheSize = g.MeasureString("a", textBox1.Font, textBox1.Width); + _cacheTextBoxHeight = (int)(Math.Ceiling(cacheSize.Height)); + } + + var textSize = g.MeasureString(textBox1.Text, textBox1.Font, textBox1.Width); + var height = (int)Math.Ceiling(textSize.Height); + height = Math.Min(height, _cacheTextBoxHeight * 5); + height = Math.Max(height, _cacheTextBoxHeight); + textBox1.Height = height; } - - var textSize = g.MeasureString(textBox1.Text, textBox1.Font, textBox1.Width); - var height = (int)Math.Ceiling(textSize.Height); - height = Math.Min(height, _cacheTextBoxHeight * 5); - height = Math.Max(height, _cacheTextBoxHeight); - textBox1.Height = height; } - } - private void ClearTextBox() - { - textBox1.Text = ""; - CheckResizeTextBox(); - } + private void ClearTextBox() + { + textBox1.Text = ""; + CheckResizeTextBox(); + } - private void ExtendFrameIntoClientArea() - { - int isDwmEnabled = 0; - DwmIsCompositionEnabled(ref isDwmEnabled); - if (isDwmEnabled == 1) + private void ExtendFrameIntoClientArea() { - MARGINS margins = new MARGINS { cxLeftWidth = 0, cxRightWidth = 0, cyTopHeight = 1, cyBottomHeight = 0 }; - DwmExtendFrameIntoClientArea(this.Handle, ref margins); + int isDwmEnabled = 0; + DwmIsCompositionEnabled(ref isDwmEnabled); + if (isDwmEnabled == 1) + { + MARGINS margins = new MARGINS { cxLeftWidth = 0, cxRightWidth = 0, cyTopHeight = 1, cyBottomHeight = 0 }; + DwmExtendFrameIntoClientArea(this.Handle, ref margins); + } } - } - private IServiceProvider _services; - private static IList _choices = new List(); - private ConversationDialogListBoxOwnerDrawHelper? _ownerDraw; - private int _cacheTextBoxHeight; + private IServiceProvider _services; + private static IList _choices = new List(); + private ConversationDialogListBoxOwnerDrawHelper? _ownerDraw; + private int _cacheTextBoxHeight; - [DllImport("dwmapi.dll")] - public static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMarInset); + [DllImport("dwmapi.dll")] + public static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMarInset); - [DllImport("dwmapi.dll")] - public static extern int DwmIsCompositionEnabled(ref int pfEnabled); + [DllImport("dwmapi.dll")] + public static extern int DwmIsCompositionEnabled(ref int pfEnabled); - [StructLayout(LayoutKind.Sequential)] - public struct MARGINS - { - public int cxLeftWidth; - public int cxRightWidth; - public int cyTopHeight; - public int cyBottomHeight; + [StructLayout(LayoutKind.Sequential)] + public struct MARGINS + { + public int cxLeftWidth; + public int cxRightWidth; + public int cyTopHeight; + public int cyBottomHeight; + } } -} +} \ No newline at end of file diff --git a/src/win32_ui/Ui/ConversationDialogListBoxOwnerDrawHelper.cs b/src/win32_ui/Ui/ConversationDialogListBoxOwnerDrawHelper.cs index 7c0bb867..e19bf087 100644 --- a/src/win32_ui/Ui/ConversationDialogListBoxOwnerDrawHelper.cs +++ b/src/win32_ui/Ui/ConversationDialogListBoxOwnerDrawHelper.cs @@ -1,147 +1,146 @@ -using System.Drawing.Drawing2D; -using System.Linq; -using System.Windows.Forms; using macaroni.Ui.Controls; +using System.Drawing.Drawing2D; -namespace macaroni; - -public class ConversationDialogListBoxOwnerDrawHelper +namespace macaroni { - public int ItemMargin { get; private set; } - public int RectRadius { get { return ItemMargin * 2; } } - - public ConversationDialogListBoxOwnerDrawHelper(DoubleBufferedListBox listBox) - { - _listBox = listBox; - _listBox.BorderStyle = BorderStyle.None; - _listBox.DrawMode = DrawMode.OwnerDrawVariable; - _listBox.DrawItem += DrawItem; - _listBox.MeasureItem += MeasureItem; - _listBox.Resize += Resize; - this.ItemMargin = 24; - } - - private void Resize(object? sender, EventArgs e) - { - // Save the selected index and the top index - int selectedIndex = _listBox.SelectedIndex; - int topIndex = _listBox.TopIndex; - - // Suspend the ListBox layout logic - _listBox.BeginUpdate(); - - // Create a copy of the items in the ListBox - object[] items = new object[_listBox.Items.Count]; - _listBox.Items.CopyTo(items, 0); - - // Clear and re-add the items to trigger the MeasureItem event - _listBox.Items.Clear(); - _listBox.Items.AddRange(items); - - // Restore the selected index and the top index - _listBox.SelectedIndex = selectedIndex; - _listBox.TopIndex = topIndex; - - // Resume the ListBox layout logic and redraw the items - _listBox.EndUpdate(); - } - - public void Dispose() - { - _listBox.DrawItem -= DrawItem; - _listBox.MeasureItem -= MeasureItem; - } - - private void MeasureItem(object? sender, MeasureItemEventArgs e) + public class ConversationDialogListBoxOwnerDrawHelper { - if (e.Index < 0 || e.Index >= _listBox.Items.Count) - return; - - var item = _listBox.Items[e.Index].ToString(); - var from = item?.Before(':').Before('.'); - var text = item?.After(':'); - - var maxWidth = _listBox.Width - 4 * ItemMargin - RectRadius; - var size = e.Graphics.MeasureString(text, _listBox.Font, maxWidth); - - e.ItemHeight = (int)Math.Ceiling(size.Height + 2 * ItemMargin); - e.ItemWidth = (int)Math.Ceiling(size.Width + 4 * ItemMargin + RectRadius); - } + public int ItemMargin { get; private set; } + public int RectRadius { get { return ItemMargin * 2; } } - private void DrawItem(object? sender, DrawItemEventArgs e) - { - if (e.Index < 0 || e.Index >= _listBox.Items.Count) - return; + public ConversationDialogListBoxOwnerDrawHelper(DoubleBufferedListBox listBox) + { + _listBox = listBox; + _listBox.BorderStyle = BorderStyle.None; + _listBox.DrawMode = DrawMode.OwnerDrawVariable; + _listBox.DrawItem += DrawItem; + _listBox.MeasureItem += MeasureItem; + _listBox.Resize += Resize; + this.ItemMargin = 24; + } - var item = _listBox.Items[e.Index].ToString()!; - var from = item.Before(':').Before('.'); - var text = item.After(':'); + private void Resize(object? sender, EventArgs e) + { + // Save the selected index and the top index + int selectedIndex = _listBox.SelectedIndex; + int topIndex = _listBox.TopIndex; - bool isUser = from == "USER"; - bool isSelected = (e.State & DrawItemState.Selected) == DrawItemState.Selected; + // Suspend the ListBox layout logic + _listBox.BeginUpdate(); - Font font = _listBox.Font; - var bubbleBrush = isUser ? Brushes.CornflowerBlue : Brushes.GhostWhite; + // Create a copy of the items in the ListBox + object[] items = new object[_listBox.Items.Count]; + _listBox.Items.CopyTo(items, 0); - Rectangle rect = e.Bounds; - e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; - e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; - e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - e.Graphics.FillRectangle(Brushes.White, rect); + // Clear and re-add the items to trigger the MeasureItem event + _listBox.Items.Clear(); + _listBox.Items.AddRange(items); - rect.X += isUser ? ItemMargin * 2 : 0; - rect.Width -= ItemMargin * 2; + // Restore the selected index and the top index + _listBox.SelectedIndex = selectedIndex; + _listBox.TopIndex = topIndex; - var maxWidth = _listBox.Width - 4 * ItemMargin - RectRadius; - var measuredSize = e.Graphics.MeasureString(text, _listBox.Font, maxWidth); - var reduceBy = maxWidth - (int)Math.Ceiling(measuredSize.Width); - if (reduceBy > 0) - { - if (isUser) rect.X += reduceBy; - rect.Width -= reduceBy; + // Resume the ListBox layout logic and redraw the items + _listBox.EndUpdate(); } - using (var path = CreateRoundedRectangle(rect.Left, rect.Top, rect.Width, rect.Height, RectRadius, ItemMargin, ItemMargin / 2, isUser)) + public void Dispose() { - e.Graphics.FillPath(bubbleBrush, path); - using var pen = new Pen(isSelected ? Brushes.Gray : Brushes.LightGray, 1); - e.Graphics.DrawPath(pen, path); + _listBox.DrawItem -= DrawItem; + _listBox.MeasureItem -= MeasureItem; } - rect.Inflate(-ItemMargin * 3 / 2, -ItemMargin / 2); - rect.Width += 4; - - StringFormat fmt = new StringFormat(); - fmt.Alignment = StringAlignment.Near; - fmt.LineAlignment = StringAlignment.Center; + private void MeasureItem(object? sender, MeasureItemEventArgs e) + { + if (e.Index < 0 || e.Index >= _listBox.Items.Count) + return; - e.Graphics.DrawString(text, font, (isSelected || isUser) ? Brushes.Black: Brushes.Gray, rect, fmt); - } + var item = _listBox.Items[e.Index].ToString(); + var from = item?.Before(':').Before('.'); + var text = item?.After(':'); - private static GraphicsPath CreateRoundedRectangle(float x, float y, float width, float height, float radius, int paddingX, int paddingY, bool user) - { - Rectangle bounds = new Rectangle((int)x, (int)y, (int)width, (int)height); - Rectangle innerBounds = new Rectangle(bounds.X + paddingX, bounds.Y + paddingY, bounds.Width - 2 * paddingX, bounds.Height - 2 * paddingY); + var maxWidth = _listBox.Width - 4 * ItemMargin - RectRadius; + var size = e.Graphics.MeasureString(text, _listBox.Font, maxWidth); - // Create a GraphicsPath object to define the rounded rectangle - GraphicsPath path = new GraphicsPath(); - path.AddArc(innerBounds.X, innerBounds.Y, radius, radius, 180, 90); - path.AddArc(innerBounds.X + innerBounds.Width - radius, innerBounds.Y, radius, radius, 270, 90); + e.ItemHeight = (int)Math.Ceiling(size.Height + 2 * ItemMargin); + e.ItemWidth = (int)Math.Ceiling(size.Width + 4 * ItemMargin + RectRadius); + } - if (user) + private void DrawItem(object? sender, DrawItemEventArgs e) { - path.AddArc(innerBounds.X + innerBounds.Width - 1, innerBounds.Y + innerBounds.Height - 1, 1, 1, 0, 90); - path.AddArc(innerBounds.X, innerBounds.Y + innerBounds.Height - radius, radius, radius, 90, 90); + if (e.Index < 0 || e.Index >= _listBox.Items.Count) + return; + + var item = _listBox.Items[e.Index].ToString()!; + var from = item.Before(':').Before('.'); + var text = item.After(':'); + + bool isUser = from == "USER"; + bool isSelected = (e.State & DrawItemState.Selected) == DrawItemState.Selected; + + Font font = _listBox.Font; + var bubbleBrush = isUser ? Brushes.CornflowerBlue : Brushes.GhostWhite; + + Rectangle rect = e.Bounds; + e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; + e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; + e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + e.Graphics.FillRectangle(Brushes.White, rect); + + rect.X += isUser ? ItemMargin * 2 : 0; + rect.Width -= ItemMargin * 2; + + var maxWidth = _listBox.Width - 4 * ItemMargin - RectRadius; + var measuredSize = e.Graphics.MeasureString(text, _listBox.Font, maxWidth); + var reduceBy = maxWidth - (int)Math.Ceiling(measuredSize.Width); + if (reduceBy > 0) + { + if (isUser) rect.X += reduceBy; + rect.Width -= reduceBy; + } + + using (var path = CreateRoundedRectangle(rect.Left, rect.Top, rect.Width, rect.Height, RectRadius, ItemMargin, ItemMargin / 2, isUser)) + { + e.Graphics.FillPath(bubbleBrush, path); + using var pen = new Pen(isSelected ? Brushes.Gray : Brushes.LightGray, 1); + e.Graphics.DrawPath(pen, path); + } + + rect.Inflate(-ItemMargin * 3 / 2, -ItemMargin / 2); + rect.Width += 4; + + StringFormat fmt = new StringFormat(); + fmt.Alignment = StringAlignment.Near; + fmt.LineAlignment = StringAlignment.Center; + + e.Graphics.DrawString(text, font, (isSelected || isUser) ? Brushes.Black : Brushes.Gray, rect, fmt); } - else + + private static GraphicsPath CreateRoundedRectangle(float x, float y, float width, float height, float radius, int paddingX, int paddingY, bool user) { - path.AddArc(innerBounds.X + innerBounds.Width - radius, innerBounds.Y + innerBounds.Height - radius, radius, radius, 0, 90); - path.AddArc(innerBounds.X, innerBounds.Y + innerBounds.Height - 1, 1, 1, 90, 90); + Rectangle bounds = new Rectangle((int)x, (int)y, (int)width, (int)height); + Rectangle innerBounds = new Rectangle(bounds.X + paddingX, bounds.Y + paddingY, bounds.Width - 2 * paddingX, bounds.Height - 2 * paddingY); + + // Create a GraphicsPath object to define the rounded rectangle + GraphicsPath path = new GraphicsPath(); + path.AddArc(innerBounds.X, innerBounds.Y, radius, radius, 180, 90); + path.AddArc(innerBounds.X + innerBounds.Width - radius, innerBounds.Y, radius, radius, 270, 90); + + if (user) + { + path.AddArc(innerBounds.X + innerBounds.Width - 1, innerBounds.Y + innerBounds.Height - 1, 1, 1, 0, 90); + path.AddArc(innerBounds.X, innerBounds.Y + innerBounds.Height - radius, radius, radius, 90, 90); + } + else + { + path.AddArc(innerBounds.X + innerBounds.Width - radius, innerBounds.Y + innerBounds.Height - radius, radius, radius, 0, 90); + path.AddArc(innerBounds.X, innerBounds.Y + innerBounds.Height - 1, 1, 1, 90, 90); + } + + path.CloseFigure(); + return path; } - path.CloseFigure(); - return path; + private DoubleBufferedListBox _listBox; } - - private DoubleBufferedListBox _listBox; -} +} \ No newline at end of file diff --git a/src/win32_ui/Ui/Form1.cs b/src/win32_ui/Ui/Form1.cs index c7552f08..a64599ae 100644 --- a/src/win32_ui/Ui/Form1.cs +++ b/src/win32_ui/Ui/Form1.cs @@ -1,9 +1,10 @@ -namespace macaroni; - -public partial class Form1 : Form +namespace macaroni { - public Form1() + public partial class Form1 : Form { - InitializeComponent(); + public Form1() + { + InitializeComponent(); + } } -} +} \ No newline at end of file diff --git a/src/win32_ui/Ui/ListBoxDialog.cs b/src/win32_ui/Ui/ListBoxDialog.cs index eead67db..ff1a4e78 100644 --- a/src/win32_ui/Ui/ListBoxDialog.cs +++ b/src/win32_ui/Ui/ListBoxDialog.cs @@ -1,16 +1,6 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.Linq; -using System.Reflection; -using System.Threading.Tasks; -using System.Windows.Forms; -using static System.Windows.Forms.VisualStyles.VisualStyleElement; - -namespace macaroni +namespace macaroni { - public partial class ListBoxDialog : Form + public partial class ListBoxDialog : Form { public ListBoxDialog() { @@ -41,7 +31,7 @@ private void AboutBox1_Load(object sender, EventArgs e) private int IndexFromChoice(IEnumerable choices, string? choice) { - return choice != null + return choice != null ? choices.ToList().IndexOf(choice) : -1; } diff --git a/src/win32_ui/Ui/NativeMessageWindow.cs b/src/win32_ui/Ui/NativeMessageWindow.cs index 3c392985..d9f9e270 100644 --- a/src/win32_ui/Ui/NativeMessageWindow.cs +++ b/src/win32_ui/Ui/NativeMessageWindow.cs @@ -3,90 +3,91 @@ using System.Runtime.InteropServices; using System.Runtime.Versioning; -namespace macaroni; - -public class NativeMessageWindow : NativeWindow +namespace macaroni { - public NativeMessageWindow(string caption = "macaroni native message window") + public class NativeMessageWindow : NativeWindow { - _caption = caption; - } + public NativeMessageWindow(string caption = "macaroni native message window") + { + _caption = caption; + } - public bool CreateWindow() - { - if (Handle == IntPtr.Zero) + public bool CreateWindow() { - CreateHandle(new CreateParams + if (Handle == IntPtr.Zero) { - Style = 0, - ExStyle = 0, - ClassStyle = 0, - Caption = _caption, - Parent = (IntPtr)HwndMessage - }); + CreateHandle(new CreateParams + { + Style = 0, + ExStyle = 0, + ClassStyle = 0, + Caption = _caption, + Parent = (IntPtr)HwndMessage + }); + } + return Handle != IntPtr.Zero; } - return Handle != IntPtr.Zero; - } - public void DestroyWindow() - { - DestroyWindow(true, IntPtr.Zero); - } - - public override void DestroyHandle() - { - DestroyWindow(false, IntPtr.Zero); - base.DestroyHandle(); - } - - protected override void WndProc(ref Message m) - { - base.WndProc(ref m); - } + public void DestroyWindow() + { + DestroyWindow(true, IntPtr.Zero); + } - private void DestroyWindow(bool destroyHwnd, IntPtr hwnd) - { - if (hwnd == IntPtr.Zero) + public override void DestroyHandle() { - hwnd = Handle; + DestroyWindow(false, IntPtr.Zero); + base.DestroyHandle(); } - if (InvokeRequired(hwnd)) + protected override void WndProc(ref Message m) { - PostMessage(new HandleRef(this, hwnd), WmClose, 0, 0); - return; + base.WndProc(ref m); } - lock (this) + private void DestroyWindow(bool destroyHwnd, IntPtr hwnd) { - if (destroyHwnd) + if (hwnd == IntPtr.Zero) + { + hwnd = Handle; + } + + if (InvokeRequired(hwnd)) { - base.DestroyHandle(); + PostMessage(new HandleRef(this, hwnd), WmClose, 0, 0); + return; + } + + lock (this) + { + if (destroyHwnd) + { + base.DestroyHandle(); + } } } - } - private bool InvokeRequired(IntPtr hwnd) - { - if (hwnd != IntPtr.Zero) return false; + private bool InvokeRequired(IntPtr hwnd) + { + if (hwnd != IntPtr.Zero) return false; - var hwndId = GetWindowThreadProcessId(new HandleRef(this, hwnd), out int pid); - var currentId = Process.GetCurrentProcess().Id; + var hwndId = GetWindowThreadProcessId(new HandleRef(this, hwnd), out int pid); + var currentId = Process.GetCurrentProcess().Id; - return currentId != hwndId; - } + return currentId != hwndId; + } - private readonly string _caption; - private const int WmClose = 0x0010; + private readonly string _caption; + private const int WmClose = 0x0010; - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] - private static readonly HandleRef HwndMessage = new HandleRef(null, new IntPtr(-3)); + [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] + private static readonly HandleRef HwndMessage = new HandleRef(null, new IntPtr(-3)); - [DllImport("user32.dll", CharSet = CharSet.Auto)] - [ResourceExposure(ResourceScope.None)] - private static extern IntPtr PostMessage(HandleRef hwnd, int msg, int wparam, int lparam); + [DllImport("user32.dll", CharSet = CharSet.Auto)] + [ResourceExposure(ResourceScope.None)] + private static extern IntPtr PostMessage(HandleRef hwnd, int msg, int wparam, int lparam); - [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)] - [ResourceExposure(ResourceScope.Process)] - private static extern int GetWindowThreadProcessId(HandleRef hwnd, out int lpdwProcessId); -} + [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)] + [ResourceExposure(ResourceScope.Process)] + private static extern int GetWindowThreadProcessId(HandleRef hwnd, out int lpdwProcessId); + } +} \ No newline at end of file diff --git a/src/win32_ui/Ui/PromptDialog.cs b/src/win32_ui/Ui/PromptDialog.cs index 8fdecf42..3e97d662 100644 --- a/src/win32_ui/Ui/PromptDialog.cs +++ b/src/win32_ui/Ui/PromptDialog.cs @@ -1,16 +1,6 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.Linq; -using System.Reflection; -using System.Threading.Tasks; -using System.Windows.Forms; -using static System.Windows.Forms.VisualStyles.VisualStyleElement; - -namespace macaroni +namespace macaroni { - public partial class PromptDialog : Form + public partial class PromptDialog : Form { public PromptDialog() { diff --git a/src/win32_ui/Ui/WhiteCustomRectangleButton.cs b/src/win32_ui/Ui/WhiteCustomRectangleButton.cs index ccf009dd..1411de2d 100644 --- a/src/win32_ui/Ui/WhiteCustomRectangleButton.cs +++ b/src/win32_ui/Ui/WhiteCustomRectangleButton.cs @@ -1,12 +1,13 @@ using macaroni.Ui.Controls; -namespace macaroni; - -public class WhiteCustomRectangleButton : CustomRectangleButton +namespace macaroni { - public WhiteCustomRectangleButton() + public class WhiteCustomRectangleButton : CustomRectangleButton { - ButtonFaceBrush = Brushes.White; - ButtonOutlineBrush = Brushes.White; + public WhiteCustomRectangleButton() + { + ButtonFaceBrush = Brushes.White; + ButtonOutlineBrush = Brushes.White; + } } -} +} \ No newline at end of file diff --git a/src/win32_ui/Ui/interop_win32.cs b/src/win32_ui/Ui/interop_win32.cs index ccd2b93e..8c25a0c6 100644 --- a/src/win32_ui/Ui/interop_win32.cs +++ b/src/win32_ui/Ui/interop_win32.cs @@ -1,60 +1,60 @@ using System.Runtime.InteropServices; -namespace macaroni.interop; - -internal partial class Win32 +namespace macaroni.interop { - [StructLayout(LayoutKind.Sequential)] - internal struct Size + internal partial class Win32 { - internal Int32 cx; - internal Int32 cy; - internal Size(Int32 cx, Int32 cy) { this.cx = cx; this.cy = cy; } - } - - [StructLayout(LayoutKind.Sequential)] - internal struct Point - { - internal Int32 x; - internal Int32 y; - - internal Point(Int32 x, Int32 y) { this.x = x; this.y = y; } + [StructLayout(LayoutKind.Sequential)] + internal struct Size + { + internal Int32 cx; + internal Int32 cy; + internal Size(Int32 cx, Int32 cy) { this.cx = cx; this.cy = cy; } + } + + [StructLayout(LayoutKind.Sequential)] + internal struct Point + { + internal Int32 x; + internal Int32 y; + + internal Point(Int32 x, Int32 y) { this.x = x; this.y = y; } + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct BLENDFUNCTION + { + internal byte BlendOp; + internal byte BlendFlags; + internal byte SourceConstantAlpha; + internal byte AlphaFormat; + } + + internal const byte AC_SRC_OVER = 0x00; + internal const byte AC_SRC_ALPHA = 0x01; + internal const Int32 ULW_COLORKEY = 0x00000001; + internal const Int32 ULW_ALPHA = 0x00000002; + internal const Int32 ULW_OPAQUE = 0x00000004; + + [DllImport("user32.dll")] + internal static extern IntPtr GetDC(IntPtr hWnd); + + [DllImport("user32.dll", ExactSpelling = true)] + internal static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC); + + [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] + internal static extern IntPtr CreateCompatibleDC(IntPtr hDC); + + [DllImport("gdi32.dll", ExactSpelling = true)] + internal static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject); + + [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)] + internal static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, ref Point pptDst, ref Size psize, IntPtr hdcSrc, ref Point pprSrc, Int32 crKey, ref BLENDFUNCTION pblend, Int32 dwFlags); + + [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] + internal static extern bool DeleteObject(IntPtr hObject); + + [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] + internal static extern bool DeleteDC(IntPtr hdc); } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - internal struct BLENDFUNCTION - { - internal byte BlendOp; - internal byte BlendFlags; - internal byte SourceConstantAlpha; - internal byte AlphaFormat; - } - - internal const byte AC_SRC_OVER = 0x00; - internal const byte AC_SRC_ALPHA = 0x01; - internal const Int32 ULW_COLORKEY = 0x00000001; - internal const Int32 ULW_ALPHA = 0x00000002; - internal const Int32 ULW_OPAQUE = 0x00000004; - - [DllImport("user32.dll")] - internal static extern IntPtr GetDC(IntPtr hWnd); - - [DllImport("user32.dll", ExactSpelling = true)] - internal static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC); - - [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] - internal static extern IntPtr CreateCompatibleDC(IntPtr hDC); - - [DllImport("gdi32.dll", ExactSpelling = true)] - internal static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject); - - [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)] - internal static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, ref Point pptDst, ref Size psize, IntPtr hdcSrc, ref Point pprSrc, Int32 crKey, ref BLENDFUNCTION pblend, Int32 dwFlags); - - [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] - internal static extern bool DeleteObject(IntPtr hObject); - - [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] - internal static extern bool DeleteDC(IntPtr hdc); -} - +} \ No newline at end of file