diff --git a/PowerType/BackgroundProcessing/ExecutionEngineThread.cs b/PowerType/BackgroundProcessing/ExecutionEngineThread.cs index 755cda7..75cef24 100644 --- a/PowerType/BackgroundProcessing/ExecutionEngineThread.cs +++ b/PowerType/BackgroundProcessing/ExecutionEngineThread.cs @@ -160,7 +160,7 @@ public void Dispose() if (!backgroundThread.Join(200)) { - throw new Exception("Failed to shutdown background thread!"); + //todo: log that we failed to shutdown background thread! } } } diff --git a/PowerType/DictionarySuggestor.cs b/PowerType/DictionarySuggestor.cs index 614163e..214ff59 100644 --- a/PowerType/DictionarySuggestor.cs +++ b/PowerType/DictionarySuggestor.cs @@ -1,13 +1,7 @@ using PowerType.Model; using PowerType.Parsing; -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; using System.Management.Automation.Language; using System.Management.Automation.Subsystem.Prediction; -using System.Text; -using System.Threading.Tasks; namespace PowerType; @@ -57,9 +51,6 @@ public IEnumerable GetPredictions(DictionaryParsingContext private IEnumerable Parse(IEnumerable parameters, DictionaryParsingContext context, IEnumerable additionalParameters) { - var repeat = (Parameter perfectMatch) => - Parse(parameters.Where(parameter => parameter != perfectMatch), context, additionalParameters); - var allParameters = parameters.Union(additionalParameters); if (!context.HasValue) { @@ -70,103 +61,112 @@ private IEnumerable Parse(IEnumerable parameter var perfectMatch = allParameters.FirstOrDefault(parameter => parameter.IsPerfectKeyMatch(currentArgument) && parameter.IsAvailable(context)); if (perfectMatch != null) { - if (perfectMatch is CommandParameter commandParameter) - { - var recursiveParameters = parameters.Where(x => x.Recursive).ToList(); - context.Parameters.Add(new ParameterWithValue(currentArgument, perfectMatch)); - return Parse(commandParameter.Parameters, context, additionalParameters.Union(recursiveParameters)); - } - else if (perfectMatch is ValueParameter valueParameter) + return GetPerfectMatches(parameters, context, additionalParameters, currentArgument, perfectMatch); + } + else if (context.IsLast) + { + //Check for partial matches + return GetPartialMatches(context, allParameters, currentArgument); + } + else + { + //Failed to find a match add empty to context and try again, skipping this value + context.Parameters.Add(new ParameterWithValue(currentArgument, null)); + return Parse(parameters, context, additionalParameters); + } + } + + private IEnumerable GetPerfectMatches(IEnumerable parameters, DictionaryParsingContext context, IEnumerable additionalParameters, PowerShellString currentArgument, Parameter perfectMatch) + { + var repeat = (Parameter perfectMatch) => + Parse(parameters.Where(parameter => parameter != perfectMatch), context, additionalParameters); + + if (perfectMatch is CommandParameter commandParameter) + { + var recursiveParameters = parameters.Where(x => x.Recursive).ToList(); + context.Parameters.Add(new ParameterWithValue(currentArgument, perfectMatch)); + return Parse(commandParameter.Parameters, context, additionalParameters.Union(recursiveParameters)); + } + else if (perfectMatch is ValueParameter valueParameter) + { + if (valueParameter.TryGetKeyAndValue(currentArgument, out var key, out PowerShellString value)) { - if (valueParameter.TryGetKeyAndValue(currentArgument, out var key, out PowerShellString value)) + var isDone = IsValueDone(context.IsLast, value); + context.Parameters.Add(new ParameterWithValue(key, perfectMatch) { - var isDone = IsValueDone(context.IsLast, value); - context.Parameters.Add(new ParameterWithValue(key, perfectMatch) - { - Value = !isDone ? null : value, - UsedEqualSign = true - }); - if (isDone) - { - return repeat(perfectMatch); - } - if (!context.HasValue) - { - if (valueParameter.Source != null) - { - return valueParameter.Source - .GetItems() - .Where(x => x.Name.Contains(value.RawValue, StringComparison.OrdinalIgnoreCase)) - .Select(x => new PredictiveSuggestion(context.Reconstruct(GetFromRawWithPreferredType(value.Type, x.Name)), x.Description)); - } - return Enumerable.Empty(); - } + Value = !isDone ? null : value, + UsedEqualSign = true + }); + if (isDone) + { + return repeat(perfectMatch); } - else if (context.IsLast) + if (!context.HasValue) { - context.Parameters.Add(new ParameterWithValue(currentArgument, perfectMatch)); if (valueParameter.Source != null) { - return valueParameter.Source - .GetItems() - .Select(x => new PredictiveSuggestion(context.Reconstruct(GetFromRawWithPreferredType(currentArgument.Type, x.Name)), x.Description)); + return GetPartialSourceMatches(context, valueParameter.Source, value); } return Enumerable.Empty(); } - else if (context.HasThreeOrMoreLeft) + } + else if (context.IsLast) + { + context.Parameters.Add(new ParameterWithValue(currentArgument, perfectMatch)); + return GetAllSourceMatches(context, currentArgument, valueParameter); + } + else if (context.HasThreeOrMoreLeft) + { + context.Parameters.Add(new ParameterWithValue(currentArgument, perfectMatch) { - context.Parameters.Add(new ParameterWithValue(currentArgument, perfectMatch) - { - Value = context.NextArgument - }); - } - else if (context.IsSecondLast) + Value = context.NextArgument + }); + } + else if (context.IsSecondLast) + { + var search = context.NextArgument; + var isDone = IsValueDone(true, search); + context.Parameters.Add(new ParameterWithValue(currentArgument, perfectMatch) { - var search = context.NextArgument; - var isDone = IsValueDone(true, search); - context.Parameters.Add(new ParameterWithValue(currentArgument, perfectMatch) - { - Value = !isDone ? null : search - }); - if (valueParameter.Source != null) - { - return valueParameter.Source - .GetItems() - .Where(x => x.Name.Contains(search.RawValue, StringComparison.OrdinalIgnoreCase)) - .Select(x => new PredictiveSuggestion(context.Reconstruct(GetFromRawWithPreferredType(currentArgument.Type, x.Name)), x.Description)); - } - } - else + Value = !isDone ? null : search + }); + if (valueParameter.Source != null) { - throw new InvalidOperationException(); - //context.Parameters.Add(new ParameterWithValue(currentArgument, perfectMatch)); + return GetPartialSourceMatches(context, valueParameter.Source, search); } } else { - context.Parameters.Add(new ParameterWithValue(currentArgument, perfectMatch)); + throw new InvalidOperationException(); + //context.Parameters.Add(new ParameterWithValue(currentArgument, perfectMatch)); } - //Check for more matches on same level - return repeat(perfectMatch); - } - else if (context.IsLast) - { - //Check for partial matches - return GetPartialMatches(context, allParameters, currentArgument); } else { - //Failed to find a match add empty to context and try again, skipping this value - context.Parameters.Add(new ParameterWithValue(currentArgument, null)); - return Parse(parameters, context, additionalParameters); + context.Parameters.Add(new ParameterWithValue(currentArgument, perfectMatch)); } + //Check for more matches on same level + return repeat(perfectMatch); } - private bool IsValueDone(bool isLast, PowerShellString value) + private IEnumerable GetAllSourceMatches(DictionaryParsingContext context, PowerShellString currentArgument, ValueParameter valueParameter) { - return !isLast || value.Type != StringConstantType.BareWord && value.IsEscapedOpened() && value.IsEscapedClosed(); + if (valueParameter.Source != null) + { + return valueParameter.Source + .GetItems() + .Select(x => new PredictiveSuggestion(context.Reconstruct(GetFromRawWithPreferredType(currentArgument.Type, x.Name)), x.Description)); + } + return Enumerable.Empty(); } + private IEnumerable GetPartialSourceMatches(DictionaryParsingContext context, Source source, PowerShellString value) => source + .GetItems() + .Where(x => x.Name.Contains(value.RawValue, StringComparison.OrdinalIgnoreCase)) + .Select(x => new PredictiveSuggestion(context.Reconstruct(GetFromRawWithPreferredType(value.Type, x.Name)), x.Description)); + private static bool IsValueDone(bool isLast, PowerShellString value) => + !isLast || (value.Type != StringConstantType.BareWord && value.IsEscapedOpened() && value.IsEscapedClosed()); + private IEnumerable GetPartialMatches(DictionaryParsingContext context, IEnumerable parameters, PowerShellString currentArgument) { foreach (var parameter in parameters) diff --git a/PowerType/ExecutionContext.cs b/PowerType/ExecutionContext.cs deleted file mode 100644 index 4a84155..0000000 --- a/PowerType/ExecutionContext.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.Diagnostics; -using System.Linq; -using System.Management.Automation; -using PowerType.Model; -using PowerType.Parsing; - -namespace PowerType; - -internal class ExecutionContext : IExecutionContext -{ - private readonly CommandInvocationIntrinsics commandInvocationIntrinsics; - private readonly SessionState sessionState; - - public ExecutionContext(CommandInvocationIntrinsics commandInvocationIntrinsics, SessionState sessionState) - { - this.commandInvocationIntrinsics = commandInvocationIntrinsics; - this.sessionState = sessionState; - } - - private IEnumerable ExecuteQuery(ScriptBlock scriptBlock, DictionaryParsingContext dictionaryParsingContext, Parameter parameter) - { - try - { - - var stopwatch = Stopwatch.StartNew(); - var result = scriptBlock.Invoke(); - /*var result = commandInvocationIntrinsics.InvokeScript(sessionState, scriptBlock, new - { - dictionaryParsingContext, - parameter - });*/ - //var result = commandInvocationIntrinsics.InvokeScript(true, command, new List()); - stopwatch.Stop(); - - - return result; - } - catch (Exception ex) - { - Console.WriteLine(ex.ToString()); - } - finally - { - Console.WriteLine("done"); - } - return Enumerable.Empty(); - } - - public bool GetCondition(ScriptBlock scriptBlock, DictionaryParsingContext dictionaryParsingContext, Parameter parameter) => - ExecuteQuery(scriptBlock, dictionaryParsingContext, parameter).Select(item => (bool)item.BaseObject).Single(); - - public IEnumerable GetDynamicSourceItems(ScriptBlock command, DictionaryParsingContext dictionaryParsingContext, Parameter parameter) => - ExecuteQuery(command, dictionaryParsingContext, parameter).Select(item => item.BaseObject is string ? new SourceItem { Name = (string)item.BaseObject } : (SourceItem)item.BaseObject); -} diff --git a/PowerType/Model/Parameter.cs b/PowerType/Model/Parameter.cs index b83af52..ddb33eb 100644 --- a/PowerType/Model/Parameter.cs +++ b/PowerType/Model/Parameter.cs @@ -12,6 +12,7 @@ namespace PowerType.Model; public abstract class Parameter { public List Keys { get; set; } = null!; + protected virtual bool AllowEmptyKeys => false; public string Name { get; set; } = null!; public string? Description { get; set; } public bool Recursive { get; set; } @@ -23,7 +24,7 @@ internal virtual void Initialize(ISystemTime systemTime) internal virtual void Validate() { - if (this is not ValueParameter && !HasKeys) + if (!AllowEmptyKeys && !HasKeys) { throw new Exception("Parameter must have at least one key"); } diff --git a/PowerType/Model/ValueParameter.cs b/PowerType/Model/ValueParameter.cs index 3d30a7c..d668ea0 100644 --- a/PowerType/Model/ValueParameter.cs +++ b/PowerType/Model/ValueParameter.cs @@ -4,6 +4,7 @@ namespace PowerType.Model; public class ValueParameter : Parameter { + protected override bool AllowEmptyKeys => true; public bool RequiresEqualSign { get; set; } public ParameterType? Type { get; set; } public Source? Source { get; set; } diff --git a/PowerType/PowerTypePredictor.cs b/PowerType/PowerTypePredictor.cs index d940c3a..6a2d0fe 100644 --- a/PowerType/PowerTypePredictor.cs +++ b/PowerType/PowerTypePredictor.cs @@ -143,18 +143,22 @@ private IEnumerable GetDictrionaryPredictons(PowerShellStr public void OnCommandLineAccepted(PredictionClient client, IReadOnlyList history) { + //This input is not needed } public void OnCommandLineExecuted(PredictionClient client, string commandLine, bool success) { + //This input is not needed } public void OnSuggestionAccepted(PredictionClient client, uint session, string acceptedSuggestion) { + //This input is not needed } public void OnSuggestionDisplayed(PredictionClient client, uint session, int countOrIndex) { + //This input is not needed } public void Dispose()