Skip to content

Commit

Permalink
Migrated&Improved AutoCompletion & Tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonas Kamsker committed Jul 19, 2023
1 parent 813a53c commit 8025d0a
Show file tree
Hide file tree
Showing 26 changed files with 835 additions and 5 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,5 @@ Thumbs.db

*.received.*

node_modules
node_modules
*.txt.bak
1 change: 1 addition & 0 deletions src/Spectre.Console.Cli/CommandApp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public async Task<int> RunAsync(IEnumerable<string> args)
cli.AddCommand<VersionCommand>(CliConstants.Commands.Version);
cli.AddCommand<XmlDocCommand>(CliConstants.Commands.XmlDoc);
cli.AddCommand<ExplainCommand>(CliConstants.Commands.Explain);
cli.AddCommand<CompleteCommand>(CliConstants.Commands.Complete);
});

_executed = true;
Expand Down
112 changes: 112 additions & 0 deletions src/Spectre.Console.Cli/Completion/CommandParameterMatcher.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
using System.Linq.Expressions;

namespace Spectre.Console.Cli.Completion;

/*
Usage:
return new CommandParameterMatcher<LionSettings>()
.Add(x => x.Legs, (prefix) =>
{
if (prefix.Length != 0)
{
return CompletionResult.Result(FindNextEvenNumber(prefix)).WithPreventDefault();
}
return CompletionResult.Result("16").WithPreventDefault();
})
.Add(x => x.Teeth, (prefix) =>
{
if (prefix.Length != 0)
{
return CompletionResult.Result(FindNextEvenNumber(prefix)).WithPreventDefault();
}
return CompletionResult.Result("32").WithPreventDefault();
})
.Match(parameter, prefix);
*/

public class CommandParameterMatcher<T>
where T : CommandSettings
{
private readonly List<(PropertyInfo Property, Func<string, ICompletionResult> Func)> _completers;

public CommandParameterMatcher()
{
_completers = new();
}

private CommandParameterMatcher(IEnumerable<(PropertyInfo, Func<string, ICompletionResult>)>? completers)
{
_completers = completers?.ToList() ?? new();
}

public ICompletionResult Match(ICommandParameterInfo parameter, string prefix)
{
var property = _completers.FirstOrDefault(x => x.Property.Name == parameter.PropertyName);
if (property.Property == null)
{
return CompletionResult.None();
}

return property.Func(prefix);
}

public CommandParameterMatcher<T> Add(Expression<Func<T, object>> property, Func<string, ICompletionResult> completer)
{
var parameter = PropertyOf(property);
_completers.Add((parameter, completer));
return this;
}

public static CommandParameterMatcher<T> Create(Dictionary<Expression<Func<T, object>>, Func<string, ICompletionResult>> completers)
{
var result = new List<(PropertyInfo, Func<string, ICompletionResult>)>();

foreach (var completer in completers)
{
var parameter = PropertyOf(completer.Key);
result.Add((parameter, completer.Value));
}

return new CommandParameterMatcher<T>(result);
}

// params create
public static CommandParameterMatcher<T> Create(params (Expression<Func<T, object>>, Func<string, ICompletionResult>)[] completers)
{
var result = new List<(PropertyInfo, Func<string, ICompletionResult>)>();
foreach (var (key, value) in completers)
{
var parameter = PropertyOf(key);
result.Add((parameter, value));
}

return new CommandParameterMatcher<T>(result);
}



private static PropertyInfo PropertyOf(LambdaExpression methodExpression)
{
var body = RemoveConvert(methodExpression.Body);
var prop = (MemberExpression)body;
return (PropertyInfo)prop.Member;
}

private static Expression RemoveConvert(Expression expression)
{
while (
expression != null
&& (
expression.NodeType == ExpressionType.Convert
|| expression.NodeType == ExpressionType.ConvertChecked
)
)
{
expression = RemoveConvert(((UnaryExpression)expression).Operand);
}

return expression;
}
}
65 changes: 65 additions & 0 deletions src/Spectre.Console.Cli/Completion/CompletionResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
namespace Spectre.Console.Cli.Completion;

public class CompletionResult : ICompletionResult
{
public bool PreventDefault { get; }
public IEnumerable<string> Suggestions { get; } = Enumerable.Empty<string>();

internal bool IsGenerated { get; private set; }

public CompletionResult()
{
}

public CompletionResult(IEnumerable<string> suggestions, bool preventDefault = false)
{
Suggestions = suggestions ?? throw new ArgumentNullException(nameof(suggestions));
PreventDefault = preventDefault;
}

public CompletionResult(ICompletionResult result)
{
Suggestions = result.Suggestions;
PreventDefault = result.PreventDefault;
}

public CompletionResult WithSuggestions(IEnumerable<string> suggestions)
{
return new(suggestions, PreventDefault);
}

/// <summary>
/// Disables completions, that are automatically generated
/// </summary>
/// <param name="preventDefault"></param>
/// <returns></returns>
public CompletionResult WithPreventDefault(bool preventDefault = true)
{
return new(Suggestions, preventDefault);
}

public CompletionResult WithGeneratedSuggestions()
{
return new(Suggestions, PreventDefault) { IsGenerated = true };
}

public static implicit operator CompletionResult(string[] suggestions)
{
return new(suggestions);
}

public static implicit operator CompletionResult(string suggestion)
{
return new(new[] { suggestion });
}

public static CompletionResult None()
{
return new();
}

public static CompletionResult Result(params string[] suggestions)
{
return new(suggestions);
}
}
14 changes: 14 additions & 0 deletions src/Spectre.Console.Cli/Completion/ICommandParameterCompleter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.Linq.Expressions;

namespace Spectre.Console.Cli.Completion;

public interface ICommandParameterCompleter
{
ICompletionResult GetSuggestions(ICommandParameterInfo parameter, string? prefix);
}

public interface ICompletionResult
{
bool PreventDefault { get; }
IEnumerable<string> Suggestions { get; }
}
2 changes: 1 addition & 1 deletion src/Spectre.Console.Cli/ICommandParameterInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ public interface ICommandParameterInfo
/// </summary>
/// <value>The description.</value>
public string? Description { get; }
}
}

0 comments on commit 8025d0a

Please sign in to comment.