Skip to content

Commit

Permalink
Merge pull request #1 from lyzerk/features/newAbstractClassImpl
Browse files Browse the repository at this point in the history
Features/new abstract class impl
  • Loading branch information
alimozdemir committed Nov 15, 2020
2 parents 1ea9832 + d74fb06 commit b76014b
Show file tree
Hide file tree
Showing 18 changed files with 249 additions and 149 deletions.
46 changes: 18 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,7 @@ PromptCLI is inspired from inquirer.js and enquirer.js. It is a interactive comm

![Basics](https://github.com/lyzerk/PromptCLI/raw/master/assets/gifs/basics.gif "Basics")

# Basics

```csharp
var prompt = new Prompt();
prompt.Add(new InputComponent("Project Name", "Project1"));
prompt.Add(new SelectComponent<string>("License Type", new List<string>() { "MIT", "Apache", "GNU" } ));
prompt.Add(new CheckboxComponent<string>("Features", new List<string>() { "Linter", "Router", "Other" }));
prompt.Add(new InputComponent("Description"));
prompt.Begin();
```

## Attributes
# Usage

```csharp
public class TestClass
Expand All @@ -37,42 +26,43 @@ public class TestClass

static void Main(string[] args)
{
var obj = new TestClass();
var prompt = new Prompt();

prompt.AddClass(obj);

prompt.Begin();
var obj = prompt.Run<TestClass>(obj);
}

```

## Without POCO class (Callback Action)

## Callback Action

You can handle callback action after each step
You can handle a callback action after each step

```csharp
var project = new Project();

var prompt = new Prompt();
prompt.Add(new InputComponent("Project Name", "Project1"))
.Callback(i => project.ProjectName = i)
.Callback(i => project.ProjectName = i)
.Add(new SelectComponent<string>("License Type", new List<string>() { "MIT", "Apache", "GNU" } ))
.Callback(i => project.License = i)
.Callback(i => project.License = i)
.Add(new CheckboxComponent<string>("Features", new List<string>() { "Linter", "Router", "Other" }))
.Callback(i => project.Features = i)
.Callback(i => project.Features = i)
.Add(new InputComponent("Description"))
.Callback(i => project.Description = i);
.Callback(i => project.Description = i);
prompt.Begin();
```

# Todo

- Unit tests
- Define data attributes for specify the components
- Linked list implementation on Prompt class
## Config

```csharp
public class PromptConfig
{
public ConsoleColor QuestionColor { get; } = ConsoleColor.Gray;
public ConsoleColor AnswerColor { get; } = ConsoleColor.Cyan;
public ConsoleColor CursorColor { get; } = ConsoleColor.Red;
public string Cursor { get; } = "> ";
}
```
# Contributions

All contributions are welcome if well described.
2 changes: 1 addition & 1 deletion src/Attributes/BaseAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public abstract class BaseAttribute : Attribute, IComponentAttribute
{
public abstract ComponentType Type { get; }
public abstract Type PropertyType { get; }
public abstract IComponent Component { get; }
public abstract ComponentBase Component { get; }

public abstract void SetCallback(PropertyInfo prop, object @class);

Expand Down
4 changes: 2 additions & 2 deletions src/Attributes/CheckboxAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public class CheckboxAttribute : BaseAttribute
{
// we need generic attribute for better support
// https://github.com/dotnet/roslyn/pull/26337
public override IComponent Component { get; }
public override ComponentBase Component { get; }
public override ComponentType Type => ComponentType.Checkbox;
public override Type PropertyType => _type;
private object _fullComponent;
Expand All @@ -27,7 +27,7 @@ public CheckboxAttribute(Type type, string text, params object[] vals)
_genericType = nonGenericType.MakeGenericType(type);

_fullComponent = Activator.CreateInstance(_genericType, input, ConvertList(vals, type));
this.Component = (IComponent)_fullComponent;
this.Component = (ComponentBase)_fullComponent;
_type = type;
}

Expand Down
2 changes: 1 addition & 1 deletion src/Attributes/IComponentAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace PromptCLI
{
public interface IComponentAttribute
{
IComponent Component { get; }
ComponentBase Component { get; }
void SetCallback(PropertyInfo prop, object @class);
}
}
2 changes: 1 addition & 1 deletion src/Attributes/InputAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace PromptCLI
public class InputAttribute : BaseAttribute
{
private InputComponent _component;
public override IComponent Component => _component;
public override ComponentBase Component => _component;
public override ComponentType Type => ComponentType.Input;
public override Type PropertyType => typeof(string);

Expand Down
4 changes: 2 additions & 2 deletions src/Attributes/SelectAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class SelectAttribute : BaseAttribute
{
// we need generic attribute for better support
// https://github.com/dotnet/roslyn/pull/26337
public override IComponent Component { get; }
public override ComponentBase Component { get; }
public override ComponentType Type => ComponentType.Select;
public override Type PropertyType => _type;
private object _fullComponent;
Expand All @@ -33,7 +33,7 @@ public SelectAttribute(Type type, string text, params object[] vals)

_fullComponent = Activator.CreateInstance(_genericType, input, ConvertList(vals, type));

this.Component = (IComponent)_fullComponent;
this.Component = (ComponentBase)_fullComponent;
_type = type;
}

Expand Down
44 changes: 24 additions & 20 deletions src/Components/CheckboxComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,20 @@

namespace PromptCLI
{
public class CheckboxComponent<T> : ComponentBase, IComponent<IEnumerable<T>>
public class CheckboxComponent<T> : ComponentBase<IEnumerable<T>>
{
private readonly Input<IEnumerable<T>> _input;
private readonly List<T> _selects;
private readonly bool[] _status;
public ComponentType ComponentType => ComponentType.Checkbox;
public Action<IEnumerable<T>> CallbackAction { get; private set; }
private Action<IEnumerable<T>> _callback;

public override ComponentType ComponentType => ComponentType.Checkbox;
public override Action<IEnumerable<T>> CallbackAction => _callback;

public Range Range => _range;

public Input<IEnumerable<T>> Result => _input;
public bool IsCompleted { get; set; }
public override Input<IEnumerable<T>> Result => _input;
public override bool IsCompleted { get; set; }


public CheckboxComponent(Input<IEnumerable<T>> input, List<T> selects, IConsoleBase console)
Expand All @@ -34,10 +36,10 @@ public CheckboxComponent(Input<IEnumerable<T>> input, List<T> selects)
}


public void Draw(bool defaultValue = true)
public override void Draw(bool defaultValue = true)
{
Console.Write(prefix, ConsoleColor.Green);
Console.WriteLine(_input.Text);
Console.Write(_config.Cursor, _config.CursorColor);
Console.WriteLine(_input.Text, _config.QuestionColor);

foreach(var item in _selects)
{
Expand All @@ -47,12 +49,15 @@ public void Draw(bool defaultValue = true)
SetPosition();
}

public void Handle(ConsoleKeyInfo act)
public override void Handle(ConsoleKeyInfo act)
{
var index = _cursorPointTop - _offsetTop - 1;
var (result, key) = IsKeyAvailable(act);
if (result == KeyInfo.Unknown)
{
ClearCurrentPosition();
// if it is checked before the the unknown char. Re-check it.
Check();
return;
}
else if (result == KeyInfo.Direction)
Expand All @@ -61,24 +66,23 @@ public void Handle(ConsoleKeyInfo act)
return;
}

var index = _cursorPointTop - _offsetTop - 1;
void Check() => WriteCurrent(_status[index] ? '•' : ' ', ConsoleColor.DarkRed);

_status[index] = !_status[index];

WriteCurrent(_status[index] ? '•' : ' ', ConsoleColor.DarkRed);
Check();
}

public void SetTopPosition(int top)
public override void SetTopPosition(int top)
{
_offsetTop = top;
_cursorPointTop = top + 1; // offset 1 for input at the begining
_cursorPointLeft = _range.Start.Value;
_maxTop = _selects.Count + 1;
}

public int GetTopPosition() => 1;
public override int GetTopPosition() => 1;

public void Complete()
public override void Complete()
{
_input.Status = _status.Select((i, index) => (status:i, index)).Where(i => i.status).Select(i => _selects[i.index]);
// Clear all drawed lines and set the cursor into component start position
Expand All @@ -92,18 +96,18 @@ public void Complete()
SetPosition();

// Write the result
Console.Write(_input.Text);
Console.Write(_input.Text, _config.QuestionColor);
Console.Write(" > ");
Console.WriteLine(string.Join(",", Result.Status), ConsoleColor.Cyan);
Console.WriteLine(string.Join(",", Result.Status), _config.AnswerColor);

CallbackAction?.Invoke(this.Result.Status);
}

public void Bind(IPrompt prompt) => _prompt = prompt;
public override void Bind(IPrompt prompt) => _prompt = prompt;

public IPrompt Callback(Action<IEnumerable<T>> callback)
public override IPrompt Callback(Action<IEnumerable<T>> callback)
{
CallbackAction = callback;
_callback = callback;
return _prompt;
}
}
Expand Down
90 changes: 74 additions & 16 deletions src/Components/ComponentBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,14 @@

namespace PromptCLI
{
public abstract class ComponentBase
public abstract class ComponentBase : IComponent
{
private readonly IConsoleBase _console;
protected const string prefix = "> ";

protected int _cursorPointLeft, _offsetLeft, _maxLeft;
protected int _cursorPointTop, _offsetTop, _maxTop;
protected string _regex;
protected Range _range;
protected IPrompt _prompt;

protected IConsoleBase Console => _console;

protected ComponentBase(): this(ConsoleBase.Default)
protected ComponentBase()
: this(ConsoleBase.Default)
{
}

Expand All @@ -25,6 +19,36 @@ protected ComponentBase(IConsoleBase console)
_console = console;
}


protected int _cursorPointLeft, _offsetLeft, _maxLeft;
protected int _cursorPointTop, _offsetTop, _maxTop;
protected string _regex;
protected Range _range;
protected IPrompt _prompt;

protected PromptConfig _config
{
get
{
// for test cases and individual uses
if (__config == null)
__config = PromptConfig.Default;

return __config;
}
set
{
__config = value;
}
}

private PromptConfig __config;

private bool topBound(int top) => top > _offsetTop && top < _offsetTop + _maxTop;
private bool leftBound(int left) => left >= _range.Start.Value && left <= _range.End.Value;
private KeyInfo isThisAvailable(char key) =>
Regex.Match(key.ToString(), _regex, RegexOptions.IgnoreCase).Success ? KeyInfo.Others : KeyInfo.Unknown;

protected void Direction(ConsoleKey key)
{
var (left, top) = (_cursorPointLeft, _cursorPointTop);
Expand All @@ -45,13 +69,6 @@ protected void Direction(ConsoleKey key)
SetPosition();
}
protected void SetPosition() => _console.SetPosition(_cursorPointLeft, _cursorPointTop);

private bool topBound(int top) => top > _offsetTop && top < _offsetTop + _maxTop;
private bool leftBound(int left) => left >= _range.Start.Value && left <= _range.End.Value;

private KeyInfo isThisAvailable(char key) =>
Regex.Match(key.ToString(), _regex, RegexOptions.IgnoreCase).Success ? KeyInfo.Others : KeyInfo.Unknown;

protected (KeyInfo, ConsoleKey) IsKeyAvailable(ConsoleKeyInfo act) =>
act.Key switch
{
Expand All @@ -69,8 +86,49 @@ act.Key switch

protected void WriteCurrent(char val, ConsoleColor? textColor = null) => _console.WritePreservePosition(val, _cursorPointLeft, _cursorPointTop, textColor);

internal void SetConfig(PromptConfig config)
{
_config = config;
}

#region Abstracts
public abstract ComponentType ComponentType { get; }

public abstract bool IsCompleted { get; set; }
public int CursorLeft => _cursorPointLeft;
public int CursorTop => _cursorPointTop;

public abstract void Complete();

public abstract void Draw(bool defaultValue = true);

public abstract int GetTopPosition();

public abstract void Handle(ConsoleKeyInfo act);

public abstract void SetTopPosition(int top);

#endregion

}

public abstract class ComponentBase<T> : ComponentBase, IComponent<T>
{
protected ComponentBase(): base(ConsoleBase.Default)
{
}

protected ComponentBase(IConsoleBase console): base(console)
{
}


public abstract Input<T> Result { get; }

public abstract Action<T> CallbackAction { get; }

public abstract void Bind(IPrompt prompt);

public abstract IPrompt Callback(Action<T> callback);
}
}
1 change: 1 addition & 0 deletions src/Components/ConsoleBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,5 +110,6 @@ public void WriteLine(string val)
{
Console.WriteLine(val);
}

}
}
2 changes: 1 addition & 1 deletion src/Components/IComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public interface IComponent

public interface IComponentPrompt<T>
{
Action<T> CallbackAction { get;}
Action<T> CallbackAction { get; }
void Bind(IPrompt prompt);
IPrompt Callback(Action<T> callback);
}
Expand Down

0 comments on commit b76014b

Please sign in to comment.