├── assets ├── title.png ├── output.png ├── ascii-icon.png ├── example1.png ├── example2.png ├── example3.png ├── example4.png ├── example5.png ├── example6.png ├── example7.png └── ansivtconsole.netcore.widget.gif ├── AnsiVtConsole.NetCore ├── assets │ ├── title.png │ ├── example1.png │ ├── example2.png │ ├── example3.png │ ├── example4.png │ ├── example5.png │ ├── example6.png │ ├── example7.png │ ├── output.png │ ├── ascii-icon.png │ └── ansivtconsole.netcore.widget.gif ├── Component │ ├── Parser │ │ ├── NonRecursiveFunctionalGrammar │ │ │ ├── TreeNode.cs │ │ │ ├── TreePath.cs │ │ │ ├── Rule.cs │ │ │ ├── SyntacticBlockList.cs │ │ │ └── SyntacticBlock.cs │ │ └── ANSI │ │ │ ├── ANSIParser.cs │ │ │ └── ansi-seq-patterns.txt │ ├── Console │ │ ├── BufferedOperationNotAvailableException.cs │ │ ├── LineSplitList.cs │ │ ├── Color4BitMap.cs │ │ ├── Warn.cs │ │ ├── ActualWorkArea.cs │ │ ├── Error.cs │ │ ├── Inp.cs │ │ ├── EchoSequenceList.cs │ │ ├── InputMap.cs │ │ ├── StringSegment.cs │ │ ├── Cursor.cs │ │ ├── Unicode.cs │ │ ├── EchoSequence.cs │ │ ├── ASCII.cs │ │ ├── Logger.cs │ │ ├── ColorSettings.cs │ │ ├── TextColor.cs │ │ └── WorkArea.cs │ ├── Settings │ │ ├── SettingsBuilder.cs │ │ ├── WorkAreaSettings.cs │ │ └── AnsiVtConsoleSettings.cs │ ├── UI │ │ └── WorkAreaScrollEventArgs.cs │ ├── Widgets │ │ ├── IAnimatedWidget.cs │ │ ├── Animatics │ │ │ ├── Easings │ │ │ │ ├── Easing.cs │ │ │ │ └── Linear.cs │ │ │ ├── Animations │ │ │ │ └── IntAnimation.cs │ │ │ ├── AnimationGroup.cs │ │ │ ├── Animation.cs │ │ │ ├── TimeLine.cs │ │ │ ├── IAnimation.cs │ │ │ ├── Animator.cs │ │ │ └── ValueAnimation.cs │ │ ├── OptionsBuilder.cs │ │ ├── Texts │ │ │ ├── Timers │ │ │ │ ├── TimerOptionsBuilder.cs │ │ │ │ └── TextTimer.cs │ │ │ ├── TypeWriting │ │ │ │ ├── TypeWriterOptionsBuilder.cs │ │ │ │ └── TypeWriter.cs │ │ │ ├── AnimatedText.cs │ │ │ ├── Text.cs │ │ │ └── Coloring │ │ │ │ └── Gradient.cs │ │ ├── AnimatedOptionsBuilder.cs │ │ ├── Models │ │ │ └── Rgb.cs │ │ ├── IWidget.cs │ │ ├── Bars │ │ │ └── GradientBar.cs │ │ └── AnimatedWidget.cs │ ├── EchoDirective │ │ └── CommandMap.cs │ └── Script │ │ └── CSharpScriptEngine.cs ├── Lib │ ├── TargetPlatform.cs │ ├── EventArgs.cs │ ├── RuntimeEnvironment.cs │ ├── Process │ │ └── ProcessCounter.cs │ ├── StrExt.cs │ ├── TextFileReader.cs │ └── Str.cs ├── LICENSE.md └── IAnsiVtConsole.cs ├── AnsiVtConsole.NetCore.Imaging ├── assets │ ├── title.png │ ├── output.png │ ├── smiley.png │ ├── ascii-icon.png │ ├── example1.png │ ├── example2.png │ ├── example3.png │ ├── example4.png │ ├── example5.png │ ├── example6.png │ └── example7.png ├── LICENSE.md └── Component │ └── Widgets │ └── Images │ └── Image.cs ├── Examples ├── AnsiVtConsole.NetCore.Examples.Widgets │ ├── Program.cs │ ├── assets │ │ └── smiley.png │ ├── Pages │ │ ├── Images.cs │ │ ├── Intro.cs │ │ └── Title.cs │ ├── AnsiVtConsole.NetCore.Examples.Widgets.csproj │ ├── Demo.cs │ ├── LICENSE.md │ └── DemoPage.cs └── AnsiVtConsole.NetCore.Examples.ANSI │ ├── AnsiVtConsole.NetCore.Examples.ANSI.csproj │ └── LICENSE.md ├── AnsiVtConsole.NetCore.CommandLine ├── assets │ └── ascii-icon.png ├── Properties │ └── launchSettings.json ├── Program.cs ├── Config │ └── appSettings.json ├── Out.cs ├── LICENSE.md └── AnsiVtConsole.NetCore.CommandLine.csproj ├── publish-nuget.bat ├── publish-nuget-imaging.bat ├── LICENSE.md ├── .gitattributes ├── Component └── Parser │ └── ANSI │ └── ansi-seq-patterns.txt └── AnsiVtConsole.NetCore.sln /assets/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/assets/title.png -------------------------------------------------------------------------------- /assets/output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/assets/output.png -------------------------------------------------------------------------------- /assets/ascii-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/assets/ascii-icon.png -------------------------------------------------------------------------------- /assets/example1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/assets/example1.png -------------------------------------------------------------------------------- /assets/example2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/assets/example2.png -------------------------------------------------------------------------------- /assets/example3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/assets/example3.png -------------------------------------------------------------------------------- /assets/example4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/assets/example4.png -------------------------------------------------------------------------------- /assets/example5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/assets/example5.png -------------------------------------------------------------------------------- /assets/example6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/assets/example6.png -------------------------------------------------------------------------------- /assets/example7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/assets/example7.png -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/assets/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/AnsiVtConsole.NetCore/assets/title.png -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/assets/example1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/AnsiVtConsole.NetCore/assets/example1.png -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/assets/example2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/AnsiVtConsole.NetCore/assets/example2.png -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/assets/example3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/AnsiVtConsole.NetCore/assets/example3.png -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/assets/example4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/AnsiVtConsole.NetCore/assets/example4.png -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/assets/example5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/AnsiVtConsole.NetCore/assets/example5.png -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/assets/example6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/AnsiVtConsole.NetCore/assets/example6.png -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/assets/example7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/AnsiVtConsole.NetCore/assets/example7.png -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/assets/output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/AnsiVtConsole.NetCore/assets/output.png -------------------------------------------------------------------------------- /assets/ansivtconsole.netcore.widget.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/assets/ansivtconsole.netcore.widget.gif -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/assets/ascii-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/AnsiVtConsole.NetCore/assets/ascii-icon.png -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore.Imaging/assets/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/AnsiVtConsole.NetCore.Imaging/assets/title.png -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore.Imaging/assets/output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/AnsiVtConsole.NetCore.Imaging/assets/output.png -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore.Imaging/assets/smiley.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/AnsiVtConsole.NetCore.Imaging/assets/smiley.png -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore.Imaging/assets/ascii-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/AnsiVtConsole.NetCore.Imaging/assets/ascii-icon.png -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore.Imaging/assets/example1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/AnsiVtConsole.NetCore.Imaging/assets/example1.png -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore.Imaging/assets/example2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/AnsiVtConsole.NetCore.Imaging/assets/example2.png -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore.Imaging/assets/example3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/AnsiVtConsole.NetCore.Imaging/assets/example3.png -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore.Imaging/assets/example4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/AnsiVtConsole.NetCore.Imaging/assets/example4.png -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore.Imaging/assets/example5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/AnsiVtConsole.NetCore.Imaging/assets/example5.png -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore.Imaging/assets/example6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/AnsiVtConsole.NetCore.Imaging/assets/example6.png -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore.Imaging/assets/example7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/AnsiVtConsole.NetCore.Imaging/assets/example7.png -------------------------------------------------------------------------------- /Examples/AnsiVtConsole.NetCore.Examples.Widgets/Program.cs: -------------------------------------------------------------------------------- 1 | using AnsiVtConsole.NetCore.Examples.Widgets; 2 | 3 | new Demo().Run(new AnsiVtConsole.NetCore.AnsiVtConsole()); 4 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore.CommandLine/assets/ascii-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/AnsiVtConsole.NetCore.CommandLine/assets/ascii-icon.png -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/assets/ansivtconsole.netcore.widget.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/AnsiVtConsole.NetCore/assets/ansivtconsole.netcore.widget.gif -------------------------------------------------------------------------------- /Examples/AnsiVtConsole.NetCore.Examples.Widgets/assets/smiley.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/Examples/AnsiVtConsole.NetCore.Examples.Widgets/assets/smiley.png -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore.CommandLine/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "out text": { 4 | "commandName": "Project", 5 | "commandLineArgs": "out text" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Parser/NonRecursiveFunctionalGrammar/TreeNode.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franck-gaspoz/AnsiVtConsole.NetCore/HEAD/AnsiVtConsole.NetCore/Component/Parser/NonRecursiveFunctionalGrammar/TreeNode.cs -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Console/BufferedOperationNotAvailableException.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Component.Console 2 | { 3 | sealed class BufferedOperationNotAvailableException : Exception 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Settings/SettingsBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore_ConsoleApp.Component.Settings 2 | { 3 | /// 4 | /// TODO : settings builder pattern (fluent design) 5 | /// 6 | sealed class SettingsBuilder 7 | { 8 | 9 | } 10 | } -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Lib/TargetPlatform.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CS1591 2 | 3 | namespace AnsiVtConsole.NetCore.Lib 4 | { 5 | /// 6 | /// based on System.Runtime.RuntimeEnvironment 7 | /// 8 | public enum TargetPlatform 9 | { 10 | FreeBSD, 11 | Linux, 12 | OSX, 13 | Windows, 14 | Any, 15 | Unspecified 16 | } 17 | } -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/UI/WorkAreaScrollEventArgs.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CS1591 2 | 3 | namespace AnsiVtConsole.NetCore.Component.UI; 4 | 5 | public sealed class WorkAreaScrollEventArgs 6 | : EventArgs 7 | { 8 | public readonly int DeltaX; 9 | public readonly int DeltaY; 10 | 11 | public WorkAreaScrollEventArgs(int deltaX, int deltaY) 12 | { 13 | DeltaX = deltaX; 14 | DeltaY = deltaY; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Widgets/IAnimatedWidget.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Component.Widgets; 2 | 3 | /// 4 | /// widget that has a regulart threaded update 5 | /// 6 | public interface IAnimatedWidget : IWidget 7 | { 8 | /// 9 | /// frames per seconds 10 | /// 11 | double FPS { get; } 12 | 13 | /// 14 | /// is running 15 | /// 16 | bool IsRunning { get; } 17 | } -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore.CommandLine/Program.cs: -------------------------------------------------------------------------------- 1 | using CommandLine.NetCore.Services.CmdLine; 2 | 3 | namespace AnsiVtConsole.NetCore.CommandLine; 4 | 5 | /// 6 | /// main class 7 | /// 8 | public class Program 9 | { 10 | /// 11 | /// command line 12 | /// 13 | /// arguments 14 | /// exit code 15 | public static int Main(string[] args) 16 | => new CommandLineInterfaceBuilder() 17 | .Build(args) 18 | .Run(); 19 | } -------------------------------------------------------------------------------- /Examples/AnsiVtConsole.NetCore.Examples.Widgets/Pages/Images.cs: -------------------------------------------------------------------------------- 1 | using AnsiVtConsole.NetCore.Imaging.Component.Widgets.Images; 2 | 3 | namespace AnsiVtConsole.NetCore.Examples.Widgets.Pages; 4 | 5 | sealed class Images : DemoPage 6 | { 7 | public override void Run() 8 | { 9 | SubTitle("Images with AnsiVtConsole.NetCore.Imaging(br)"); 10 | 11 | var img1 = new Image("assets/smiley.png", 32, 16, false, (x, y, c) => "☻") 12 | .Add(_); 13 | 14 | _.Out.SetCursorPos(img1.Width!.Value, img1.Y); 15 | 16 | var img2 = new Image("assets/smiley.png", 16, 16) 17 | .Add(_); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Lib/EventArgs.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Lib 2 | { 3 | /// 4 | /// generic event args + IsCanceled information 5 | /// 6 | /// event arg type 7 | sealed class EventArgs : EventArgs 8 | { 9 | public T? Value { get; set; } 10 | 11 | public bool IsCanceled { get; set; } 12 | 13 | public EventArgs(T? val) => Value = val; 14 | 15 | public EventArgs() { } 16 | 17 | public void Recycle() 18 | { 19 | Value = default; 20 | IsCanceled = false; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Settings/WorkAreaSettings.cs: -------------------------------------------------------------------------------- 1 | using AnsiVtConsole.NetCore.Component.UI; 2 | 3 | namespace AnsiVtConsole.NetCore.Component.Settings; 4 | 5 | /// 6 | /// work area settings 7 | /// 8 | public sealed class WorkAreaSettings 9 | { 10 | #pragma warning disable CS1591 11 | public EventHandler? ViewSizeChanged { get; set; } 12 | 13 | public EventHandler? WorkAreaScrolled { get; set; } 14 | 15 | public bool EnableConstraintConsolePrintInsideWorkArea { get; set; } = false; 16 | 17 | public bool RedrawUIElementsEnabled = true; 18 | 19 | #pragma warning restore CS1591 20 | } 21 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore.CommandLine/Config/appSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Microsoft.Hosting.Lifetime": "Error" 5 | } 6 | }, 7 | "App": { 8 | "Title": "out", 9 | "ReleaseDate": "01/12/2023" 10 | }, 11 | "Commands": { 12 | "out": { 13 | "Description": "output a text using AinsiVtConsole. Enable ansi markup and ansi vt sequences", 14 | "Syntax": { 15 | "text": "text" 16 | }, 17 | "Options": { 18 | "--raw": "get the raw text showing non printable characters", 19 | "--err": "output to the error stream instead of the standard output stream" 20 | } 21 | } 22 | }, 23 | "GlobalOptions": { 24 | 25 | } 26 | } -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Widgets/Animatics/Easings/Easing.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Component.Widgets.Animatics.Easings; 2 | 3 | /// 4 | /// easing function 5 | /// 6 | public abstract class Easing 7 | { 8 | /// 9 | /// get the time line position ratio from begin to end according to the easing function 10 | /// 11 | /// animation 12 | /// progress 13 | /// fps 14 | /// the value 15 | public abstract double GetPosition( 16 | ValueAnimation animation, 17 | double progress, 18 | double fps); 19 | } 20 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Widgets/Animatics/Easings/Linear.cs: -------------------------------------------------------------------------------- 1 | #define dbg 2 | 3 | namespace AnsiVtConsole.NetCore.Component.Widgets.Animatics.Easings; 4 | 5 | /// 6 | /// linear easing function 7 | /// 8 | public class Linear : Easing 9 | { 10 | /// 11 | public override double GetPosition( 12 | ValueAnimation animation, 13 | double progress, 14 | double fps) 15 | { 16 | var position = Math.Max( 17 | 1, 18 | progress / animation.Duration); 19 | 20 | #if dbg 21 | System.Diagnostics.Debug.WriteLine($"easing {GetType().Name} : position = {position}"); 22 | #endif 23 | return position; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Console/LineSplitList.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Component.Console 2 | { 3 | sealed class LineSplitList 4 | { 5 | public readonly List Splits; 6 | 7 | public readonly EchoSequenceList? PrintSequences; 8 | 9 | public readonly int CursorIndex; 10 | 11 | public readonly int CursorLineIndex; 12 | 13 | public LineSplitList( 14 | List splits, 15 | EchoSequenceList? printSequences, 16 | int cursorIndex = -1, 17 | int cursorLineIndex = -1) 18 | { 19 | Splits = splits; 20 | PrintSequences = printSequences; 21 | CursorIndex = cursorIndex; 22 | CursorLineIndex = cursorLineIndex; 23 | } 24 | 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/EchoDirective/CommandMap.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Component.EchoDirective 2 | { 3 | /// 4 | /// these map attribute a echo command delegate to an echo directive syntax 5 | /// 6 | sealed class CommandMap 7 | { 8 | public Dictionary< 9 | string, 10 | (EchoDirectiveProcessor.SimpleCommandDelegate? simpleCommand, 11 | EchoDirectiveProcessor.CommandDelegate? command, 12 | object? parameter)>? Map; 13 | 14 | public CommandMap(Dictionary< 15 | string, 16 | (EchoDirectiveProcessor.SimpleCommandDelegate? simpleCommand, 17 | EchoDirectiveProcessor.CommandDelegate? command, 18 | object? parameter)> map) 19 | => Map = map; 20 | 21 | } 22 | } -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Widgets/OptionsBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Component.Widgets; 2 | 3 | /// 4 | /// generic option builder 5 | /// 6 | /// type of builded widget 7 | public class OptionsBuilder 8 | where T : class, IWidget 9 | { 10 | /// 11 | /// builded widget 12 | /// 13 | public T Widget { get; protected set; } 14 | 15 | /// 16 | /// type writer options builder 17 | /// 18 | /// widget 19 | public OptionsBuilder(T widget) 20 | => Widget = widget; 21 | 22 | /// 23 | /// build the configured object 24 | /// 25 | /// the configured object 26 | public T Build() => Widget; 27 | } 28 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Parser/NonRecursiveFunctionalGrammar/TreePath.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CS1591 2 | 3 | namespace AnsiVtConsole.NetCore.Component.Parser.NonRecursiveFunctionalGrammar 4 | { 5 | public sealed class TreePath : List 6 | { 7 | public Rule? Rule; 8 | 9 | public int Index; 10 | 11 | public TreePath(Rule? rule, int index) 12 | { 13 | Rule = rule; 14 | Index = index; 15 | } 16 | 17 | public TreePath(Rule? rule, int index, IEnumerable o) : base(o) 18 | { 19 | Rule = rule; 20 | Index = index; 21 | } 22 | 23 | public override string ToString() => $"<#{Rule?.ID}> " + string.Join(' ', this.Select(x => x.Label)); 24 | 25 | public string Key => string.Join('-', this.Select(x => x.ID)); 26 | } 27 | } -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Console/Color4BitMap.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CS1591 2 | 3 | namespace AnsiVtConsole.NetCore.Component.Console 4 | { 5 | /// 6 | /// 4 bits colors map - see https://en.wikipedia.org/wiki/ANSI_escape_code#3-bit_and_4-bit 7 | /// 8 | public enum Color4BitMap 9 | { 10 | // 3 bits 11 | 12 | darkgray = 0b0, 13 | gray = 0b1111, 14 | red = 0b1, 15 | green = 0b10, 16 | yellow = 0b11, 17 | blue = 0b100, 18 | magenta = 0b101, 19 | cyan = 0b110, 20 | white = 0b111, 21 | 22 | // 4 bits 23 | 24 | black = 0b1000, 25 | darkred = 0b1001, 26 | darkgreen = 0b1010, 27 | darkyellow = 0b1011, 28 | darkblue = 0b1100, 29 | darkmagenta = 0b1101, 30 | darkcyan = 0b1110, 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Widgets/Texts/Timers/TimerOptionsBuilder.cs: -------------------------------------------------------------------------------- 1 | using AnsiVtConsole.NetCore.Component.Widgets.Texts.Timers; 2 | 3 | namespace AnsiVtConsole.NetCore.Component.Widgets; 4 | 5 | /// 6 | /// timer option builder 7 | /// 8 | public class TimerOptionsBuilder : OptionsBuilder 9 | { 10 | /// 11 | /// type writer options builder 12 | /// 13 | /// widget 14 | public TimerOptionsBuilder(TextTimer widget) 15 | : base(widget) { } 16 | 17 | /// 18 | /// set the pattern (allowed while running) 19 | /// 20 | /// pattern 21 | /// this object 22 | public TextTimer Pattern(string pattern) 23 | { 24 | Widget.SetPattern(pattern); 25 | return Widget; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Widgets/AnimatedOptionsBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Component.Widgets; 2 | 3 | /// 4 | /// generic option builder 5 | /// 6 | /// type of builded widget 7 | public class AnimatedOptionsBuilder : OptionsBuilder 8 | where T : class, IAnimatedWidget 9 | { 10 | /// 11 | /// type writer options builder 12 | /// 13 | /// widget 14 | public AnimatedOptionsBuilder(T widget) 15 | : base(widget) { } 16 | 17 | /// 18 | /// fps 19 | /// 20 | /// fps 21 | /// this object 22 | public AnimatedOptionsBuilder Fps(double fps) 23 | { 24 | var o = Widget as AnimatedWidget>; 25 | o!.SetFPS(fps); 26 | return this; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /publish-nuget.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | cls 3 | echo -------------------------------------------------------------------------------------- 4 | echo publish-nuget 5 | echo -------------------------------------------------------------------------------------- 6 | echo tag the version and publish the corresponding nuget from version to github and nuget 7 | echo parameter: version tag 8 | echo example: publish-nuget 1.0.15 9 | echo nugetkey=%nugetkey% 10 | echo githubkey=%githubkey% 11 | echo version=%1 12 | echo -------------------------------------------------------------------------------------- 13 | 14 | git tag -a v%1 -m v%1 15 | git push origin v%1 16 | nuget push AnsiVtConsole.NetCore/bin/Release/AnsiVtConsole.NetCore.%1.nupkg %nugetkey% -SkipDuplicate -Source https://api.nuget.org/v3/index.json -Verbosity detailed 17 | dotnet nuget push "AnsiVtConsole.NetCore/bin/Release/AnsiVtConsole.NetCore.%1.nupkg" --skip-duplicate --api-key %githubkey% --source "github" 18 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Lib/RuntimeEnvironment.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CS1591 2 | 3 | using System.Runtime.InteropServices; 4 | 5 | namespace AnsiVtConsole.NetCore.Lib 6 | { 7 | public static class RuntimeEnvironment 8 | { 9 | public static OSPlatform? OSType 10 | { 11 | get 12 | { 13 | OSPlatform? oSPlatform = null; 14 | if (RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD)) 15 | oSPlatform = OSPlatform.FreeBSD; 16 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) 17 | oSPlatform = OSPlatform.Windows; 18 | if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) 19 | oSPlatform = OSPlatform.OSX; 20 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) 21 | oSPlatform = OSPlatform.Linux; 22 | return oSPlatform; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /publish-nuget-imaging.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | cls 3 | echo -------------------------------------------------------------------------------------- 4 | echo publish-nuget 5 | echo -------------------------------------------------------------------------------------- 6 | echo tag the version and publish the corresponding nuget from version to github and nuget 7 | echo parameter: version tag 8 | echo example: publish-nuget 1.0.15 9 | echo nugetkey=%nugetkey% 10 | echo githubkey=%githubkey% 11 | echo version=%1 12 | echo -------------------------------------------------------------------------------------- 13 | 14 | rem git tag -a v%1 -m v%1 15 | rem git push origin v%1 16 | nuget push AnsiVtConsole.NetCore.Imaging/bin/Release/AnsiVtConsole.NetCore.Imaging.%1.nupkg %nugetkey% -SkipDuplicate -Source https://api.nuget.org/v3/index.json -Verbosity detailed 17 | dotnet nuget push "AnsiVtConsole.NetCore.Imaging/bin/Release/AnsiVtConsole.NetCore.Imaging.%1.nupkg" --skip-duplicate --api-key %githubkey% --source "github" 18 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Console/Warn.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Component.Console; 2 | 3 | class Warn 4 | { 5 | readonly ConsoleTextWriterWrapper _out; 6 | readonly Error _err; 7 | 8 | public Warn( 9 | ConsoleTextWriterWrapper outStream, 10 | Error err) 11 | { 12 | _out = outStream; 13 | _err = err; 14 | } 15 | 16 | public void Log(string text = "") => LogInternal(text, false); 17 | 18 | public void LogLine(string text = "") => LogInternal(text, true); 19 | 20 | public void LogLine(IEnumerable texts) 21 | { 22 | foreach (var s in texts) 23 | _err.LogLine(s); 24 | } 25 | 26 | public void Log(IEnumerable texts) 27 | { 28 | foreach (var s in texts) 29 | _err.Log(s); 30 | } 31 | 32 | void LogInternal(string text, bool lineBreak = false) 33 | { 34 | lock (_out.Lock!) 35 | { 36 | _out.Write(text, lineBreak); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Examples/AnsiVtConsole.NetCore.Examples.ANSI/AnsiVtConsole.NetCore.Examples.ANSI.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 1.0.21.0 9 | 1.0.21.0 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | contentFiles/any/;content/ 25 | PreserveNewest 26 | true 27 | True 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Console/ActualWorkArea.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CS1591 2 | 3 | namespace AnsiVtConsole.NetCore.Component.Console 4 | { 5 | /// 6 | /// acutal work area 7 | /// 8 | public sealed class ActualWorkArea 9 | { 10 | public readonly string Id; 11 | public readonly int Left; 12 | public readonly int Top; 13 | public readonly int Right; 14 | public readonly int Bottom; 15 | 16 | public ActualWorkArea(string id, int left, int top, int right, int bottom) 17 | { 18 | Id = id; 19 | Left = left; 20 | Right = right; 21 | Top = top; 22 | Bottom = bottom; 23 | } 24 | 25 | public void Deconstruct(out string id, out int left, out int top, out int right, out int bottom) 26 | { 27 | id = Id; 28 | left = Left; 29 | right = Right; 30 | top = Top; 31 | bottom = Bottom; 32 | } 33 | } 34 | } 35 | #pragma warning restore CS1591 -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Console/Error.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Component.Console; 2 | 3 | sealed class Error 4 | { 5 | readonly ConsoleTextWriterWrapper _out; 6 | 7 | public Error(ConsoleTextWriterWrapper outStream) 8 | => _out = outStream; 9 | 10 | public void Log(string text = "") => LogInternal(text, false); 11 | 12 | public void LogLine(string text = "") => LogInternal(text, true); 13 | 14 | public void LogLine(IEnumerable texts) 15 | { 16 | foreach (var s in texts) 17 | LogLine(s); 18 | } 19 | 20 | public void Log(IEnumerable texts) 21 | { 22 | foreach (var s in texts) 23 | Log(s); 24 | } 25 | 26 | void LogInternal(string text, bool lineBreak = false) 27 | { 28 | lock (_out.Lock!) 29 | { 30 | _out.RedirectToErr = true; 31 | if (!lineBreak) 32 | _out.Write(text); 33 | else 34 | _out.WriteLine(text); 35 | _out.RedirectToErr = false; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Parser/NonRecursiveFunctionalGrammar/Rule.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Component.Parser.NonRecursiveFunctionalGrammar 2 | { 3 | /// 4 | /// rule 5 | /// 6 | public sealed class Rule : List 7 | { 8 | static int _counter = 0; 9 | static readonly object _counterLock = new(); 10 | #pragma warning disable CS1591 11 | public int ID; 12 | 13 | public TreePath TreePath; 14 | 15 | public string Key => TreePath.Key; 16 | 17 | #pragma warning disable CS8618 18 | public Rule() => Init(); 19 | #pragma warning restore CS8618 20 | 21 | #pragma warning disable CS8618 22 | public Rule(IEnumerable range) : base(range) => Init(); 23 | #pragma warning restore CS8618 24 | #pragma warning restore CS1591 25 | 26 | void Init() 27 | { 28 | TreePath = new TreePath(this, -1); 29 | lock (_counterLock) 30 | { 31 | ID = _counter; 32 | _counter++; 33 | } 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Parser/NonRecursiveFunctionalGrammar/SyntacticBlockList.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CS1591 2 | 3 | namespace AnsiVtConsole.NetCore.Component.Parser.NonRecursiveFunctionalGrammar 4 | { 5 | public sealed class SyntacticBlockList : List 6 | { 7 | public bool IsSelected; 8 | 9 | public SyntacticBlockList Clone() 10 | { 11 | var r = new SyntacticBlockList(); 12 | r.AddRange(this); 13 | r.IsSelected = IsSelected; 14 | return r; 15 | } 16 | 17 | /// 18 | /// get the real length of the text without ansi sequences non printed characters 19 | /// 20 | /// length of visible part of the text 21 | public int GetTextLength() => GetText().Length; 22 | 23 | /// 24 | /// gets the text part of the syntactic elements 25 | /// 26 | /// string without ansi sequences 27 | public string GetText() => string.Join("", this.Where(x => !x.IsANSISequence).Select(x => x.Text)); 28 | } 29 | } -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Parser/NonRecursiveFunctionalGrammar/SyntacticBlock.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CS1591 2 | 3 | using AnsiVtConsole.NetCore.Component.Console; 4 | 5 | namespace AnsiVtConsole.NetCore.Component.Parser.NonRecursiveFunctionalGrammar 6 | { 7 | public sealed class SyntacticBlock 8 | { 9 | public string Text; 10 | 11 | public int Index; 12 | 13 | public TreePath? SyntacticRule; 14 | 15 | public bool IsSelected; 16 | 17 | public bool IsANSISequence; 18 | 19 | public SyntacticBlock( 20 | int index, 21 | TreePath? syntacticRule, 22 | string text, 23 | bool isSelected = false, 24 | bool isANSISequence = true) 25 | { 26 | Index = index; 27 | SyntacticRule = syntacticRule; 28 | Text = text; 29 | IsSelected = isSelected; 30 | IsANSISequence = isANSISequence; 31 | } 32 | 33 | public override string ToString() => $"{Index}->{Index + Text.Length - 1} : \"{ASCII.GetNonPrintablesCodesAsLabel(Text, false)}\" == {SyntacticRule}"; 34 | } 35 | } -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Widgets/Texts/TypeWriting/TypeWriterOptionsBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Component.Widgets.Texts.TypeWriting; 2 | 3 | /// 4 | /// type options writer builder 5 | /// 6 | public sealed class TypeWriterOptionsBuilder : AnimatedOptionsBuilder 7 | { 8 | /// 9 | /// type writer options builder 10 | /// 11 | /// type writer 12 | public TypeWriterOptionsBuilder(TypeWriter typeWriter) 13 | : base(typeWriter) { } 14 | 15 | /// 16 | /// cursor 17 | /// 18 | /// cursor 19 | /// this object 20 | public TypeWriterOptionsBuilder Cursor(string cursor) 21 | { 22 | Widget.SetCursor(cursor); 23 | return this; 24 | } 25 | 26 | /// 27 | /// text 28 | /// 29 | /// text 30 | /// this object 31 | public TypeWriterOptionsBuilder Text(string text) 32 | { 33 | Widget.SetText(text); 34 | return this; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Examples/AnsiVtConsole.NetCore.Examples.Widgets/AnsiVtConsole.NetCore.Examples.Widgets.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 1.0.21.0 9 | 1.0.21.0 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | contentFiles/any/;content/ 26 | PreserveNewest 27 | true 28 | True 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Widgets/Animatics/Animations/IntAnimation.cs: -------------------------------------------------------------------------------- 1 | using AnsiVtConsole.NetCore.Component.Widgets.Animatics.Easings; 2 | 3 | namespace AnsiVtConsole.NetCore.Component.Widgets.Animatics.Animations; 4 | 5 | /// 6 | /// int animation 7 | /// 8 | public sealed class IntAnimation : ValueAnimation 9 | { 10 | /// 11 | public IntAnimation( 12 | int from, 13 | int to, 14 | double duration, 15 | int increment = 1, 16 | Easing? easing = null) : base(from, to, duration, increment, easing) { } 17 | 18 | /// 19 | public IntAnimation( 20 | int to, 21 | double duration, 22 | int increment = 1, 23 | Easing? easing = null) : base(to, duration, increment, easing) { } 24 | 25 | /// 26 | public override void SetValueAt(double position) 27 | { 28 | var value = Math.Min( 29 | Math.Max(From, To), 30 | Math.Abs(To - From) 31 | * (position / Duration) 32 | + Math.Min(From, To) 33 | ); 34 | 35 | var intValue = (int)Math.Max( 36 | Math.Min(From, To), 37 | value 38 | ); 39 | 40 | SetValue(intValue); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Console/Inp.cs: -------------------------------------------------------------------------------- 1 | using sc = System.Console; 2 | 3 | namespace AnsiVtConsole.NetCore.Component.Console; 4 | 5 | /// 6 | /// input prompter 7 | /// 8 | public class Inp 9 | { 10 | readonly ConsoleTextWriterWrapper _out; 11 | 12 | /// 13 | /// output stream to be used for the prompt 14 | /// 15 | /// a console text writer 16 | public Inp(ConsoleTextWriterWrapper @out) => _out = @out; 17 | 18 | /// 19 | /// display a prompt and read a line from standard input 20 | /// 21 | /// prompt 22 | /// inputed line if any 23 | public string? Readln(string? prompt = null) 24 | { 25 | lock (_out.Lock!) 26 | { 27 | if (prompt != null) 28 | _out.Write(prompt); 29 | } 30 | return sc.ReadLine(); 31 | } 32 | 33 | /// 34 | /// wait for a key to be pressed 35 | /// 36 | /// a prompt message or default if omitted 37 | public void WaitKeyPress(string? prompt = "press a key to continue...") 38 | { 39 | _out.WriteLine(prompt!); 40 | while (!sc.KeyAvailable) 41 | Thread.Yield(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore.CommandLine/Out.cs: -------------------------------------------------------------------------------- 1 | 2 | using CommandLine.NetCore.Services.CmdLine.Arguments; 3 | using CommandLine.NetCore.Services.CmdLine.Commands; 4 | 5 | namespace AnsiVtConsole.NetCore.CommandLine; 6 | 7 | class Out : Command 8 | { 9 | public Out(Dependencies dependencies) : base(dependencies) 10 | { 11 | } 12 | 13 | protected override CommandResult Execute(ArgSet args) => 14 | 15 | // echo [--err] 16 | 17 | For(Param()) 18 | .Do(() => OutAnsi) 19 | 20 | // echo --raw [--esc-only] [--hexa] [--err] 21 | 22 | .For(Param(), Opt("raw"), Opt("esc-only", true), Opt("hexa", true)) 23 | .Do(() => OutRaw) 24 | 25 | .Options(Opt("err")) 26 | 27 | .With(args); 28 | 29 | 30 | void OutAnsi(Param textParam, Opt errOpt) 31 | => DoOut(textParam.Value!, errOpt.IsSet, false, false, false); 32 | 33 | void OutRaw(Param textParam, Opt errOpt, Opt escOpt, Opt hexaOpt) 34 | => DoOut(textParam.Value!, errOpt.IsSet, true, escOpt.IsSet, hexaOpt.IsSet); 35 | 36 | void DoOut(string text, bool err, bool raw, bool esc, bool hexa) 37 | { 38 | var console = new AnsiVtConsole(); 39 | 40 | if (raw) 41 | text = console.Out.GetRawText(text, esc, hexa); 42 | 43 | if (!err) 44 | console.Out.WriteLine(text); 45 | else 46 | console.Logger.LogError(text); 47 | } 48 | } -------------------------------------------------------------------------------- /Examples/AnsiVtConsole.NetCore.Examples.Widgets/Pages/Intro.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Examples.Widgets.Pages; 2 | 3 | sealed class Intro : DemoPage 4 | { 5 | public override void Run() 6 | { 7 | TypeWriter("Welcome to the demonstration program of AnsiVtCore.NetCore") 8 | .Add(_) 9 | .Wait() 10 | .Wait(500); 11 | 12 | _.Out.WriteLine(); 13 | 14 | TypeWrite("This program show examples of using (bon,b=green,f=white)WIDGETS components(tdoff)"); 15 | 16 | _.Out.WriteLine(); 17 | 18 | TypeWrite("Widgets are elements drawn on console with:(br)"); 19 | 20 | _.Out.WriteLine(); 21 | 22 | var dot = "(f=yellow)►(f=white)"; 23 | TypeWrite($" {dot} live update"); 24 | TypeWrite($" {dot} ANSI markup and sequences"); 25 | TypeWrite($" {dot} animations"); 26 | TypeWrite($" {dot} functionalities"); 27 | 28 | _.Out.WriteLine(); 29 | 30 | var remCol = "(tdoff,f=darkcyan)"; 31 | var higCol = "(uon,bon,f=magenta)"; 32 | TypeWrite($"{remCol}░ Widgets are composable together and the {higCol}Animator{remCol} class can animate any of their properties"); 33 | TypeWrite($"{remCol}░ Widgets mecanism is {higCol}thread safe{remCol} thus several widgets can play simultaneously"); 34 | 35 | _.Out.WriteLine().WriteLine(); 36 | 37 | TypeWrite("░ this demo will auto play, juste have a seat and watch. Let's go now"); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Console/EchoSequenceList.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CS1591 2 | 3 | using System.Collections; 4 | using System.Text; 5 | 6 | namespace AnsiVtConsole.NetCore.Component.Console 7 | { 8 | public sealed class EchoSequenceList : IEnumerable 9 | { 10 | public readonly List List 11 | = new(); 12 | 13 | public void Add(EchoSequence printSequence) => List.Add(printSequence); 14 | 15 | public override string ToString() 16 | { 17 | var r = new StringBuilder(); 18 | foreach (var printSequence in List) 19 | r.AppendLine(printSequence.ToString()); 20 | return r.ToString(); 21 | } 22 | 23 | public string ToStringPattern() 24 | { 25 | var r = new StringBuilder(); 26 | foreach (var printSequence in List) 27 | r.Append(printSequence.ToStringPattern()); 28 | return r.ToString(); 29 | } 30 | 31 | public IEnumerator GetEnumerator() => List.GetEnumerator(); 32 | 33 | IEnumerator IEnumerable.GetEnumerator() => List.GetEnumerator(); 34 | 35 | public int TextLength 36 | { 37 | get 38 | { 39 | var n = 0; 40 | foreach (var seq in List) 41 | { 42 | if (seq.IsText) 43 | n += seq.Length; 44 | } 45 | 46 | return n; 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Widgets/Texts/AnimatedText.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Component.Widgets.Texts; 2 | 3 | /// 4 | /// animated text 5 | /// 6 | public sealed class AnimatedText : AnimatedWidget> 7 | { 8 | readonly Func _frameContent; 9 | 10 | /// 11 | /// animated text 12 | /// 13 | /// fps 14 | /// func that gives each frame content 15 | public AnimatedText( 16 | double fps, 17 | Func frameContent) 18 | : base(fps, new Text(string.Empty)) => _frameContent = frameContent; 19 | 20 | /// 21 | /// animated text 22 | /// 23 | /// cursor x 24 | /// cursor y 25 | /// fps 26 | /// func that gives each frame content 27 | public AnimatedText( 28 | int x, 29 | int y, 30 | double fps, 31 | Func frameContent) 32 | : base(x, y, fps, new Text(string.Empty)) 33 | => _frameContent = frameContent; 34 | 35 | /// 36 | protected override bool IsEnd() => false; 37 | 38 | /// 39 | protected override void RenderFrame() 40 | => SetText(_frameContent()); 41 | 42 | /// 43 | protected override string RenderWidget(string render) 44 | => render; 45 | 46 | /// 47 | protected override void StartInit() { } 48 | } 49 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Widgets/Texts/Text.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Component.Widgets.Texts; 2 | 3 | /// 4 | /// text widget 5 | /// 6 | public sealed class Text : Widget> 7 | { 8 | string? _value; 9 | /// 10 | /// text 11 | /// 12 | public string Value 13 | { 14 | get => _value!; 15 | set 16 | { 17 | _value = value; 18 | TextChanged?.Invoke(this, new EventArgs()); 19 | } 20 | } 21 | 22 | /// 23 | public override void SetText(string text) 24 | => Value = text; 25 | 26 | /// 27 | public override string GetText() 28 | => Value; 29 | 30 | /// 31 | /// text changed event 32 | /// 33 | public event EventHandler TextChanged; 34 | 35 | /// 36 | /// widget text 37 | /// 38 | /// cursor x 39 | /// cursor y 40 | /// text 41 | public Text(int x, int y, string text) : base(x, y) 42 | { 43 | Value = text; 44 | TextChanged += OnTextChanged; 45 | } 46 | 47 | /// 48 | /// widget text 49 | /// 50 | /// text 51 | public Text(string text) : base(null) 52 | { 53 | Value = text; 54 | TextChanged += OnTextChanged; 55 | } 56 | 57 | void OnTextChanged(object? sender, EventArgs e) 58 | { 59 | lock (Console!.Out.Lock) 60 | { 61 | Update(); 62 | } 63 | } 64 | 65 | /// 66 | protected override string RenderWidget() => Value; 67 | } 68 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Widgets/Models/Rgb.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Component.Widgets.Models; 2 | 3 | /// 4 | /// rgb color values 5 | /// 6 | public sealed class Rgb 7 | { 8 | int _r; 9 | /// 10 | /// red 11 | /// 12 | public int R 13 | { 14 | get => _r; 15 | set => _r = value; 16 | } 17 | 18 | int _g; 19 | /// 20 | /// green 21 | /// 22 | public int G 23 | { 24 | get => _g; 25 | set => _g = value; 26 | } 27 | 28 | int _b; 29 | /// 30 | /// blue 31 | /// 32 | public int B 33 | { 34 | get => _b; 35 | set => _b = value; 36 | } 37 | 38 | /// 39 | /// Rgb 40 | /// 41 | /// red 42 | /// green 43 | /// blue 44 | public Rgb(int r = 0, int g = 0, int b = 0) 45 | { 46 | _r = r; 47 | _g = g; 48 | _b = b; 49 | } 50 | 51 | /// 52 | /// set from another Rgb 53 | /// 54 | /// rgb 55 | /// this object 56 | public Rgb Set(Rgb rgb) 57 | { 58 | _r = rgb.R; 59 | _g = rgb.G; 60 | _b = rgb.B; 61 | return this; 62 | } 63 | 64 | /// 65 | /// set from rgb 66 | /// 67 | /// red 68 | /// green 69 | /// blue 70 | /// this object 71 | public Rgb Set(int r = 0, int g = 0, int b = 0) 72 | { 73 | _r = r; 74 | _g = g; 75 | _b = b; 76 | return this; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Widgets/IWidget.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Component.Widgets; 2 | 3 | /// 4 | /// widget abstract 5 | /// 6 | public interface IWidget 7 | { 8 | /// 9 | /// wrapped widget 10 | /// 11 | IWidget? WrappedWidget { get; } 12 | 13 | /// 14 | /// set the text of the deepest wrapped widget in the hierarchy 15 | /// 16 | /// text 17 | void SetText(string text); 18 | 19 | /// 20 | /// get the text of the deepest wrapped widget in the hierarchy 21 | /// 22 | /// 23 | string GetText(); 24 | 25 | /// 26 | /// fixed location X if any else location when rendered (origin 0) 27 | /// 28 | int X { get; } 29 | 30 | /// 31 | /// fixed location Y if any else else location when rendered (origin 0) 32 | /// 33 | int Y { get; } 34 | 35 | /// 36 | /// right location X after rendering (origin 0) else -1 37 | /// 38 | int RightX { get; } 39 | 40 | /// 41 | /// bottom location Y after rendering (origin 0) else -1 42 | /// 43 | int BottomY { get; } 44 | 45 | /// 46 | /// render the widget 47 | /// 48 | /// the console to render to 49 | /// the render of the widget 50 | string Render(IAnsiVtConsole console); 51 | 52 | /// 53 | /// update the display of the widget previously attached to a console (already rendered) 54 | /// 55 | void Update(bool shouldHideCursor = true); 56 | 57 | /// 58 | /// set parent widget 59 | /// 60 | /// parent 61 | void SetParent(IWidget parent); 62 | } -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Console/InputMap.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Component.Console 2 | { 3 | sealed class InputMap 4 | { 5 | public const int ExactMatch = 0; 6 | public const int NoMatch = -1; 7 | public const int PartialMatch = 1; 8 | 9 | public readonly string? Text; 10 | public readonly object? Code; 11 | /// 12 | /// -1 : no match, 0 : exact match , 1: partial match 13 | /// 14 | public readonly Func? MatchInput; 15 | public readonly bool CaseSensitiveMatch; 16 | 17 | public InputMap(string text, bool caseSensitiveMatch = false) 18 | { 19 | Text = text; 20 | CaseSensitiveMatch = caseSensitiveMatch; 21 | } 22 | 23 | public InputMap(string text, object code, bool caseSensitiveMatch = false) 24 | { 25 | Text = text; 26 | Code = code; 27 | CaseSensitiveMatch = caseSensitiveMatch; 28 | } 29 | 30 | public InputMap(Func matchInput, object code) 31 | { 32 | MatchInput = matchInput; 33 | Code = code; 34 | } 35 | 36 | public int Match(string input, ConsoleKeyInfo key) 37 | { 38 | if (Text != null) 39 | { 40 | if (Text.Equals(input, CaseSensitiveMatch ? StringComparison.CurrentCulture : StringComparison.CurrentCultureIgnoreCase)) 41 | return ExactMatch; 42 | if (Text.StartsWith(input, CaseSensitiveMatch ? StringComparison.CurrentCulture : StringComparison.CurrentCultureIgnoreCase)) 43 | return PartialMatch; 44 | return NoMatch; 45 | } 46 | else 47 | { 48 | return (MatchInput == null) ? -1 : MatchInput(input, key); 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Widgets/Bars/GradientBar.cs: -------------------------------------------------------------------------------- 1 | using AnsiVtConsole.NetCore.Component.Widgets.Texts.Coloring; 2 | 3 | namespace AnsiVtConsole.NetCore.Component.Widgets.Bars; 4 | 5 | /// 6 | /// animatable raimbow bar 7 | /// 8 | public sealed class GradientBar : Widget> 9 | { 10 | /// 11 | /// bar char 12 | /// 13 | public char BarChar { get; private set; } = DefaultBarChar; 14 | 15 | /// 16 | /// raimbow 17 | /// 18 | public Gradient Gradient => (Gradient)WrappedWidget!; 19 | 20 | const char DefaultBarChar = '─'; 21 | 22 | /// 23 | /// length 24 | /// 25 | public int Length { get; private set; } 26 | 27 | /// 28 | /// gradient bar 29 | /// 30 | /// length 31 | /// character used to draw the bar 32 | public GradientBar(int length, char? barChar = null) 33 | : base(new Gradient(GetBarText(length, barChar ?? DefaultBarChar))) 34 | { 35 | Length = length; 36 | BarChar = barChar ?? DefaultBarChar; 37 | } 38 | 39 | /// 40 | /// gradient bar 41 | /// 42 | /// cursor x 43 | /// cursor y 44 | /// length 45 | /// character used to draw the bar 46 | public GradientBar(int x, int y, int length, char? barChar = null) 47 | : base( 48 | x, 49 | y, 50 | new Gradient(GetBarText(length, barChar ?? DefaultBarChar))) 51 | { 52 | Length = length; 53 | BarChar = barChar ?? DefaultBarChar; 54 | } 55 | 56 | static string GetBarText(int length, char barChar) 57 | => "".PadLeft(length, barChar); 58 | 59 | /// 60 | protected override string RenderWidget(string render) 61 | => render; 62 | } 63 | -------------------------------------------------------------------------------- /Examples/AnsiVtConsole.NetCore.Examples.Widgets/Demo.cs: -------------------------------------------------------------------------------- 1 | using AnsiVtConsole.NetCore.Examples.Widgets.Pages; 2 | 3 | using static AnsiVtConsole.NetCore.Component.Console.ANSI; 4 | 5 | namespace AnsiVtConsole.NetCore.Examples.Widgets; 6 | 7 | sealed class Demo : DemoPage 8 | { 9 | readonly Title _title; 10 | 11 | readonly List<(DemoPage demo, int waitForNextPage)> _demos = new(); 12 | 13 | readonly bool _isAutomatic = true; 14 | int _cursorTop; 15 | const int DefWait = 6; 16 | 17 | public Demo() 18 | { 19 | _title = new Title(); 20 | _demos.AddRange(new List<(DemoPage, int)>() 21 | { 22 | (_title,0), 23 | (new Intro(),8), 24 | (new Images(),DefWait) 25 | }); 26 | } 27 | 28 | public override void Run() 29 | { 30 | _.Out.ClearScreen(); 31 | _.Out.HideCur(); 32 | 33 | var lastDemo = _demos.Last().demo; 34 | do 35 | { 36 | foreach (var (demo, waitForNextPage) in _demos) 37 | { 38 | demo.Run(_); 39 | if (_cursorTop == 0) 40 | _cursorTop = _.Out.CursorTop; 41 | 42 | if (_isAutomatic) 43 | WaitBeforeNextPage(waitForNextPage); 44 | else 45 | WaitKeyBeforeNextPage(); 46 | } 47 | 48 | _title.Animation!.Stop(); 49 | _.Out.CursorHome(); 50 | } 51 | while (true); 52 | } 53 | 54 | void WaitBeforeNextPage(int waitForNextPage) 55 | { 56 | _.Out.Write(DECTCEMShow); 57 | if (waitForNextPage > 0) 58 | WaitPage(waitForNextPage); 59 | NextPage(); 60 | } 61 | 62 | void WaitKeyBeforeNextPage() 63 | { 64 | _.Out.Write(DECTCEMShow); 65 | _.Inp.WaitKeyPress(); 66 | NextPage(); 67 | } 68 | 69 | void NextPage() => _.Out.Write( 70 | CUP(1, _cursorTop + 1) 71 | + ED(0) 72 | + CUP(1, _cursorTop + 1) 73 | + DECTCEMShow); 74 | 75 | } 76 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Widgets/Animatics/AnimationGroup.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | 3 | namespace AnsiVtConsole.NetCore.Component.Widgets.Animatics; 4 | 5 | /// 6 | /// value animation group - usefull to setup properties for a set of animations in one time 7 | /// 8 | public sealed class AnimationGroup 9 | { 10 | /// 11 | /// animations 12 | /// 13 | public IReadOnlyList Animations => _animations; 14 | 15 | readonly List _animations = new(); 16 | 17 | /// 18 | /// animation group 19 | /// 20 | /// animations in the group 21 | public AnimationGroup(params IAnimation[] animations) 22 | => _animations.AddRange(animations); 23 | 24 | /// 25 | /// add target property of a class to animations in the group 26 | /// 27 | /// linq expression that reference the target property of an object: () => obj.a.b.. Expression0<Func<ValueTypeglt;>> 28 | /// this object 29 | public AnimationGroup For(LambdaExpression expression) 30 | { 31 | foreach (var anim in _animations) 32 | anim.For(expression); 33 | return this; 34 | } 35 | 36 | /// 37 | /// add target property of a class to animation in the group 38 | /// 39 | /// property name 40 | /// this object 41 | public AnimationGroup For(string propertyName) 42 | { 43 | foreach (var anim in _animations) 44 | anim.For(propertyName); 45 | return this; 46 | } 47 | 48 | /// 49 | /// setup target(s) for animations in the group 50 | /// 51 | /// one or several targets 52 | /// this object 53 | public AnimationGroup Target(params object[] targets) 54 | { 55 | foreach (var anim in _animations) 56 | anim.Target(targets); 57 | return this; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Console/StringSegment.cs: -------------------------------------------------------------------------------- 1 | using AnsiVtConsole.NetCore.Lib; 2 | 3 | namespace AnsiVtConsole.NetCore.Component.Console 4 | { 5 | sealed class StringSegment 6 | { 7 | public string Text { get; private set; } 8 | public int X { get; private set; } 9 | public int Y { get; private set; } 10 | public int Length { get; private set; } 11 | 12 | public Dictionary? Map; 13 | 14 | public void SetText(string text, bool updateCoords = false) 15 | { 16 | Text = text; 17 | if (updateCoords) 18 | { 19 | Length = text.Length; 20 | Y = X + Length; 21 | } 22 | } 23 | 24 | public StringSegment(string text, int x, int y, int length) 25 | { 26 | Text = text; 27 | X = x; 28 | Y = y; 29 | Length = length; 30 | } 31 | 32 | public StringSegment(string text, int x, int y) 33 | { 34 | Text = text; 35 | X = x; 36 | Y = y; 37 | Length = y - x + 1; 38 | } 39 | 40 | public StringSegment(string text, int x, int y, int length, Dictionary map) 41 | { 42 | Text = text; 43 | X = x; 44 | Y = y; 45 | Length = length; 46 | if (map != null && map.Count > 0) 47 | Map = new Dictionary { map }; 48 | } 49 | 50 | public StringSegment(string text, int x, int y, Dictionary map) 51 | { 52 | Text = text; 53 | X = x; 54 | Y = y; 55 | Length = y - x + 1; 56 | if (map != null && map.Count > 0) 57 | Map = new Dictionary { map }; 58 | } 59 | 60 | /// 61 | /// warn: this is intensively used in error messages... 62 | /// 63 | /// text representation of a StringSegment 64 | public override string ToString() => 65 | //return $"pos={X},{Y} l={Length} Text={Text}"; // warn: this is intensively used in error messages... 66 | Text; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Lib/Process/ProcessCounter.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Lib.Process 2 | { 3 | /// 4 | /// process counter usable with ProcessWrapper 5 | /// 6 | sealed class ProcessCounter 7 | { 8 | int _counter; 9 | 10 | readonly object _counterLock = new(); 11 | 12 | public static bool Log { get; set; } = true; 13 | 14 | public int Counter 15 | { 16 | get 17 | { 18 | lock (_counterLock) 19 | { 20 | return _counter; 21 | } 22 | } 23 | } 24 | 25 | public int GetCounter() => _counter; 26 | 27 | public ProcessCounter() => _counter = 0; 28 | 29 | public void Increase() 30 | { 31 | lock (_counterLock) 32 | { 33 | _counter++; 34 | if (Log) 35 | System.Diagnostics.Debug.WriteLine("ProcessCounter:Increased = " + _counter); 36 | } 37 | } 38 | 39 | public void Decrease() 40 | { 41 | lock (_counterLock) 42 | { 43 | _counter--; 44 | if (Log) 45 | System.Diagnostics.Debug.WriteLine("ProcessCounter:Decreased = " + _counter); 46 | } 47 | } 48 | 49 | public void WaitForLessThan(int N) 50 | { 51 | if (Log) 52 | System.Diagnostics.Debug.WriteLine("ProcessCounter:WaitForLessThan " + N); 53 | var t = new Thread(() => WaitForLessThanNInternal(N)); 54 | t.Start(); 55 | t.Join(); 56 | } 57 | 58 | void WaitForLessThanNInternal(int n) 59 | { 60 | var end = false; 61 | while (!end) 62 | { 63 | int v; 64 | lock (_counterLock) 65 | { 66 | v = GetCounter(); 67 | if (v < n) 68 | end = true; 69 | if (!end) 70 | { 71 | Thread.Yield(); 72 | Thread.Sleep(50); 73 | } 74 | } 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Examples/AnsiVtConsole.NetCore.Examples.Widgets/Pages/Title.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | using AnsiVtConsole.NetCore.Component.Widgets.Animatics; 4 | using AnsiVtConsole.NetCore.Component.Widgets.Animatics.Animations; 5 | using AnsiVtConsole.NetCore.Component.Widgets.Bars; 6 | using AnsiVtConsole.NetCore.Component.Widgets.Texts.Coloring; 7 | 8 | namespace AnsiVtConsole.NetCore.Examples.Widgets.Pages; 9 | 10 | sealed class Title : DemoPage 11 | { 12 | public Animation? Animation { get; private set; } 13 | 14 | public override void Run() 15 | { 16 | var str = @" 17 | ___ _ __ __ _ ___ _ _ _ _ ___ 18 | / \ _ _ ___(_)\ \ / /| |_ / __| ___ _ _ ___ ___ | | ___ | \| | ___ | |_ / __| ___ _ _ ___ 19 | | - || ' \ (_-/| | \ / | _|| (__ / _ \| ' \ (_-// _ \| |/ -_) _ | . |/ -_)| _|| (__ / _ \| '_|/ -_) 20 | |_|_||_||_|/__/|_| \_/ \__| \___|\___/|_||_|/__/\___/|_|\___| (_) |_|\_|\___| \__| \___|\___/|_| \___| 21 | "; 22 | Gradient Setup(Gradient raimbow) 23 | => raimbow 24 | .Origin(0, 0, 128) 25 | .CyclicGradient(4, 9, 14); 26 | 27 | Gradient RaimbowText(string str) 28 | => Setup(new Gradient(str)); 29 | 30 | var title = RaimbowText(str).Add(_); 31 | 32 | RaimbowText($" AnsiVtConsole.NetCore v{Assembly.GetExecutingAssembly().GetName().Version}").Add(_); 33 | 34 | _.Out.WriteLine(); 35 | 36 | var bar = new GradientBar(113); 37 | Setup(bar.Gradient); 38 | bar.Add(_); 39 | 40 | _.Out.WriteLine(); 41 | _.Out.WriteLine(); 42 | 43 | var anims = 44 | new AnimationGroup( 45 | new IntAnimation(0, 255, 2000d) 46 | .For(() => bar.Gradient.OriginRGB.R), 47 | new IntAnimation(0, 255, 2000d) 48 | .For(() => bar.Gradient.OriginRGB.G), 49 | new IntAnimation(128, 255, 2000d) 50 | .For(() => bar.Gradient.OriginRGB.B)) 51 | .Target(bar.Gradient.OriginRGB); 52 | 53 | Animation = new Animation() 54 | .Add( 55 | new TimeLine() 56 | .Loop() 57 | .AutoReverse() 58 | .Add(anims) 59 | .Update(bar) 60 | ) 61 | .Start(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | AnsiVtConsole.NetCore Copyright (c) 2023 franck gaspoz (franck.gaspoz@gmail.com) 2 | Licence Free MIT 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the « Software »), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED « AS IS », WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | 22 | ------------------------------------------------------------------------------------------------------ 23 | 24 | AnsiVtConsole.NetCore Copyright (c) 2023 franck gaspoz (franck.gaspoz@gmail.com) 25 | Licence Libre MIT 26 | 27 | L’autorisation est accordée, gracieusement, à toute personne acquérant une copie 28 | de ce logiciel et des fichiers de documentation associés (le « logiciel »), de commercialiser 29 | le logiciel sans restriction, notamment les droits d’utiliser, de copier, de modifier, 30 | de fusionner, de publier, de distribuer, de sous-licencier et / ou de vendre des copies du logiciel, 31 | ainsi que d’autoriser les personnes auxquelles la logiciel est fournie à le faire, 32 | sous réserve des conditions suivantes : 33 | 34 | La déclaration de copyright ci-dessus et la présente autorisation doivent être incluses dans 35 | toutes copies ou parties substantielles du logiciel. 36 | 37 | LE LOGICIEL EST FOURNI « TEL QUEL », SANS GARANTIE D’AUCUNE SORTE, EXPLICITE OU IMPLICITE, 38 | NOTAMMENT SANS GARANTIE DE QUALITÉ MARCHANDE, D’ADÉQUATION À UN USAGE PARTICULIER ET D’ABSENCE 39 | DE CONTREFAÇON. EN AUCUN CAS, LES AUTEURS OU TITULAIRES DU DROIT D’AUTEUR NE SERONT RESPONSABLES 40 | DE TOUT DOMMAGE, RÉCLAMATION OU AUTRE RESPONSABILITÉ, QUE CE SOIT DANS LE CADRE D’UN CONTRAT, 41 | D’UN DÉLIT OU AUTRE, EN PROVENANCE DE, CONSÉCUTIF À OU EN RELATION AVEC LE LOGICIEL OU SON UTILISATION, 42 | OU AVEC D’AUTRES ÉLÉMENTS DU LOGICIEL. -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/LICENSE.md: -------------------------------------------------------------------------------- 1 | AnsiVtConsole.NetCore Copyright (c) 2023 franck gaspoz (franck.gaspoz@gmail.com) 2 | Licence Free MIT 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the « Software »), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED « AS IS », WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | 22 | ------------------------------------------------------------------------------------------------------ 23 | 24 | AnsiVtConsole.NetCore Copyright (c) 2023 franck gaspoz (franck.gaspoz@gmail.com) 25 | Licence Libre MIT 26 | 27 | L’autorisation est accordée, gracieusement, à toute personne acquérant une copie 28 | de ce logiciel et des fichiers de documentation associés (le « logiciel »), de commercialiser 29 | le logiciel sans restriction, notamment les droits d’utiliser, de copier, de modifier, 30 | de fusionner, de publier, de distribuer, de sous-licencier et / ou de vendre des copies du logiciel, 31 | ainsi que d’autoriser les personnes auxquelles la logiciel est fournie à le faire, 32 | sous réserve des conditions suivantes : 33 | 34 | La déclaration de copyright ci-dessus et la présente autorisation doivent être incluses dans 35 | toutes copies ou parties substantielles du logiciel. 36 | 37 | LE LOGICIEL EST FOURNI « TEL QUEL », SANS GARANTIE D’AUCUNE SORTE, EXPLICITE OU IMPLICITE, 38 | NOTAMMENT SANS GARANTIE DE QUALITÉ MARCHANDE, D’ADÉQUATION À UN USAGE PARTICULIER ET D’ABSENCE 39 | DE CONTREFAÇON. EN AUCUN CAS, LES AUTEURS OU TITULAIRES DU DROIT D’AUTEUR NE SERONT RESPONSABLES 40 | DE TOUT DOMMAGE, RÉCLAMATION OU AUTRE RESPONSABILITÉ, QUE CE SOIT DANS LE CADRE D’UN CONTRAT, 41 | D’UN DÉLIT OU AUTRE, EN PROVENANCE DE, CONSÉCUTIF À OU EN RELATION AVEC LE LOGICIEL OU SON UTILISATION, 42 | OU AVEC D’AUTRES ÉLÉMENTS DU LOGICIEL. -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore.Imaging/LICENSE.md: -------------------------------------------------------------------------------- 1 | AnsiVtConsole.NetCore Copyright (c) 2023 franck gaspoz (franck.gaspoz@gmail.com) 2 | Licence Free MIT 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the « Software »), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED « AS IS », WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | 22 | ------------------------------------------------------------------------------------------------------ 23 | 24 | AnsiVtConsole.NetCore Copyright (c) 2023 franck gaspoz (franck.gaspoz@gmail.com) 25 | Licence Libre MIT 26 | 27 | L’autorisation est accordée, gracieusement, à toute personne acquérant une copie 28 | de ce logiciel et des fichiers de documentation associés (le « logiciel »), de commercialiser 29 | le logiciel sans restriction, notamment les droits d’utiliser, de copier, de modifier, 30 | de fusionner, de publier, de distribuer, de sous-licencier et / ou de vendre des copies du logiciel, 31 | ainsi que d’autoriser les personnes auxquelles la logiciel est fournie à le faire, 32 | sous réserve des conditions suivantes : 33 | 34 | La déclaration de copyright ci-dessus et la présente autorisation doivent être incluses dans 35 | toutes copies ou parties substantielles du logiciel. 36 | 37 | LE LOGICIEL EST FOURNI « TEL QUEL », SANS GARANTIE D’AUCUNE SORTE, EXPLICITE OU IMPLICITE, 38 | NOTAMMENT SANS GARANTIE DE QUALITÉ MARCHANDE, D’ADÉQUATION À UN USAGE PARTICULIER ET D’ABSENCE 39 | DE CONTREFAÇON. EN AUCUN CAS, LES AUTEURS OU TITULAIRES DU DROIT D’AUTEUR NE SERONT RESPONSABLES 40 | DE TOUT DOMMAGE, RÉCLAMATION OU AUTRE RESPONSABILITÉ, QUE CE SOIT DANS LE CADRE D’UN CONTRAT, 41 | D’UN DÉLIT OU AUTRE, EN PROVENANCE DE, CONSÉCUTIF À OU EN RELATION AVEC LE LOGICIEL OU SON UTILISATION, 42 | OU AVEC D’AUTRES ÉLÉMENTS DU LOGICIEL. -------------------------------------------------------------------------------- /Examples/AnsiVtConsole.NetCore.Examples.ANSI/LICENSE.md: -------------------------------------------------------------------------------- 1 | AnsiVtConsole.NetCore Copyright (c) 2022 franck gaspoz (franck.gaspoz@gmail.com) 2 | Licence Free MIT 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the « Software »), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED « AS IS », WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | 22 | ------------------------------------------------------------------------------------------------------ 23 | 24 | AnsiVtConsole.NetCore Copyright (c) 2022 franck gaspoz (franck.gaspoz@gmail.com) 25 | Licence Libre MIT 26 | 27 | L’autorisation est accordée, gracieusement, à toute personne acquérant une copie 28 | de ce logiciel et des fichiers de documentation associés (le « logiciel »), de commercialiser 29 | le logiciel sans restriction, notamment les droits d’utiliser, de copier, de modifier, 30 | de fusionner, de publier, de distribuer, de sous-licencier et / ou de vendre des copies du logiciel, 31 | ainsi que d’autoriser les personnes auxquelles la logiciel est fournie à le faire, 32 | sous réserve des conditions suivantes : 33 | 34 | La déclaration de copyright ci-dessus et la présente autorisation doivent être incluses dans 35 | toutes copies ou parties substantielles du logiciel. 36 | 37 | LE LOGICIEL EST FOURNI « TEL QUEL », SANS GARANTIE D’AUCUNE SORTE, EXPLICITE OU IMPLICITE, 38 | NOTAMMENT SANS GARANTIE DE QUALITÉ MARCHANDE, D’ADÉQUATION À UN USAGE PARTICULIER ET D’ABSENCE 39 | DE CONTREFAÇON. EN AUCUN CAS, LES AUTEURS OU TITULAIRES DU DROIT D’AUTEUR NE SERONT RESPONSABLES 40 | DE TOUT DOMMAGE, RÉCLAMATION OU AUTRE RESPONSABILITÉ, QUE CE SOIT DANS LE CADRE D’UN CONTRAT, 41 | D’UN DÉLIT OU AUTRE, EN PROVENANCE DE, CONSÉCUTIF À OU EN RELATION AVEC LE LOGICIEL OU SON UTILISATION, 42 | OU AVEC D’AUTRES ÉLÉMENTS DU LOGICIEL. -------------------------------------------------------------------------------- /Examples/AnsiVtConsole.NetCore.Examples.Widgets/LICENSE.md: -------------------------------------------------------------------------------- 1 | AnsiVtConsole.NetCore Copyright (c) 2022 franck gaspoz (franck.gaspoz@gmail.com) 2 | Licence Free MIT 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the « Software »), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED « AS IS », WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | 22 | ------------------------------------------------------------------------------------------------------ 23 | 24 | AnsiVtConsole.NetCore Copyright (c) 2022 franck gaspoz (franck.gaspoz@gmail.com) 25 | Licence Libre MIT 26 | 27 | L’autorisation est accordée, gracieusement, à toute personne acquérant une copie 28 | de ce logiciel et des fichiers de documentation associés (le « logiciel »), de commercialiser 29 | le logiciel sans restriction, notamment les droits d’utiliser, de copier, de modifier, 30 | de fusionner, de publier, de distribuer, de sous-licencier et / ou de vendre des copies du logiciel, 31 | ainsi que d’autoriser les personnes auxquelles la logiciel est fournie à le faire, 32 | sous réserve des conditions suivantes : 33 | 34 | La déclaration de copyright ci-dessus et la présente autorisation doivent être incluses dans 35 | toutes copies ou parties substantielles du logiciel. 36 | 37 | LE LOGICIEL EST FOURNI « TEL QUEL », SANS GARANTIE D’AUCUNE SORTE, EXPLICITE OU IMPLICITE, 38 | NOTAMMENT SANS GARANTIE DE QUALITÉ MARCHANDE, D’ADÉQUATION À UN USAGE PARTICULIER ET D’ABSENCE 39 | DE CONTREFAÇON. EN AUCUN CAS, LES AUTEURS OU TITULAIRES DU DROIT D’AUTEUR NE SERONT RESPONSABLES 40 | DE TOUT DOMMAGE, RÉCLAMATION OU AUTRE RESPONSABILITÉ, QUE CE SOIT DANS LE CADRE D’UN CONTRAT, 41 | D’UN DÉLIT OU AUTRE, EN PROVENANCE DE, CONSÉCUTIF À OU EN RELATION AVEC LE LOGICIEL OU SON UTILISATION, 42 | OU AVEC D’AUTRES ÉLÉMENTS DU LOGICIEL. -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore.CommandLine/LICENSE.md: -------------------------------------------------------------------------------- 1 | AnsiVtConsole.NetCore Copyright (c) December 2022 franck gaspoz (franck.gaspoz@gmail.com) 2 | Licence Free MIT 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the « Software »), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED « AS IS », WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | 22 | ------------------------------------------------------------------------------------------------------ 23 | 24 | AnsiVtConsole.NetCore Copyright (c) December 2022 franck gaspoz (franck.gaspoz@gmail.com) 25 | Licence Libre MIT 26 | 27 | L’autorisation est accordée, gracieusement, à toute personne acquérant une copie 28 | de ce logiciel et des fichiers de documentation associés (le « logiciel »), de commercialiser 29 | le logiciel sans restriction, notamment les droits d’utiliser, de copier, de modifier, 30 | de fusionner, de publier, de distribuer, de sous-licencier et / ou de vendre des copies du logiciel, 31 | ainsi que d’autoriser les personnes auxquelles la logiciel est fournie à le faire, 32 | sous réserve des conditions suivantes : 33 | 34 | La déclaration de copyright ci-dessus et la présente autorisation doivent être incluses dans 35 | toutes copies ou parties substantielles du logiciel. 36 | 37 | LE LOGICIEL EST FOURNI « TEL QUEL », SANS GARANTIE D’AUCUNE SORTE, EXPLICITE OU IMPLICITE, 38 | NOTAMMENT SANS GARANTIE DE QUALITÉ MARCHANDE, D’ADÉQUATION À UN USAGE PARTICULIER ET D’ABSENCE 39 | DE CONTREFAÇON. EN AUCUN CAS, LES AUTEURS OU TITULAIRES DU DROIT D’AUTEUR NE SERONT RESPONSABLES 40 | DE TOUT DOMMAGE, RÉCLAMATION OU AUTRE RESPONSABILITÉ, QUE CE SOIT DANS LE CADRE D’UN CONTRAT, 41 | D’UN DÉLIT OU AUTRE, EN PROVENANCE DE, CONSÉCUTIF À OU EN RELATION AVEC LE LOGICIEL OU SON UTILISATION, 42 | OU AVEC D’AUTRES ÉLÉMENTS DU LOGICIEL. -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/IAnsiVtConsole.cs: -------------------------------------------------------------------------------- 1 | using AnsiVtConsole.NetCore.Component.Console; 2 | using AnsiVtConsole.NetCore.Component.Settings; 3 | 4 | namespace AnsiVtConsole.NetCore; 5 | 6 | /// 7 | /// AnsiVtConsole interface 8 | /// 9 | public interface IAnsiVtConsole 10 | { 11 | /// 12 | /// settings of the console 13 | /// 14 | public AnsiVtConsoleSettings Settings { get; } 15 | 16 | /// 17 | /// work area settings 18 | /// 19 | public WorkAreaSettings WorkAreaSettings { get; } 20 | 21 | /// 22 | /// input prompter 23 | /// 24 | public Inp Inp { get; } 25 | 26 | /// 27 | /// default colors and predefined colors sets 28 | /// 29 | ColorSettings Colors { get; } 30 | 31 | /// 32 | /// system standard err stream wrapper 33 | /// 34 | TextWriterWrapper StdErr { get; } 35 | 36 | /// 37 | /// standard input stream 38 | /// 39 | TextReader In { get; } 40 | 41 | /// 42 | /// cursor controler 43 | /// 44 | Cursor Cursor { get; } 45 | 46 | /// 47 | /// output stream 48 | /// 49 | ConsoleTextWriterWrapper Out { get; } 50 | 51 | /// 52 | /// work area 53 | /// 54 | WorkArea WorkArea { get; } 55 | 56 | /// 57 | /// logger 58 | /// 59 | Logger Logger { get; } 60 | 61 | /// 62 | /// terminates current process 63 | /// 64 | /// return code 65 | void Exit(int r = 0); 66 | 67 | /// 68 | /// output infos about the system and the console host 69 | /// 70 | void Infos(); 71 | 72 | /// 73 | /// redirects outputs to a file 74 | /// 75 | /// file path - set null to disable redirect 76 | void RedirectErr(string? filepath = null); 77 | 78 | /// 79 | /// redirects errors to a stream writer 80 | /// 81 | /// stream writer - set null to disable redirect 82 | void RedirectErr(StreamWriter? sw); 83 | 84 | /// 85 | /// redirects outputs to a file 86 | /// 87 | /// file path - set null to disable redirect 88 | void RedirectOut(string? filepath = null); 89 | 90 | /// 91 | /// redirects outputs to a stream writer 92 | /// 93 | /// stream writer - set null to disable redirect 94 | void RedirectOut(StreamWriter? sw); 95 | } 96 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /Examples/AnsiVtConsole.NetCore.Examples.Widgets/DemoPage.cs: -------------------------------------------------------------------------------- 1 | using AnsiVtConsole.NetCore.Component.Widgets.Texts; 2 | using AnsiVtConsole.NetCore.Component.Widgets.Texts.Timers; 3 | using AnsiVtConsole.NetCore.Component.Widgets.Texts.TypeWriting; 4 | 5 | using static AnsiVtConsole.NetCore.Component.Console.ANSI; 6 | 7 | namespace AnsiVtConsole.NetCore.Examples.Widgets; 8 | 9 | abstract class DemoPage 10 | { 11 | #pragma warning disable CS8618 12 | protected IAnsiVtConsole _; 13 | #pragma warning restore CS8618 14 | 15 | public void Run(IAnsiVtConsole console) 16 | { 17 | _ = console; 18 | Run(); 19 | } 20 | 21 | protected static TypeWriter TypeWriter(string text) 22 | => new( 23 | $"{SGR_SetForegroundColor4bits(SGR_4BitsColors.White, true)}{text}", 24 | 10000, 25 | $"{SGR_SetForegroundColor4bits(SGR_4BitsColors.Green, true)}█(rsf)"); 26 | 27 | protected TypeWriter TypeWrite(string text) 28 | => TypeWriter(text).Add(_).Wait(); 29 | 30 | public abstract void Run(); 31 | 32 | protected static void Wait(int delay) => Thread.Sleep(delay); 33 | 34 | protected void WaitPage(int waitForNextPage) 35 | { 36 | PleaseWait(waitForNextPage); 37 | Thread.Sleep(waitForNextPage * 1000); 38 | } 39 | 40 | protected void SubTitle(string text) 41 | { 42 | TypeWrite($"(f=white){text}"); 43 | _.Out.WriteLine(); 44 | } 45 | 46 | protected void PleaseWait(int waitForNextPage) 47 | { 48 | _.Out.WriteLine().WriteLine(); 49 | 50 | var tipsAnim = TipsAnim(); 51 | 52 | var tt = new TextTimer( 53 | tipsAnim.RightX + 1, 54 | tipsAnim.BottomY, 55 | "(bkf,f=yellow)This page will automatically update in {0}(f=yellow) seconds...(rsf)", 56 | 2, 57 | TimeSpan.FromSeconds(waitForNextPage * 100), 58 | (duration) => GetDurationText(duration)) 59 | .Add(_!); 60 | tt 61 | .OnStop += (o, e) => tipsAnim.Stop(); 62 | tt.Wait(); 63 | } 64 | 65 | protected AnimatedText TipsAnim() 66 | => new AnimatedText(5, () => GetTipsFrame()) 67 | .Add(_!); 68 | 69 | int _tipIndex = 0; 70 | static readonly string[] _tipsFrames = new string[] 71 | { 72 | "► ", 73 | " ► ", 74 | " ►" 75 | }; 76 | 77 | string GetTipsFrame() 78 | { 79 | var tip = _tipsFrames[_tipIndex++]; 80 | _tipIndex %= 3; 81 | return tip; 82 | } 83 | 84 | static string GetDurationText(TimeSpan duration) 85 | { 86 | var seconds = duration.TotalSeconds; 87 | var text = seconds.ToString(); 88 | var col = ""; 89 | if (seconds <= 5) col = "(f=darkyellow)"; 90 | if (seconds <= 3) col = "(f=red)"; 91 | return col + text; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Widgets/Animatics/Animation.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Component.Widgets.Animatics; 2 | 3 | /// 4 | /// animation 5 | /// run parallely values animations grouped in one time line 6 | /// run sequencially times lines 7 | /// 8 | public sealed class Animation 9 | { 10 | /// 11 | /// animatables 12 | /// 13 | public IReadOnlyList TimeLines 14 | => _timeLines; 15 | 16 | readonly List _timeLines = new(); 17 | 18 | double _fps = 10; 19 | /// 20 | /// frame per seconds 21 | /// 22 | public double Fps 23 | { 24 | get => _fps; 25 | set 26 | { 27 | if (IsRunning) 28 | throw new InvalidOperationException("can't change fps when running"); 29 | _fps = value; 30 | } 31 | } 32 | 33 | /// 34 | /// is running 35 | /// 36 | public bool IsRunning { get; private set; } 37 | 38 | readonly Animator _animator; 39 | 40 | /// 41 | /// animation 42 | /// 43 | /// frames per seconds (default 10) 44 | public Animation(double? fps = null) 45 | { 46 | _animator = new(this); 47 | _fps = fps ?? 10; 48 | } 49 | 50 | /// 51 | /// add a time line to the animation 52 | /// 53 | /// time line 54 | /// this object 55 | public Animation Add(TimeLine timeline) 56 | { 57 | _timeLines.Add(timeline); 58 | return this; 59 | } 60 | 61 | /// 62 | /// starts animation 63 | /// 64 | /// this object 65 | public Animation Start() 66 | { 67 | _animator.OnStart += OnStart; 68 | _animator.OnStop += OnStop; 69 | _animator.Start(); 70 | return this; 71 | } 72 | 73 | void OnStart(object? o, EventArgs e) => IsRunning = true; 74 | 75 | /// 76 | /// starts animation 77 | /// 78 | /// this object 79 | public Animation Stop() 80 | { 81 | _animator.Stop(); 82 | return this; 83 | } 84 | 85 | void OnStop(object? o, EventArgs e) 86 | { 87 | IsRunning = false; 88 | _animator.OnStart -= OnStart; 89 | _animator.OnStop -= OnStop; 90 | } 91 | 92 | /// 93 | /// wait end of animation. blocks current thread 94 | /// 95 | /// this object 96 | public Animation Wait() 97 | { 98 | while (IsRunning) 99 | { 100 | Thread.Yield(); 101 | } 102 | return this; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Parser/ANSI/ANSIParser.cs: -------------------------------------------------------------------------------- 1 | using AnsiVtConsole.NetCore.Component.Parser.NonRecursiveFunctionalGrammar; 2 | 3 | namespace AnsiVtConsole.NetCore.Component.Parser.ANSI 4 | { 5 | /// 6 | /// ANSI parser. Use grammar defined in Component/Parser/ANSI/ansi-seq-patterns.txt 7 | /// 8 | public static class ANSIParser 9 | { 10 | #region attributes 11 | 12 | /// 13 | /// the grammar file name that must be loaded 14 | /// 15 | public const string GrammarFileName = "ansi-seq-patterns.txt"; 16 | 17 | static readonly NonRecursiveFunctionGrammarParser _parser; 18 | 19 | #endregion 20 | 21 | #region init 22 | 23 | static ANSIParser() 24 | { 25 | var ap = System.Reflection.Assembly.GetExecutingAssembly().Location; 26 | var p = Path.Combine( 27 | Path.GetDirectoryName(ap)!, 28 | "Component", 29 | "Parser", 30 | "ANSI", 31 | GrammarFileName); 32 | var lines = File.ReadLines(p); 33 | _parser = new NonRecursiveFunctionGrammarParser(lines); 34 | } 35 | 36 | #endregion 37 | 38 | /// 39 | /// get the syntax block list of a text 40 | /// 41 | /// text to be parsed 42 | /// syntax block list 43 | public static SyntacticBlockList Parse(string s) => _parser.Parse(s); 44 | 45 | /// 46 | /// get the real length of the text without ansi sequences non printed characters 47 | /// 48 | /// text to be analyzed 49 | /// length of visible part of the text 50 | public static int GetTextLength(string s) => GetText(s).Length; 51 | 52 | /// 53 | /// gets the text part of the syntactic elements 54 | /// 55 | /// text to be analyzed 56 | /// string without ansi sequences 57 | public static string GetText(string s) => _parser.Parse(s).GetText(); 58 | 59 | /// 60 | /// indicates wether or not a string starts with a known ansi sequence. the parsed syntax is assigned in the out parameter 'syntax' 61 | /// 62 | /// text to be parsed 63 | /// parsed syntax 64 | /// true if the given text starts with a known ansi sequence. 65 | public static bool StartsWithANSISequence(string s, out SyntacticBlockList syntax) 66 | { 67 | syntax = _parser.Parse(s); 68 | if (syntax.Count == 0) 69 | return false; 70 | return syntax[0].IsANSISequence; 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Console/Cursor.cs: -------------------------------------------------------------------------------- 1 | 2 | using sc = System.Console; 3 | namespace AnsiVtConsole.NetCore.Component.Console; 4 | 5 | /// 6 | /// cursor control 7 | /// 8 | public class Cursor 9 | { 10 | readonly IAnsiVtConsole _console; 11 | 12 | /// 13 | /// a cursor attached to a console and an output stream 14 | /// 15 | /// console 16 | public Cursor(IAnsiVtConsole console) => _console = console; 17 | 18 | /// 19 | /// fix coordianates according to the console buffer size 20 | /// 21 | /// x 22 | /// y 23 | public void FixCoords(ref int x, ref int y) 24 | { 25 | lock (_console.Out.Lock!) 26 | { 27 | x = Math.Max(0, Math.Min(x, sc.BufferWidth - 1)); 28 | y = Math.Max(0, Math.Min(y, sc.BufferHeight - 1)); 29 | } 30 | } 31 | 32 | /// 33 | /// get an int value from a x string coordinate or the real cursor position if no or not valid parameter 34 | /// 35 | /// x 36 | /// x 37 | public int GetCursorX(object? x = null) 38 | { 39 | if (x != null && x is string s && !string.IsNullOrWhiteSpace(s)) 40 | { 41 | if (int.TryParse(s, out var v)) 42 | return v; 43 | else 44 | { 45 | if (_console.Settings.TraceCommandErrors) 46 | _console.Logger.LogError($"wrong cursor x: {x}"); 47 | } 48 | } 49 | if (!_console.WorkArea.IsConsoleGeometryEnabled) 50 | return 0; 51 | 52 | lock (_console.Out.Lock!) 53 | { 54 | return sc.CursorLeft; 55 | } 56 | } 57 | 58 | /// 59 | /// get an int value from a y string coordinate or the real cursor position if no or not valid parameter 60 | /// 61 | /// y 62 | /// y 63 | public int GetCursorY(object? x = null) 64 | { 65 | if (x != null && x is string s && !string.IsNullOrWhiteSpace(s)) 66 | { 67 | if (int.TryParse(s, out var v)) 68 | return v; 69 | else 70 | { 71 | if (_console.Settings.TraceCommandErrors) 72 | _console.Logger.LogError($"wrong cursor y: {x}"); 73 | } 74 | } 75 | if (!_console.WorkArea.IsConsoleGeometryEnabled) 76 | return 0; 77 | 78 | lock (_console.Out.Lock!) 79 | { 80 | return sc.CursorTop; 81 | } 82 | } 83 | 84 | /// 85 | /// hide cursor (not thread safe) 86 | /// 87 | public void Hide() => sc.CursorVisible = false; 88 | 89 | /// 90 | /// show cursor (not thread safe) 91 | /// 92 | public void Show() => sc.CursorVisible = true; 93 | } 94 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Script/CSharpScriptEngine.cs: -------------------------------------------------------------------------------- 1 | using AnsiVtConsole.NetCore.Component.Console; 2 | 3 | using Microsoft.CodeAnalysis.CSharp.Scripting; 4 | using Microsoft.CodeAnalysis.Scripting; 5 | 6 | namespace AnsiVtConsole.NetCore.Component.Script 7 | { 8 | /// 9 | /// c# script engine 10 | /// 11 | public sealed class CSharpScriptEngine 12 | { 13 | readonly Dictionary> _csscripts = new(); 14 | 15 | /// 16 | /// default script options 17 | /// 18 | public ScriptOptions DefaultScriptOptions; 19 | 20 | #pragma warning disable CS8618 21 | 22 | /// 23 | /// CSharpScriptEngine 24 | /// 25 | /// 26 | public CSharpScriptEngine(IAnsiVtConsole console) => Init(console); 27 | 28 | #pragma warning restore CS8618 29 | 30 | /// 31 | /// CSharpScriptEngine 32 | /// 33 | /// 34 | /// 35 | public CSharpScriptEngine(IAnsiVtConsole console, ScriptOptions defaultScriptOptions) 36 | { 37 | DefaultScriptOptions = defaultScriptOptions; 38 | Init(console); 39 | } 40 | 41 | void Init(IAnsiVtConsole console) 42 | { 43 | DefaultScriptOptions ??= ScriptOptions.Default; 44 | DefaultScriptOptions = DefaultScriptOptions 45 | .AddImports("System") 46 | .AddReferences(console.GetType().Assembly); 47 | } 48 | 49 | /// 50 | /// execute a csharp script 51 | /// 52 | /// source code 53 | /// output 54 | /// script options 55 | /// script return value 56 | public object? ExecCSharp( 57 | string csharpText, 58 | ConsoleTextWriterWrapper @out, 59 | ScriptOptions? scriptOptions = null 60 | ) 61 | { 62 | try 63 | { 64 | scriptOptions ??= DefaultScriptOptions; 65 | var scriptKey = csharpText; 66 | if (!_csscripts.TryGetValue(scriptKey, out var script)) 67 | { 68 | script = CSharpScript.Create( 69 | csharpText, 70 | scriptOptions 71 | ); 72 | var cpl = script.Compile(); 73 | _csscripts[scriptKey] = script; 74 | } 75 | var res = script.RunAsync(); 76 | return res.Result.ReturnValue; 77 | } 78 | catch (CompilationErrorException ex) 79 | { 80 | @out?.Errorln($"{csharpText}"); 81 | @out?.Errorln(string.Join(Environment.NewLine, ex.Diagnostics)); 82 | return null; 83 | } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Widgets/Texts/TypeWriting/TypeWriter.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Component.Widgets.Texts.TypeWriting; 2 | 3 | /// 4 | /// type writer 5 | /// 6 | public sealed class TypeWriter : AnimatedWidget 7 | { 8 | /// 9 | /// text 10 | /// 11 | public string Value { get; private set; } 12 | 13 | /// 14 | /// cursor 15 | /// 16 | public string? Cursor { get; private set; } 17 | 18 | int _charIndex = 0; 19 | char[]? _chars; 20 | string _str = string.Empty; 21 | string _rawStr = string.Empty; 22 | 23 | /// 24 | /// type writer 25 | /// 26 | /// text 27 | /// frames per second 28 | /// cursor 29 | public TypeWriter( 30 | string text, 31 | double fps, 32 | string? cursor = null) 33 | : base(fps, new Text(string.Empty)) 34 | { 35 | Cursor = cursor; 36 | Value = text; 37 | } 38 | 39 | /// 40 | /// type writer 41 | /// 42 | /// cursor x 43 | /// cursor y 44 | /// text 45 | /// frames per second 46 | /// cursor 47 | public TypeWriter( 48 | int x, 49 | int y, 50 | string text, 51 | double fps, 52 | string? cursor = null) 53 | : base(x, y, fps, new Text(string.Empty)) 54 | { 55 | Cursor = cursor; 56 | Value = text; 57 | } 58 | 59 | /// 60 | protected override string RenderWidget(string render) 61 | => render; 62 | 63 | /// 64 | protected override void StartInit() 65 | { 66 | _str = string.Empty; 67 | _rawStr = Console!.Out.GetPrint(Value, false); 68 | _chars = _rawStr.ToCharArray(); 69 | _charIndex = 0; 70 | } 71 | 72 | /// 73 | protected override bool IsEnd() => _charIndex >= _rawStr.Length; 74 | 75 | /// 76 | protected override void RenderFrame() 77 | { 78 | _str += _chars![_charIndex++]; 79 | 80 | base.SetText(_str 81 | + (_charIndex < _rawStr.Length ? 82 | GetCursor() 83 | : string.Empty)); 84 | } 85 | 86 | /// 87 | /// set the cursor 88 | /// 89 | /// cursor 90 | /// this object 91 | public TypeWriter SetCursor(string cursor) 92 | { 93 | AssertNotRunning(); 94 | Cursor = cursor; 95 | return this; 96 | } 97 | 98 | /// 99 | /// set the text 100 | /// 101 | /// text 102 | /// this object 103 | public new TypeWriter SetText(string text) 104 | { 105 | AssertNotRunning(); 106 | Value = text; 107 | base.SetText(string.Empty); 108 | return this; 109 | } 110 | 111 | string? GetCursor() 112 | => Cursor?.ToString(); 113 | } 114 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Settings/AnsiVtConsoleSettings.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Component.Settings; 2 | 3 | /// 4 | /// ansi vt console settings 5 | /// 6 | public class AnsiVtConsoleSettings 7 | { 8 | /// 9 | /// console id 10 | /// 11 | public int ID { get; internal set; } 12 | 13 | /// 14 | /// is error redirected 15 | /// 16 | public bool IsErrorRedirected { get; internal set; } = false; 17 | 18 | /// 19 | /// is output redirect 20 | /// 21 | public bool IsOutputRedirected { get; internal set; } = false; 22 | 23 | /// 24 | /// if true trace command errors 25 | /// 26 | public bool TraceCommandErrors { get; set; } = true; 27 | 28 | /// 29 | /// if true dump exception traces else use log error 30 | /// 31 | public bool DumpExceptions { get; set; } = true; 32 | 33 | /// 34 | /// default foreground color 35 | /// 36 | public ConsoleColor? DefaultForeground { get; set; } 37 | 38 | /// 39 | /// default background color 40 | /// 41 | public ConsoleColor? DefaultBackground { get; set; } 42 | 43 | /// 44 | /// markup print directive pattern begin char 45 | /// 46 | public char CommandBlockBeginChar { get; set; } = '('; 47 | 48 | /// 49 | /// markup print directive pattern end char 50 | /// 51 | public char CommandBlockEndChar { get; set; } = ')'; 52 | 53 | /// 54 | /// markup print directive separator char 55 | /// 56 | public char CommandSeparatorChar { get; set; } = ','; 57 | 58 | /// 59 | /// markup print directive value assignation char 60 | /// 61 | public char CommandValueAssignationChar { get; set; } = '='; 62 | 63 | /// 64 | /// markup code block pattern begin 65 | /// 66 | public string CodeBlockBegin { get; set; } = "[["; 67 | 68 | /// 69 | /// markup code block end begin 70 | /// 71 | public string CodeBlockEnd { get; set; } = "]]"; 72 | 73 | /// 74 | /// if true forwards logs to system diagnostics 75 | /// 76 | public bool ForwardLogsToSystemDiagnostics { get; set; } = true; 77 | 78 | /// 79 | /// tab length 80 | /// 81 | public int TabLength { get; set; } = 7; 82 | 83 | /// 84 | /// if set markup (print directives) is removed from outputs 85 | /// 86 | public bool IsMarkupDisabled { get; set; } = false; 87 | 88 | /// 89 | /// if set markup is not handled and outputed 90 | /// 91 | public bool IsRawOutputEnabled { get; set; } = false; 92 | 93 | /// 94 | /// if set and IsRawOutputEnabled, non printable characters are replaced by their name 95 | /// 96 | public bool ReplaceNonPrintableCharactersByTheirName { get; set; } = true; 97 | 98 | /// 99 | /// if set, any ansi sequence is removed from output 100 | /// 101 | public bool RemoveANSISequences { get; set; } = false; 102 | } 103 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Widgets/Animatics/TimeLine.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Component.Widgets.Animatics; 2 | 3 | /// 4 | /// story board 5 | /// 6 | public sealed class TimeLine 7 | { 8 | /// 9 | /// animatables 10 | /// 11 | public IReadOnlyList Animations 12 | => _animations; 13 | 14 | readonly List _animations = new(); 15 | 16 | /// 17 | /// is loop 18 | /// 19 | public bool IsLoop { get; private set; } 20 | 21 | /// 22 | /// is auto reverse 23 | /// 24 | public bool IsAutoReverse { get; private set; } 25 | 26 | /// 27 | /// widgets that must be updated during animation 28 | /// 29 | public IReadOnlyList Widgets => _widgets; 30 | 31 | readonly List _widgets = new(); 32 | 33 | /// 34 | /// add animation(s) to the timeline 35 | /// 36 | /// animations 37 | /// this object 38 | public TimeLine Add(params IAnimation[] animations) 39 | { 40 | _animations.AddRange(animations); 41 | return this; 42 | } 43 | 44 | /// 45 | /// add animation(s) to the timeline 46 | /// 47 | /// animations 48 | /// this object 49 | public TimeLine Add(AnimationGroup animations) 50 | { 51 | _animations.AddRange(animations.Animations); 52 | return this; 53 | } 54 | 55 | /// 56 | /// specifiy widgets to be updated during animation 57 | /// 58 | /// widgets 59 | /// this object 60 | public TimeLine Update(params IWidget[] widgets) 61 | { 62 | _widgets.AddRange(widgets); 63 | return this; 64 | } 65 | 66 | /// 67 | /// render widgets 68 | /// 69 | /// this object 70 | public TimeLine Render() 71 | { 72 | foreach (var widget in _widgets) 73 | widget.Update(); 74 | return this; 75 | } 76 | 77 | /// 78 | /// enable loop 79 | /// 80 | /// this object 81 | public TimeLine Loop() 82 | { 83 | IsLoop = true; 84 | return this; 85 | } 86 | 87 | /// 88 | /// enable auto reverse 89 | /// 90 | /// this object 91 | public TimeLine AutoReverse() 92 | { 93 | IsAutoReverse = true; 94 | return this; 95 | } 96 | 97 | /// 98 | /// time line 99 | /// 100 | /// is loop 101 | /// is auto reverse 102 | public TimeLine(bool isLoop = false, bool isAutoReverse = false) 103 | { 104 | IsLoop = isLoop; 105 | IsAutoReverse = isAutoReverse; 106 | } 107 | 108 | /// 109 | /// get total time line duration 110 | /// 111 | /// max duration of animations 112 | public double Duration 113 | => !Animations.Any() ? 0 114 | : _animations.Select(x => x.Duration).Max(); 115 | } 116 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Console/Unicode.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Component.Console 2 | { 3 | /// 4 | /// unicode characters 5 | /// 6 | public static class Unicode 7 | { 8 | #pragma warning disable CS1591 9 | 10 | public const char DoubleUnderline = '‗'; 11 | public const char Cross = '┼'; // 8224 12 | public const char OutlinedCross = '╬'; 13 | public const char Lire = '£'; 14 | public const char Yen = '¥'; 15 | public const char None = 'ø'; 16 | public const char ARet = '¶'; 17 | public const char Demi = '½'; 18 | public const char Quar = '¼'; 19 | public const char ThreeQuar = '¾'; 20 | public const char DoubleExclam = '‼'; 21 | public const char Exp1 = '¹'; 22 | public const char Exp2 = '²'; 23 | public const char Exp3 = '³'; 24 | public const char ExpRelease = '®'; 25 | public const char Copyright = '©'; 26 | public const char AE = 'Æ'; 27 | public const char AESmall = 'æ'; 28 | public const char Bull = '·'; 29 | public const char ArrowThickUp = '▲'; 30 | public const char ArrowThickDown = '▼'; 31 | public const char ArrowThickLeft = '◄'; 32 | public const char ArrowThickRight = '►'; 33 | public const char ArrowUp = '↑'; 34 | public const char ArrowRight = '→'; 35 | public const char ArrowDown = '↓'; 36 | public const char ArrowLeftRight = '↔'; 37 | public const char ArrowUpDown = '↕'; 38 | public const char ArrowUpDownUnderline = '↨'; 39 | public const char MoreOrLess = '±'; 40 | public const char CornerBottomLeft = '∟'; 41 | public const char BarSmallDottedVertical = '¦'; 42 | public const char LeftChevron = '«'; 43 | public const char RightChevron = '»'; 44 | public const char EdgeFlatTopRight = '¬'; 45 | public const char BarHorizontal = '─'; 46 | public const char BarVertical = '│'; 47 | public const char EdgeTopLeft = '┌'; 48 | public const char EdgeTopRight = '┐'; 49 | public const char EdgeBottomLeft = '└'; 50 | public const char EdgeBottomRight = '┘'; 51 | public const char EdgeRowLeft = '├'; 52 | public const char EdgeRowRight = '┤'; 53 | public const char EdgeColTop = '┬'; 54 | public const char EdgeColBottom = '┴'; 55 | public const char EdgeRowColCross = '┼'; 56 | public const char BarDoubleThickHorizontal = '▬'; 57 | public const char BarDoubleHorizontal = '═'; 58 | public const char BarDoubleVertical = '║'; 59 | public const char EdgeDoubleTopLeft = '╔'; 60 | public const char EdgeDoubleTopRight = '╗'; 61 | public const char EdgeDoubleBottomLeft = '╚'; 62 | public const char EdgeDoubleBottomRight = '╝'; 63 | public const char EdgeDoubleRowLeft = '╠'; 64 | public const char EdgeDoubleRowRight = '╣'; 65 | public const char EdgeDoubleColTop = '╦'; 66 | public const char EdgeDoubleColBottom = '╩'; 67 | public const char EdgeDoubleRowColCross = '╬'; 68 | public const char BoxHalfTop = '▀'; 69 | public const char BoxHalfBottom = '▄'; 70 | public const char Box = '█'; 71 | public const char BoxQuarLight = '░'; 72 | public const char BoxTierLight = '▒'; 73 | public const char BoxHalfLight = '▓'; 74 | public const char CardPic = '♠'; 75 | public const char CardTrefl = '♣'; 76 | public const char CardArt = '♥'; 77 | public const char CardCarro = '♦'; 78 | public const char SmileyTransp = '☺'; 79 | public const char Smiley = '☻'; 80 | 81 | #pragma warning restore CS1591 82 | 83 | } 84 | } -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Widgets/Animatics/IAnimation.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | 3 | using AnsiVtConsole.NetCore.Component.Widgets.Animatics.Easings; 4 | 5 | namespace AnsiVtConsole.NetCore.Component.Widgets.Animatics; 6 | 7 | /// 8 | /// animation 9 | /// 10 | public interface IAnimation 11 | { 12 | /// 13 | /// current value 14 | /// 15 | /// value type 16 | /// value 17 | TValue? Value() 18 | where TValue : class; 19 | 20 | /// 21 | /// from value 22 | /// 23 | /// value type 24 | /// value 25 | TValue? From() 26 | where TValue : class; 27 | 28 | /// 29 | /// to value 30 | /// 31 | /// value type 32 | /// value 33 | TValue? To() 34 | where TValue : class; 35 | 36 | /// 37 | /// value increment 38 | /// 39 | /// value type 40 | /// value 41 | TValue? Increment() 42 | where TValue : class; 43 | 44 | /// 45 | /// add target property of a class to animation 46 | /// 47 | /// linq expression that reference the target property of an object: () => obj.a.b.. Expression0<Func<ValueTypeglt;>> 48 | /// this object 49 | IAnimation For(LambdaExpression expression); 50 | 51 | /// 52 | /// add target property of a class to animation 53 | /// 54 | /// property name 55 | /// this object 56 | IAnimation For(string propertyName); 57 | 58 | /// 59 | /// add target property of an object to animation 60 | /// 61 | /// target 62 | /// property name 63 | /// this object 64 | IAnimation For(object target, string propertyName); 65 | 66 | /// 67 | /// add target property of an object to animation 68 | /// 69 | /// animation target object 70 | /// linq expression that reference the target property of an object: () => obj.a.b.. Expression0<Func<ValueTypeglt;>> 71 | /// this object 72 | IAnimation For(object target, LambdaExpression expression); 73 | 74 | /// 75 | /// setup target(s) for this animation 76 | /// 77 | /// one or several targets 78 | /// this object 79 | IAnimation Target(params object[] targets); 80 | 81 | /// 82 | /// duration (ms) 83 | /// 84 | /// value 85 | double Duration { get; } 86 | 87 | /// 88 | /// easing function 89 | /// 90 | public Easing Easing { get; } 91 | 92 | /// 93 | /// set the value for any position in the animation time line 94 | /// 95 | /// position (ms) 96 | /// timeline playing in reverse 97 | abstract void SetValueAt( 98 | double position, 99 | bool reverse); 100 | 101 | /// 102 | /// set the value for any position in the animation time line 103 | /// 104 | /// position (ms) 105 | abstract void SetValueAt(double position); 106 | 107 | } -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Console/EchoSequence.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CS1591 2 | 3 | using AnsiVtConsole.NetCore.Component.EchoDirective; 4 | 5 | namespace AnsiVtConsole.NetCore.Component.Console 6 | { 7 | public sealed class EchoSequence 8 | { 9 | public readonly EchoDirectives? PrintDirective; 10 | public readonly int FirstIndex; 11 | public readonly int LastIndex; 12 | public readonly string? Value; 13 | public readonly string? Text; 14 | public int Length => LastIndex - FirstIndex + 1; 15 | 16 | readonly IAnsiVtConsole _console; 17 | 18 | public EchoSequence( 19 | IAnsiVtConsole console, 20 | EchoDirectives? printDirective, 21 | int firstIndex, 22 | int lastIndex, 23 | string? value, 24 | string? text, 25 | int relIndex = 0) 26 | { 27 | _console = console; 28 | PrintDirective = printDirective; 29 | FirstIndex = firstIndex + relIndex; 30 | LastIndex = lastIndex + relIndex; 31 | Value = value; 32 | Text = text; 33 | } 34 | 35 | public EchoSequence( 36 | IAnsiVtConsole console, 37 | string? printDirective, 38 | int firstIndex, 39 | int lastIndex, 40 | string? value, 41 | string? text, 42 | int relIndex = 0) 43 | { 44 | _console = console; 45 | if (printDirective != null) 46 | { 47 | if (Enum.TryParse(printDirective, out var pr)) 48 | PrintDirective = pr; 49 | } 50 | 51 | FirstIndex = firstIndex + relIndex; 52 | LastIndex = lastIndex + relIndex; 53 | Value = value; 54 | Text = text; 55 | } 56 | 57 | public string ToText() 58 | { 59 | var s = ""; 60 | if (PrintDirective.HasValue && Value == null) 61 | { 62 | s += $"{_console.Settings.CommandBlockBeginChar}{PrintDirective}{_console.Settings.CommandBlockEndChar}"; 63 | } 64 | else 65 | { 66 | if (PrintDirective.HasValue && Value != null) 67 | s += $"{_console.Settings.CommandBlockBeginChar}{PrintDirective}{_console.Settings.CommandValueAssignationChar}{Value}{_console.Settings.CommandBlockEndChar}"; 68 | else 69 | s += Text; 70 | } 71 | return s; 72 | } 73 | 74 | public override string ToString() 75 | { 76 | var s = $"{FirstIndex}..{LastIndex}({Length}) "; 77 | if (PrintDirective.HasValue && Value == null) 78 | { 79 | s += $"{PrintDirective}"; 80 | } 81 | else 82 | { 83 | if (PrintDirective.HasValue && Value != null) 84 | s += $"{PrintDirective}={Value}"; 85 | else 86 | s += Text; 87 | } 88 | return s; 89 | } 90 | 91 | public string ToStringPattern() 92 | { 93 | var c = "-"; 94 | var s = ""; 95 | if (PrintDirective.HasValue && Value == null) 96 | { 97 | s += $"{c}{PrintDirective}{c}"; 98 | } 99 | else 100 | { 101 | if (PrintDirective.HasValue && Value != null) 102 | s += $"{c}{PrintDirective}={Value}{c}"; 103 | else 104 | s += Text; 105 | } 106 | return s; 107 | } 108 | 109 | public bool IsText => !PrintDirective.HasValue; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Widgets/Texts/Timers/TextTimer.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Component.Widgets.Texts.Timers; 2 | 3 | /// 4 | /// text animation 5 | /// 6 | public sealed class TextTimer : AnimatedWidget> 7 | { 8 | /// 9 | /// timer duration 10 | /// 11 | public TimeSpan Duration { get; private set; } 12 | 13 | /// 14 | /// duration to string presentation method 15 | /// 16 | public Func DurationToString { get; private set; } 17 | 18 | string _pattern; 19 | DateTime? _endTime; 20 | 21 | /// 22 | /// text timer 23 | /// 24 | /// text pattern. {0} indicates the duration 25 | /// frames per second 26 | /// timer duration 27 | /// eventually a personalized prensentation function of the duration 28 | public TextTimer( 29 | string text, 30 | double fps, 31 | TimeSpan duration, 32 | Func? durationToString = null 33 | ) : base(fps, new Text(string.Empty)) 34 | { 35 | _pattern = text; 36 | Duration = duration; 37 | DurationToString = durationToString ?? DefaultDurationToString; 38 | } 39 | 40 | /// 41 | /// text timer 42 | /// 43 | /// cursor x 44 | /// cursor y 45 | /// text pattern. {0} indicates the duration 46 | /// frames per second 47 | /// timer duration 48 | /// eventually a personalized prensentation function of the duration 49 | public TextTimer( 50 | int x, 51 | int y, 52 | string text, 53 | double fps, 54 | TimeSpan duration, 55 | Func? durationToString = null 56 | ) : base(x, y, fps, new Text(string.Empty)) 57 | { 58 | _pattern = text; 59 | Duration = duration; 60 | DurationToString = durationToString ?? DefaultDurationToString; 61 | } 62 | 63 | static string DefaultDurationToString(TimeSpan duration) 64 | { 65 | var r = string.Empty; 66 | if (duration.Days > 0) r += duration.Days + " day "; 67 | if (duration.Hours > 0) r += duration.Hours + " h "; 68 | if (duration.Minutes > 0) r += duration.Minutes + " min "; 69 | if (duration.Seconds > 0) r += duration.Seconds + " s "; 70 | if (duration.Milliseconds > 0) r += duration.Milliseconds + "ms"; 71 | return r; 72 | } 73 | 74 | /// 75 | protected override bool IsEnd() => DateTime.Now > _endTime; 76 | 77 | /// 78 | protected override void RenderFrame() 79 | { 80 | var remaining = DateTime.Now >= _endTime ? TimeSpan.FromSeconds(0) 81 | : _endTime!.Value - DateTime.Now; 82 | SetText( 83 | string.Format( 84 | _pattern, 85 | DurationToString(remaining))); 86 | } 87 | 88 | /// 89 | protected override void StartInit() 90 | => _endTime = DateTime.Now + Duration; 91 | 92 | /// 93 | protected override string RenderWidget(string render) 94 | => render; 95 | 96 | /// 97 | /// set the pattern 98 | /// 99 | /// pattern 100 | /// this object 101 | public TextTimer SetPattern(string pattern) 102 | { 103 | _pattern = pattern; 104 | return this; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /Component/Parser/ANSI/ansi-seq-patterns.txt: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------------- 2 | // ansi sequences patterns 3 | // from https://invisible-island.net/xterm/ctlseqs/ctlseqs.html 4 | // ----------------------------------------------------------------------------------- 5 | // in terminal wt,vscode we observe : 6 | // num? <-> numlist? 7 | // numlist := (;123456789)* 8 | // lowest priority rules are added to cover these cases 9 | // ----------------------------------------------------------------------------------- 10 | 11 | // ----------------------------------------------------------------------------------- 12 | // lexical 13 | // ----------------------------------------------------------------------------------- 14 | 15 | // scf (revision 1967) 16 | 17 | NONE := \x0 18 | SOH := \x1 19 | STX := \x2 20 | ETX := \x3 21 | EOT := \x4 22 | ENQ := \x5 23 | ACK := \x6 24 | BEL := \x7 25 | BS := \x8 26 | HT := \x9 27 | LF := \xa 28 | VT := \xb 29 | FF := \xC 30 | CR := \xd 31 | SO := \xe 32 | SI := \xf 33 | DLE := \x10 34 | DC1 := \x11 35 | DC2 := \x12 36 | DC3 := \x13 37 | DC4 := \x14 38 | NAK := \x15 39 | SYN := \x16 40 | ETB := \x17 41 | CAN := \x18 42 | EM := \x19 43 | SUB := \x1a 44 | ESC := \x1b 45 | FS := \x1c 46 | GS := \x1d 47 | RS := \x1e 48 | US := \x1f 49 | //SP := \x20 // is visible 50 | 51 | // C1 Control characters 52 | 53 | CSI := ESC [ 54 | OSC := ESC ] 55 | APC := ESC _ 56 | DCS := ESC P 57 | ST := ESC \ 58 | PM := ESC ^ 59 | 60 | // ----------------------------------------------------------------------------------- 61 | // syntactic rules 62 | // rule syntax: rule:= ( symbol | list_of_symbol | char | text | numlist? | num ) 63 | // list_of_symbol := symbol (,symbol)* 64 | // ----------------------------------------------------------------------------------- 65 | 66 | // single character functions (except ESC) 67 | NONE 68 | SOH 69 | STX 70 | ETX 71 | EOT 72 | ENQ 73 | ACK 74 | BEL 75 | BS 76 | HT 77 | LF 78 | VT 79 | FF 80 | CR 81 | SO 82 | SI 83 | DLE 84 | DC1 85 | DC2 86 | DC3 87 | DC4 88 | NAK 89 | SYN 90 | ETB 91 | CAN 92 | EM 93 | SUB 94 | FS 95 | GS 96 | RS 97 | US 98 | SP 99 | scf 100 | 101 | ESC D,E,H,M,N,O,P,V,W,X,Z,6,7,8,9,=,>,F,c,l,m,n,o,|,},~ 102 | ESC SP L,M,N 103 | ESC # 3,4,5,6,7,8,P,Q,R,q,p 104 | ESC % @,G 105 | 106 | // use \x2; as SP 107 | 108 | ESC ( A,B,C,H,K,Q,R,Y,Z,4,",%\x2;2,%\x2;6,%\x2;=,=,`,E,6,0,<,>,"\x2;4,"\x2;?,%\x2;0,%\x2;5,%\x2;4,%\x2;3,&\x2;5 109 | ESC * A,B,C,H,K,Q,R,Y,Z,4,",%\x2;2,%\x2;6,%\x2;=,=,`,E,6,0,<,>,"\x2;4,"\x2;?,%\x2;0,%\x2;5,%\x2;4,%\x2;3,&\x2;5 110 | ESC + A,B,C,H,K,Q,R,Y,Z,4,",%\x2;2,%\x2;6,%\x2;=,=,`,E,6,0,<,>,"\x2;4,"\x2;?,%\x2;0,%\x2;5,%\x2;4,%\x2;3,&\x2;5 111 | 112 | ESC - A,B,F,H,L,M 113 | ESC . A,B,F,H,L,M 114 | ESC / A,B,F,H,L,M 115 | 116 | // is ignored on reference terminals ? (TODO: check) 117 | // APC text ST NONE 118 | APC text 119 | 120 | // are ignored on reference terminals ? (TODO: check) 121 | // DCS 0,1, ; 0,1 | text ST 122 | // DCS $ m," p,SP q," q,r,s,t,$ |,* | text ST 123 | // DCS 1,2 $ t text ST 124 | // DCS + Q text ST 125 | // DCS + p text ST 126 | // DCS + q text ST 127 | DCS text 128 | 129 | CSI u 130 | CSI ! p 131 | CSI # q,{,} 132 | CSI numlist? ' w,x,z,{,|,},~ 133 | CSI numlist? " p,q 134 | CSI numlist? $ p,t,v,w,x,z,{,| 135 | CSI numlist? SP q,t,u 136 | CSI ? numlist? $ p 137 | CSI ? numlist? s,T,J,h,i,l,m,n,c 138 | CSI > numlist? m,n,p,q,t,T,m,n 139 | CSI numlist? * x,y,| 140 | CSI numlist? # y,{,Q,P,| 141 | CSI numlist? @,A,B,C,D,E,F,G,H,I,J,K,L,M,P,S,T,X,Z,^,`,a,b,d,e,i,f,g,h,r,t,q,x 142 | CSI numlist? SP @,A 143 | 144 | OSC numlist? BEL,ST 145 | PM numlist? ST 146 | 147 | CSI 1,2,3,4,5,6,7,8,9 ~ 148 | CSI 2 5 ~ 149 | CSI 2 6 ~ 150 | CSI 2 8 ~ 151 | CSI 2 9 ~ 152 | CSI 3 1 ~ 153 | CSI 3 2 ~ 154 | CSI 3 3 ~ 155 | CSI 3 4 ~ 156 | 157 | // extended rules 158 | 159 | ESC - char 160 | ESC . char 161 | ESC / char 162 | ESC + char,% char," char,& char 163 | ESC * char,% char," char,& char 164 | ESC ( char,% char," char,& char 165 | ESC % char 166 | ESC # char 167 | ESC SP char 168 | ESC char 169 | 170 | CSI numlist? char 171 | CSI ? numlist? char 172 | CSI ? num ; num ; char 173 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Parser/ANSI/ansi-seq-patterns.txt: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------------- 2 | // ansi sequences patterns 3 | // from https://invisible-island.net/xterm/ctlseqs/ctlseqs.html 4 | // ----------------------------------------------------------------------------------- 5 | // in terminal wt,vscode we observe : 6 | // num? <-> numlist? 7 | // numlist := (;123456789)* 8 | // lowest priority rules are added to cover these cases 9 | // ----------------------------------------------------------------------------------- 10 | 11 | // ----------------------------------------------------------------------------------- 12 | // lexical 13 | // ----------------------------------------------------------------------------------- 14 | 15 | // scf (revision 1967) 16 | 17 | NONE := \x0 18 | SOH := \x1 19 | STX := \x2 20 | ETX := \x3 21 | EOT := \x4 22 | ENQ := \x5 23 | ACK := \x6 24 | BEL := \x7 25 | BS := \x8 26 | HT := \x9 27 | LF := \xa 28 | VT := \xb 29 | FF := \xC 30 | CR := \xd 31 | SO := \xe 32 | SI := \xf 33 | DLE := \x10 34 | DC1 := \x11 35 | DC2 := \x12 36 | DC3 := \x13 37 | DC4 := \x14 38 | NAK := \x15 39 | SYN := \x16 40 | ETB := \x17 41 | CAN := \x18 42 | EM := \x19 43 | SUB := \x1a 44 | ESC := \x1b 45 | FS := \x1c 46 | GS := \x1d 47 | RS := \x1e 48 | US := \x1f 49 | //SP := \x20 // is visible 50 | 51 | // C1 Control characters 52 | 53 | CSI := ESC [ 54 | OSC := ESC ] 55 | APC := ESC _ 56 | DCS := ESC P 57 | ST := ESC \ 58 | PM := ESC ^ 59 | 60 | // ----------------------------------------------------------------------------------- 61 | // syntactic rules 62 | // rule syntax: rule:= ( symbol | list_of_symbol | char | text | numlist? | num ) 63 | // list_of_symbol := symbol (,symbol)* 64 | // ----------------------------------------------------------------------------------- 65 | 66 | // single character functions (except ESC) 67 | NONE 68 | SOH 69 | STX 70 | ETX 71 | EOT 72 | ENQ 73 | ACK 74 | BEL 75 | BS 76 | HT 77 | LF 78 | VT 79 | FF 80 | CR 81 | SO 82 | SI 83 | DLE 84 | DC1 85 | DC2 86 | DC3 87 | DC4 88 | NAK 89 | SYN 90 | ETB 91 | CAN 92 | EM 93 | SUB 94 | FS 95 | GS 96 | RS 97 | US 98 | SP 99 | scf 100 | 101 | ESC D,E,H,M,N,O,P,V,W,X,Z,6,7,8,9,=,>,F,c,l,m,n,o,|,},~ 102 | ESC SP L,M,N 103 | ESC # 3,4,5,6,7,8,P,Q,R,q,p 104 | ESC % @,G 105 | 106 | // use \x2; as SP 107 | 108 | ESC ( A,B,C,H,K,Q,R,Y,Z,4,",%\x2;2,%\x2;6,%\x2;=,=,`,E,6,0,<,>,"\x2;4,"\x2;?,%\x2;0,%\x2;5,%\x2;4,%\x2;3,&\x2;5 109 | ESC * A,B,C,H,K,Q,R,Y,Z,4,",%\x2;2,%\x2;6,%\x2;=,=,`,E,6,0,<,>,"\x2;4,"\x2;?,%\x2;0,%\x2;5,%\x2;4,%\x2;3,&\x2;5 110 | ESC + A,B,C,H,K,Q,R,Y,Z,4,",%\x2;2,%\x2;6,%\x2;=,=,`,E,6,0,<,>,"\x2;4,"\x2;?,%\x2;0,%\x2;5,%\x2;4,%\x2;3,&\x2;5 111 | 112 | ESC - A,B,F,H,L,M 113 | ESC . A,B,F,H,L,M 114 | ESC / A,B,F,H,L,M 115 | 116 | // is ignored on reference terminals ? (TODO: check) 117 | // APC text ST NONE 118 | APC text 119 | 120 | // are ignored on reference terminals ? (TODO: check) 121 | // DCS 0,1, ; 0,1 | text ST 122 | // DCS $ m," p,SP q," q,r,s,t,$ |,* | text ST 123 | // DCS 1,2 $ t text ST 124 | // DCS + Q text ST 125 | // DCS + p text ST 126 | // DCS + q text ST 127 | DCS text 128 | 129 | CSI u 130 | CSI ! p 131 | CSI # q,{,} 132 | CSI numlist? ' w,x,z,{,|,},~ 133 | CSI numlist? " p,q 134 | CSI numlist? $ p,t,v,w,x,z,{,| 135 | CSI numlist? SP q,t,u 136 | CSI ? numlist? $ p 137 | CSI ? numlist? s,T,J,h,i,l,m,n,c 138 | CSI > numlist? m,n,p,q,t,T,m,n 139 | CSI numlist? * x,y,| 140 | CSI numlist? # y,{,Q,P,| 141 | CSI numlist? @,A,B,C,D,E,F,G,H,I,J,K,L,M,P,S,T,X,Z,^,`,a,b,d,e,i,f,g,h,r,t,q,x 142 | CSI numlist? SP @,A 143 | 144 | OSC numlist? BEL,ST 145 | PM numlist? ST 146 | 147 | CSI 1,2,3,4,5,6,7,8,9 ~ 148 | CSI 2 5 ~ 149 | CSI 2 6 ~ 150 | CSI 2 8 ~ 151 | CSI 2 9 ~ 152 | CSI 3 1 ~ 153 | CSI 3 2 ~ 154 | CSI 3 3 ~ 155 | CSI 3 4 ~ 156 | 157 | // extended rules 158 | 159 | ESC - char 160 | ESC . char 161 | ESC / char 162 | ESC + char,% char," char,& char 163 | ESC * char,% char," char,& char 164 | ESC ( char,% char," char,& char 165 | ESC % char 166 | ESC # char 167 | ESC SP char 168 | ESC char 169 | 170 | CSI numlist? char 171 | CSI ? numlist? char 172 | CSI ? num ; num ; char 173 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Lib/StrExt.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CS1591 2 | 3 | using System.Text; 4 | using System.Text.RegularExpressions; 5 | 6 | namespace AnsiVtConsole.NetCore.Lib 7 | { 8 | /// 9 | /// string util extensions methods 10 | /// 11 | public static class StrExt 12 | { 13 | #region others 14 | 15 | public static Match Match(this string input, string regex) 16 | { 17 | var r = new Regex(regex); 18 | return r.Match(input); 19 | } 20 | 21 | public static void Match(this string input, string regex, out Match match) 22 | { 23 | var r = new Regex(regex); 24 | match = r.Match(input); 25 | } 26 | 27 | #endregion 28 | 29 | public static List SplitNotUnslashed(this string s, char c) 30 | { 31 | var r = new List(); 32 | var j = 0; 33 | bool matchsep; 34 | for (var i = 0; i < s.Length; i++) 35 | { 36 | if ((matchsep = s[i] == c) && i > 0 && s[i] - 1 != '\\') 37 | { 38 | r.Add(new string(s.AsSpan()[j..i])); 39 | j = i + 1; 40 | } 41 | else if ((matchsep = s[i] == c) && i == 0) 42 | { 43 | r.Add(""); 44 | j = i + 1; 45 | } 46 | } 47 | 48 | if (j < s.Length) 49 | r.Add(new string(s[j..])); 50 | return r; 51 | } 52 | 53 | public static List SplitByPrefixsNotUnslashed(this string s, List chars) 54 | { 55 | var r = new List(); 56 | var j = 0; 57 | bool matchsep; 58 | s = new string(s.Reverse().ToArray()); 59 | for (var i = 0; i < s.Length; i++) 60 | { 61 | if ((matchsep = chars.Contains(s[i])) && i > 0 && s[i] - 1 != '\\') 62 | { 63 | r.Add(new string(s.Substring(j, i - j + 1))); 64 | j = i + 1; 65 | } 66 | else if ((matchsep = chars.Contains(s[i])) && i == 0) 67 | { 68 | r.Add(""); 69 | j = i + 1; 70 | } 71 | } 72 | 73 | if (j < s.Length) 74 | r.Add(new string(s[j..])); 75 | return r.Select(x => new string(x.Reverse().ToArray())).ToList(); 76 | } 77 | 78 | /// 79 | /// indicates if the string contains at least one of the characters 80 | /// 81 | /// string 82 | /// chars list 83 | /// 84 | public static bool Contains(this string s, List chars) 85 | { 86 | foreach (var c in chars) 87 | { 88 | if (s.Contains(c)) 89 | return true; 90 | } 91 | 92 | return false; 93 | } 94 | 95 | public static bool IsUpperCase(this string s) 96 | { 97 | foreach (var c in s) 98 | { 99 | if (!char.IsUpper(c)) 100 | return false; 101 | } 102 | 103 | return true; 104 | } 105 | 106 | public static bool EndsWith(this string s, List postfixs) 107 | { 108 | foreach (var p in postfixs) 109 | { 110 | if (s.EndsWith(p)) 111 | return true; 112 | } 113 | 114 | return false; 115 | } 116 | 117 | public static bool ContainsDigit(this string s) 118 | { 119 | foreach (var c in s) 120 | { 121 | if (char.IsDigit(c)) 122 | return true; 123 | } 124 | 125 | return false; 126 | } 127 | 128 | public static string RemoveDigits(this string s) 129 | { 130 | var sb = new StringBuilder(); 131 | foreach (var c in s) 132 | { 133 | if (!char.IsDigit(c)) 134 | sb.Append(c); 135 | } 136 | 137 | return sb.ToString(); 138 | } 139 | } 140 | } -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Lib/TextFileReader.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CS1591 2 | 3 | using System.Runtime.InteropServices; 4 | 5 | namespace AnsiVtConsole.NetCore.Lib 6 | { 7 | public static class TextFileReader 8 | { 9 | public static ((int count, string separator, OSPlatform eol) detectedEOL, 10 | List<(int count, string separator, OSPlatform eol)> eolCounts, 11 | string[] lines) GetEOLCounts(string txt) 12 | { 13 | string[]? r = null; 14 | 15 | var sep_crcrlf = "\r\r\n"; 16 | var sep_linux = "\n"; 17 | var sep_osx = "\r"; 18 | var sep_windows = "\r\n"; 19 | var sep_qnx_pre_posix = "" + (char)30; 20 | var sep_unicode_VT = "\u000B"; 21 | var sep_unicode_FF = "\u000C"; 22 | var sep_unicode_NEL = "\u0085"; 23 | var sep_unicode_LS = "\u2028"; 24 | var sep_unicode_PS = "\u2029"; 25 | var eols = new List<(string separator, OSPlatform eol)> 26 | { 27 | (sep_windows,OSPlatform.Windows), 28 | (sep_linux,OSPlatform.Linux), 29 | (sep_osx,OSPlatform.OSX), 30 | (sep_osx, OSPlatform.Create("QNX pre-POSIX")), 31 | (sep_unicode_VT,OSPlatform.Create("Unicode VT")), 32 | (sep_unicode_FF,OSPlatform.Create("Unicode FF")), 33 | (sep_unicode_NEL,OSPlatform.Create("Unicode NEL")), 34 | (sep_unicode_LS,OSPlatform.Create("Unicode LS")), 35 | (sep_unicode_PS,OSPlatform.Create("Unicode PS")), 36 | }; 37 | 38 | static (int count, string separator, OSPlatform eol) Count(string searched, string txt, OSPlatform eol) 39 | { 40 | var i = 0; 41 | var cnt = 0; 42 | while (i < txt.Length && i > -1) 43 | { 44 | if ((i = txt.IndexOf(searched, i)) > -1) 45 | { 46 | cnt++; 47 | i++; 48 | } 49 | } 50 | 51 | return (cnt, searched, eol); 52 | } 53 | OSPlatform? detectedOspl = null; 54 | var counts = new List<(int count, string separator, OSPlatform eol)>(); 55 | 56 | var cnt_doublecrlf = Count(sep_crcrlf, txt, OSPlatform.Create("CRCRLF")); 57 | if (cnt_doublecrlf.count > 0) 58 | { 59 | txt = txt.Replace(cnt_doublecrlf.separator, sep_windows); 60 | detectedOspl = cnt_doublecrlf.eol; 61 | } 62 | foreach (var eol in eols) 63 | counts.Add(Count(eol.separator, txt, eol.eol)); 64 | 65 | var max = counts.Max((x) => x.count); 66 | 67 | // check by order which encoding has the most count 68 | (int count, string separator, OSPlatform eol)? matchEOL = null; 69 | 70 | foreach (var eol in eols) 71 | { 72 | var check = counts.Where(x => x.separator == eol.separator).First(); 73 | if (check.count == max) 74 | { 75 | matchEOL = check; 76 | r = txt.Split(check.separator); 77 | if (!detectedOspl.HasValue) 78 | detectedOspl = check.eol; 79 | break; 80 | } 81 | } 82 | 83 | if (!detectedOspl.HasValue) 84 | { 85 | // eol not detected, returns whole file in a single line 86 | matchEOL = (0, string.Empty, OSPlatform.Create("?")); 87 | r = new string[] { txt }; 88 | } 89 | return (matchEOL!.Value, counts, r!); 90 | } 91 | 92 | /// 93 | /// read all lines of a text file, according to detected eol symbol after any eventual eol symbols clean up 94 | /// use default file encoding 95 | /// 96 | /// 97 | /// (text of the file splited into lines,eol symbol plateform style name,detected eol symbol 98 | public static (string[] lines, OSPlatform eol, string separator) ReadAllLines(string path) 99 | { 100 | var txt = File.ReadAllText(path); 101 | var (detectedEOL, _, lines) = GetEOLCounts(txt); 102 | return (lines, detectedEOL.eol, detectedEOL.separator); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Widgets/Texts/Coloring/Gradient.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | using AnsiVtConsole.NetCore.Component.Widgets.Models; 4 | 5 | using static AnsiVtConsole.NetCore.Component.Console.ANSI; 6 | 7 | namespace AnsiVtConsole.NetCore.Component.Widgets.Texts.Coloring; 8 | 9 | /// 10 | /// raimbow text 11 | /// 12 | public sealed class Gradient : Widget> 13 | { 14 | /// 15 | /// origin RGB of the gradient 16 | /// 17 | public Rgb OriginRGB { get; private set; } = new(0, 0, 128); 18 | 19 | /// 20 | /// current RGB of the gradient 21 | /// 22 | public Rgb Rgb { get; private set; } = new(); 23 | 24 | /// 25 | /// delta RGB of the gradient 26 | /// 27 | public Rgb DRgb { get; private set; } = new(4, 9, 14); 28 | 29 | /// 30 | /// text 31 | /// 32 | public Text Text => (Text)WrappedWidget!; 33 | 34 | readonly StringBuilder _sb = new(); 35 | 36 | /// 37 | /// gradient 38 | /// 39 | /// 40 | public Gradient(string text) : base(new Text(text)) { } 41 | 42 | /// 43 | /// gradient 44 | /// 45 | /// cursor x 46 | /// cursor y 47 | /// 48 | public Gradient(int x, int y, string text) : base(x, y, new Text(text)) { } 49 | 50 | /// 51 | public Gradient(IWidget wrappedWidget) 52 | : base(wrappedWidget) { } 53 | 54 | /// 55 | /// set origin r,g,b of the gradient 56 | /// 57 | /// oring R of the gradient 58 | /// oring G of the gradient 59 | /// oring B of the gradient 60 | /// this object 61 | public Gradient Origin(int r, int g, int b) 62 | { 63 | OriginRGB = new(r, g, b); 64 | return this; 65 | } 66 | 67 | /// 68 | /// set origin r,g,b of the gradient 69 | /// 70 | /// rgb 71 | /// this object 72 | public Gradient Origin(Rgb rgb) 73 | { 74 | OriginRGB = rgb; 75 | return this; 76 | } 77 | 78 | /// 79 | /// setup cyclic gradient with dr,dg,db increments 80 | /// 81 | /// delta R 82 | /// delta G 83 | /// detla B 84 | /// this object 85 | public Gradient CyclicGradient(int dr, int dg, int db) 86 | { 87 | DRgb = new(dr, dg, db); 88 | return this; 89 | } 90 | 91 | /// 92 | /// setup cyclic gradient with dr,dg,db increments 93 | /// 94 | /// rgb 95 | /// this object 96 | public Gradient CyclicGradient(Rgb rgb) 97 | { 98 | DRgb = rgb; 99 | return this; 100 | } 101 | 102 | /// 103 | protected override string RenderWidget(string render) 104 | { 105 | _sb.Clear(); 106 | 107 | var t = render!.ToCharArray(); 108 | foreach (var c in t) 109 | { 110 | if (c == '\n') 111 | { 112 | Rgb.Set(OriginRGB); 113 | } 114 | Rgb = NextColor(Rgb, DRgb); 115 | 116 | _sb.Append(SGR_SetForegroundColor24bits(Rgb.R, Rgb.G, Rgb.B)); 117 | _sb.Append(c); 118 | } 119 | return _sb.ToString(); 120 | } 121 | 122 | static Rgb NextColor(Rgb rgb, Rgb drgb) 123 | { 124 | var r = rgb.R + drgb.R; 125 | var g = rgb.G + drgb.G; 126 | var b = rgb.B + drgb.B; 127 | if (r < 0) 128 | { 129 | r = 0; 130 | drgb.R = drgb.R * -1; 131 | } 132 | if (r > 255) 133 | { 134 | r = 255; 135 | drgb.R = drgb.R *= -1; 136 | } 137 | if (g < 0) 138 | { 139 | g = 0; 140 | drgb.G = drgb.G * -1; 141 | } 142 | if (g > 255) 143 | { 144 | g = 255; 145 | drgb.G = drgb.G *= -1; 146 | } 147 | if (b < 0) 148 | { 149 | b = 0; 150 | drgb.B = drgb.B * -1; 151 | } 152 | if (b > 255) 153 | { 154 | b = 255; 155 | drgb.B = drgb.B *= -1; 156 | } 157 | rgb.Set(r, g, b); 158 | return rgb; 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Console/ASCII.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CS1591 2 | 3 | namespace AnsiVtConsole.NetCore.Component.Console 4 | { 5 | /// 6 | /// all ASCII codes that we take into account for the targetted terminals referential 7 | /// from https://en.wikipedia.org/wiki/ANSI_escape_code 8 | /// 9 | public static class ASCII 10 | { 11 | #region codes 12 | 13 | public const char NUL = (char)0; 14 | public const char SOH = (char)1; 15 | public const char STX = (char)2; 16 | public const char ELX = (char)3; 17 | public const char EOT = (char)4; 18 | public const char ENQ = (char)5; 19 | public const char ACK = (char)6; 20 | public const char BEL = (char)7; 21 | public const char BS = (char)8; 22 | public const char HT = (char)9; 23 | public const char LF = (char)10; 24 | public const char VT = (char)11; 25 | public const char FF = (char)12; 26 | public const char CR = (char)13; 27 | public const char SO = (char)14; 28 | public const char SI = (char)15; 29 | public const char DLE = (char)16; 30 | public const char DC1 = (char)17; 31 | public const char DC2 = (char)18; 32 | public const char DC3 = (char)19; 33 | public const char DC4 = (char)20; 34 | public const char NAK = (char)21; 35 | public const char SYN = (char)22; 36 | public const char ETB = (char)23; 37 | public const char CAN = (char)24; 38 | public const char EM = (char)25; 39 | public const char SUB = (char)26; 40 | public const char ESC = (char)27; 41 | public const char FS = (char)28; 42 | public const char GS = (char)29; 43 | public const char RS = (char)30; 44 | public const char US = (char)31; 45 | public const char SP = (char)32; 46 | 47 | #endregion 48 | 49 | #region texts (that should be understandable in command line and kernel methods) 50 | 51 | public const string NUL_TXT = "\\0"; 52 | public const string BEL_TXT = "\\a"; 53 | public const string BS_TXT = "\\b"; 54 | public const string HT_TXT = "\\t"; 55 | public const string LF_TXT = "\\n"; 56 | public const string VT_TXT = "\\v"; 57 | public const string FF_TXT = "\\f"; 58 | public const string CR_TXT = "\\r"; 59 | public const string ESC_TXT = "\\e"; 60 | 61 | #endregion 62 | 63 | #region util 64 | 65 | static Dictionary? _codesToNames = null; 66 | static readonly Dictionary? _codesToTexts = new() 67 | { 68 | { NUL, NUL_TXT }, 69 | { BEL, BEL_TXT }, 70 | { BS, BS_TXT }, 71 | { HT, HT_TXT }, 72 | { LF, LF_TXT }, 73 | { VT, VT_TXT }, 74 | { FF, FF_TXT }, 75 | { CR, CR_TXT }, 76 | { ESC, ESC_TXT }, 77 | }; 78 | 79 | static void RequireCodesToNames() 80 | { 81 | if (_codesToNames != null) 82 | return; 83 | _codesToNames = new Dictionary(); 84 | var fields = typeof(ASCII).GetFields(); 85 | if (fields != null) 86 | { 87 | foreach (var field in fields) 88 | { 89 | if (!field.Name.EndsWith("_TXT")) 90 | _codesToNames.Add((char)field!.GetValue(null)!, field.Name); 91 | } 92 | } 93 | } 94 | 95 | static string GetPreferredRepresentation( 96 | char c, 97 | string labelFormat = "<{0}>", 98 | string textFormat = "{0}", 99 | bool escapablesOnly = false) 100 | { 101 | if (_codesToTexts!.TryGetValue(c, out var txt)) 102 | return string.Format(textFormat, txt); 103 | return escapablesOnly ? 104 | c + "" 105 | : string.Format(labelFormat, _codesToNames![c]); 106 | } 107 | 108 | public static string GetNonPrintablesCodesAsLabel( 109 | string s, 110 | bool includeSP, 111 | bool escapablesOnly = false, 112 | string labelFormat = "<{0}>", 113 | string textFormat = "{0}") 114 | { 115 | RequireCodesToNames(); 116 | var r = ""; 117 | foreach (var c in s) 118 | { 119 | var min = SP + (includeSP ? 0 : -1); 120 | r += (c <= min) ? GetPreferredRepresentation( 121 | c, 122 | labelFormat, 123 | textFormat, 124 | escapablesOnly) : "" + c; 125 | } 126 | return r; 127 | } 128 | 129 | #endregion 130 | } 131 | } -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore.Imaging/Component/Widgets/Images/Image.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | using AnsiVtConsole.NetCore.Component.Widgets; 4 | 5 | using SkiaSharp; 6 | 7 | using static AnsiVtConsole.NetCore.Component.Console.ANSI; 8 | 9 | namespace AnsiVtConsole.NetCore.Imaging.Component.Widgets.Images; 10 | 11 | /// 12 | /// iamge to ansi widget 13 | /// 14 | public sealed class Image : Widget> 15 | { 16 | /// 17 | /// text 18 | /// 19 | public string? Filename { get; private set; } 20 | 21 | /// 22 | /// width 23 | /// 24 | public int? Width { get; private set; } 25 | 26 | /// 27 | /// height 28 | /// 29 | public int? Height { get; private set; } 30 | 31 | /// 32 | /// pixel char function 33 | /// 34 | public Func PixelChar { get; private set; } 35 | 36 | /// 37 | /// if true the bitmap is painted on background 38 | /// 39 | public bool PaintOnBackground { get; private set; } 40 | 41 | const string DefaultPixelChar = " "; 42 | 43 | SKBitmap? _image; 44 | SKBitmap? _scaledImage; 45 | StringBuilder? _sb; 46 | 47 | /// 48 | /// widget image 49 | /// if both width and height are null use the image size 50 | /// if height is null it is computed according to the image width/height ratio 51 | /// if width is null it is computed according to the image width/height ratio 52 | /// 53 | /// filename 54 | /// width 55 | /// height 56 | /// if true the bitmap is painted on background 57 | /// a function that gives the string to draw a pixel from position x and y (default is " ") 58 | public Image( 59 | string filename, 60 | int? width = null, 61 | int? height = null, 62 | bool paintOnBackground = true, 63 | Func? pixelChar = null) 64 | { 65 | if (width is not null && width <= 0) 66 | throw new ArgumentException("width must be > 0"); 67 | if (height is not null && height <= 0) 68 | throw new ArgumentException("height must be > 0"); 69 | Width = width; 70 | Height = height; 71 | Filename = filename; 72 | PixelChar = pixelChar ?? DefaultPixelCharFunc; 73 | PaintOnBackground = paintOnBackground; 74 | } 75 | 76 | string DefaultPixelCharFunc(int x, int y, SKColor color) => DefaultPixelChar; 77 | 78 | /// 79 | public Image(IWidget wrappedWidget) 80 | : base(wrappedWidget) 81 | => throw new NotImplementedException(); 82 | 83 | string GetImage() 84 | { 85 | if (_image is null) 86 | { 87 | _image = SKBitmap.Decode(Filename); 88 | if (_image is null) 89 | throw new InvalidOperationException($"failed to load or decode image: " + Filename); 90 | } 91 | 92 | if (_scaledImage is null && Width is not null) 93 | { 94 | _scaledImage = new SKBitmap(Width!.Value, Height!.Value); 95 | if (!_image.ScalePixels(_scaledImage, SKFilterQuality.High)) 96 | throw new InvalidOperationException($"failed to scale image: {Filename} from ({_image.Width},{_image.Height}) to ({Width},{Height})"); 97 | } 98 | 99 | var image = Width is null ? _image : _scaledImage; 100 | if (_sb is null) 101 | _sb = new StringBuilder(image!.Width * image.Height * 16 + image.Height * 18); 102 | else _sb.Clear(); 103 | 104 | var curY = Y; 105 | 106 | var pixels = image!.Pixels; 107 | var pixelIndex = 0; 108 | for (var y = 0; y < image.Height; y++) 109 | { 110 | for (var x = 0; x < image.Width; x++) 111 | { 112 | var color = pixels[pixelIndex++]; 113 | var alpha = color.Alpha / 255d; 114 | var red = (int)Math.Round(color.Red * alpha); 115 | var green = (int)Math.Round(color.Green * alpha); 116 | var blue = (int)Math.Round(color.Blue * alpha); 117 | _sb.Append( 118 | (PaintOnBackground ? 119 | SGR_SetBackgroundColor24bits( 120 | red, 121 | green, 122 | blue 123 | ) 124 | : SGR_SetForegroundColor24bits( 125 | red, 126 | green, 127 | blue 128 | )) 129 | + PixelChar(x, y, color)); 130 | } 131 | _sb.Append(RSTXTA + CRLF); 132 | if (y != image.Height) 133 | _sb.Append(CUP(X + 1, Y + 1 + y)); 134 | } 135 | 136 | return _sb.ToString(); 137 | } 138 | 139 | /// 140 | protected override string RenderWidget() => GetImage(); 141 | } 142 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Console/Logger.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Component.Console; 2 | 3 | /// 4 | /// logger 5 | /// log to console, can forwards to System.Diagnostics.Debug 6 | /// 7 | public sealed class Logger 8 | { 9 | readonly ConsoleTextWriterWrapper _out; 10 | readonly IAnsiVtConsole _console; 11 | readonly Error _err; 12 | readonly Warn _warn; 13 | readonly string[] _crlf = { Environment.NewLine }; 14 | 15 | internal Logger( 16 | IAnsiVtConsole console, 17 | ConsoleTextWriterWrapper @out, 18 | Error err, 19 | Warn warn 20 | ) 21 | { 22 | _console = console; 23 | _out = @out; 24 | _err = err; 25 | _warn = warn; 26 | } 27 | 28 | /// 29 | /// log an error 30 | /// 31 | /// exception 32 | /// enable or disable to replicate log to System.Diagnostics.Debug 33 | public void LogError(Exception exception, bool enableForwardLogsToSystemDiagnostics = true) 34 | { 35 | if (_console.Settings.ForwardLogsToSystemDiagnostics && enableForwardLogsToSystemDiagnostics) 36 | System.Diagnostics.Debug.WriteLine(exception + ""); 37 | if (_console.Settings.DumpExceptions) 38 | { 39 | LogError(exception, string.Empty, enableForwardLogsToSystemDiagnostics); 40 | } 41 | else 42 | { 43 | var msg = exception.Message; 44 | while (exception.InnerException != null) 45 | { 46 | exception = exception.InnerException; 47 | msg += _crlf + exception.Message; 48 | } 49 | var ls = msg.Split(_crlf, StringSplitOptions.None) 50 | .Select(x => _console.Colors.Error + x); 51 | _err.LogLine(ls); 52 | } 53 | } 54 | 55 | /// 56 | /// log an error 57 | /// 58 | /// exception 59 | /// message 60 | /// enable or disable to replicate log to System.Diagnostics.Debug 61 | public void LogError(Exception exception, string message = "", bool enableForwardLogsToSystemDiagnostics = true) 62 | { 63 | if (_console.Settings.ForwardLogsToSystemDiagnostics && enableForwardLogsToSystemDiagnostics) 64 | System.Diagnostics.Debug.WriteLine(message + _crlf + exception + ""); 65 | var ls = new List(); 66 | if (_console.Settings.DumpExceptions) 67 | { 68 | ls = (exception + "").Split(_crlf, StringSplitOptions.None) 69 | .Select(x => _console.Colors.Error + x) 70 | .ToList(); 71 | if (message != null) 72 | ls.Insert(0, $"{_console.Colors.Error}{message}"); 73 | } 74 | else 75 | { 76 | ls.Insert(0, $"{_console.Colors.Error}{message}: {exception.Message}"); 77 | } 78 | 79 | _err.LogLine(ls); 80 | } 81 | 82 | /// 83 | /// log an error 84 | /// 85 | /// message 86 | /// enable or disable to replicate log to System.Diagnostics.Debug 87 | public void LogError(string message = "", bool enableForwardLogsToSystemDiagnostics = true) 88 | { 89 | if (_console.Settings.ForwardLogsToSystemDiagnostics && enableForwardLogsToSystemDiagnostics) 90 | System.Diagnostics.Debug.WriteLine(message); 91 | var ls = (message + "").Split(_crlf, StringSplitOptions.None) 92 | .Select(x => _console.Colors.Error + x); 93 | _err.LogLine(ls); 94 | } 95 | 96 | /// 97 | /// log a warning 98 | /// 99 | /// message 100 | /// enable or disable to replicate log to System.Diagnostics.Debug 101 | public void LogWarning(string message = "", bool enableForwardLogsToSystemDiagnostics = true) 102 | { 103 | if (_console.Settings.ForwardLogsToSystemDiagnostics && enableForwardLogsToSystemDiagnostics) 104 | System.Diagnostics.Debug.WriteLine(message); 105 | var ls = (message + "").Split(_crlf, StringSplitOptions.None) 106 | .Select(x => _console.Colors.Warning + x); 107 | _warn.LogLine(ls); 108 | } 109 | 110 | /// 111 | /// log a message 112 | /// 113 | /// message 114 | /// enable or disable to replicate log to System.Diagnostics.Debug 115 | public void Log(string message = "", bool enableForwardLogsToSystemDiagnostics = true) 116 | { 117 | if (_console.Settings.ForwardLogsToSystemDiagnostics && enableForwardLogsToSystemDiagnostics) 118 | System.Diagnostics.Debug.WriteLine(message); 119 | var ls = (message + "").Split(_crlf, StringSplitOptions.None) 120 | .Select(x => _console.Colors.Log + x); 121 | foreach (var l in ls) 122 | _out.WriteLine(l); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Widgets/Animatics/Animator.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | using Microsoft.CodeAnalysis; 4 | 5 | namespace AnsiVtConsole.NetCore.Component.Widgets.Animatics; 6 | 7 | /// 8 | /// sequential play of timelines 9 | /// 10 | public sealed class Animator 11 | { 12 | /// 13 | /// indicates if animation is playing or not 14 | /// 15 | public bool IsRunning { get; private set; } 16 | 17 | bool _end = false; 18 | readonly Animation _animation; 19 | TimeLine? _timeLine; 20 | int _timeLineIndex; 21 | double _timeLapse; 22 | DateTime? _timeLineStartTime; 23 | DateTime? _timeLineEndTime; 24 | double _sumAnimationDuration; 25 | int _tick; 26 | 27 | /// 28 | /// on start event 29 | /// 30 | public event EventHandler OnStart; 31 | 32 | /// 33 | /// on stop event 34 | /// 35 | public event EventHandler OnStop; 36 | 37 | #pragma warning disable CS8618 38 | /// 39 | /// animator 40 | /// 41 | /// played animation 42 | public Animator(Animation animation) => _animation = animation; 43 | #pragma warning restore CS8618 44 | 45 | /// 46 | /// starts an animation 47 | /// 48 | public void Start() 49 | { 50 | IsRunning = true; 51 | _timeLapse = GetTimeLapse(); 52 | 53 | if (!_animation.TimeLines.Any()) 54 | return; 55 | 56 | OnStart?.Invoke(this, EventArgs.Empty); 57 | 58 | new Thread(() => RunAnimation(_animation)) 59 | .Start(); 60 | } 61 | 62 | /// 63 | /// stops the animation 64 | /// 65 | public void Stop() 66 | { 67 | _end = true; 68 | IsRunning = false; 69 | OnStop?.Invoke(this, EventArgs.Empty); 70 | } 71 | 72 | void Start(bool reverse, TimeLine timeLine) 73 | { 74 | #if DEBUG 75 | _tick = 0; 76 | #endif 77 | _sumAnimationDuration = 0; 78 | _timeLine = timeLine; 79 | _timeLineStartTime = DateTime.Now; 80 | _timeLineEndTime = _timeLineStartTime!.Value.Add( 81 | TimeSpan.FromMilliseconds(_timeLine.Duration)); 82 | _end = false; 83 | } 84 | 85 | double GetTimeLapse() 86 | => 1 / _animation.Fps * 1000; 87 | 88 | void RunAnimation(object? obj) 89 | { 90 | #if DEBUG 91 | Dbg($"start timeline {_timeLineIndex} | fps={_animation.Fps} | timeLapse = {_timeLapse} ms"); 92 | #endif 93 | 94 | var reverse = false; 95 | var reverseCount = 0; 96 | 97 | while (IsRunning && _timeLineIndex < _animation.TimeLines.Count) 98 | { 99 | Start(reverse, _animation.TimeLines[_timeLineIndex]); 100 | 101 | #if DEBUG 102 | Dbg($"start timeline {_timeLineIndex} : {_timeLine!.Duration} ms"); 103 | #endif 104 | 105 | while (!_end) 106 | { 107 | var time = DateTime.Now; 108 | _end = time > _timeLineEndTime; 109 | 110 | var position = !reverse ? 111 | (time - _timeLineStartTime!.Value) 112 | .TotalMilliseconds 113 | : (_timeLineEndTime!.Value - time) 114 | .TotalMilliseconds; 115 | 116 | var frameStartTime = DateTime.Now; 117 | 118 | foreach (var animation in _timeLine!.Animations) 119 | { 120 | #if DEBUG 121 | Dbg($"animate tick {_tick} position {position} : {animation} # {DateStr(DateTime.Now)} (-> {DateStr(_timeLineEndTime!.Value)})"); 122 | #endif 123 | animation.SetValueAt( 124 | Math.Min( 125 | animation.Duration, position), 126 | reverse); 127 | } 128 | 129 | _tick++; 130 | _timeLine.Render(); 131 | 132 | var frameDuration = (DateTime.Now - frameStartTime).TotalMilliseconds; 133 | _sumAnimationDuration += frameDuration; 134 | 135 | if (frameDuration > _timeLapse) 136 | Debug.WriteLine( 137 | $"animation frame time overriden: took {frameDuration}ms but frame length is {_timeLapse} ms"); 138 | 139 | var wait = Math.Max(0, _timeLapse - frameDuration); 140 | 141 | #if DEBUG 142 | Debug.WriteLine($"frame: duration={frameDuration} ms | time lapse = {_timeLapse} ms | wait = {wait} ms"); 143 | #endif 144 | Thread.Sleep((int)wait); 145 | } 146 | 147 | if (_timeLine!.IsAutoReverse) 148 | reverse = !reverse; 149 | #if DEBUG 150 | if (_tick > 0) 151 | Debug.WriteLine($"average animation duration = {_sumAnimationDuration / _tick} ms. frame delay = {_timeLapse} ms"); 152 | #endif 153 | if (!_timeLine.IsLoop || !(_timeLine.IsAutoReverse && reverseCount == 0)) 154 | _timeLineIndex++; 155 | } 156 | 157 | IsRunning = false; 158 | OnStop?.Invoke(this, EventArgs.Empty); 159 | } 160 | 161 | #if DEBUG 162 | static string DateStr(DateTime d) 163 | => $"{d.Hour}:{d.Month}:{d.Second}:{d.Millisecond}"; 164 | 165 | static void Dbg(string text) => System.Diagnostics.Debug.WriteLine(text); 166 | #endif 167 | } 168 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Console/ColorSettings.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Component.Console; 2 | 3 | /// 4 | /// predefined colors 5 | /// 6 | public sealed class ColorSettings 7 | { 8 | readonly IAnsiVtConsole _console; 9 | 10 | /// 11 | /// attach the settings to a console 12 | /// 13 | /// console 14 | public ColorSettings(IAnsiVtConsole console) => _console = console; 15 | 16 | /// 17 | /// defaults shell foreground and background - if is setted. designed to preserve console default background transparency 18 | /// 19 | /// text color 20 | public TextColor Default => new( 21 | _console.Settings.DefaultForeground, 22 | _console.Settings.DefaultBackground, ANSI.RSTXTA); 23 | 24 | /// 25 | /// inverted default shell foreground and background 26 | /// 27 | public TextColor Inverted => new( 28 | _console.Settings.DefaultBackground, 29 | _console.Settings.DefaultForeground); 30 | 31 | // states colors 32 | 33 | #pragma warning disable CS1591 34 | 35 | public TextColor Log = new(ConsoleColor.Green, null); 36 | public TextColor Error = new(ConsoleColor.Red, null); 37 | public TextColor Success = new(ConsoleColor.Green, null); 38 | public TextColor Warning = new(ConsoleColor.DarkYellow, null); 39 | public TextColor Debug = new(ConsoleColor.Green, null); 40 | 41 | // states as text in a box 42 | 43 | public TextColor BoxOk = new(ConsoleColor.White, ConsoleColor.DarkGreen); 44 | public TextColor BoxError = new(ConsoleColor.Yellow, ConsoleColor.Red); 45 | public TextColor BoxUnknown = new(ConsoleColor.Green, ConsoleColor.DarkCyan); 46 | public TextColor BoxNotIdentified = new(ConsoleColor.Yellow, ConsoleColor.Red); 47 | public TextColor Information = new(ConsoleColor.DarkCyan, null); 48 | public TextColor TextExtract = new(ConsoleColor.Green, null); 49 | public TextColor TextExtractSelectionBlock = new(ConsoleColor.Yellow, ConsoleColor.Green); 50 | 51 | public TextColor TaskInformation = new(ConsoleColor.Blue, null); 52 | 53 | // UI 54 | 55 | public TextColor TitleBar = new(ConsoleColor.White, ConsoleColor.DarkBlue); 56 | public TextColor TitleDarkText = new(ConsoleColor.Gray, ConsoleColor.DarkBlue); 57 | public TextColor InteractionBar = new(ConsoleColor.White, ConsoleColor.DarkBlue); 58 | public TextColor InteractionPanel = new(ConsoleColor.White, ConsoleColor.DarkBlue); 59 | public TextColor InteractionPanelCmdKeys = new(ConsoleColor.Black, ConsoleColor.White); 60 | public TextColor InteractionPanelDisabledCmdKeys = new(ConsoleColor.DarkGray, ConsoleColor.Black); 61 | 62 | public TextColor InteractionPanelCmdLabel = new(ConsoleColor.Yellow, ConsoleColor.DarkBlue); 63 | public TextColor InteractionPanelDisabledCmdLabel = new(ConsoleColor.DarkGray, ConsoleColor.DarkBlue); 64 | 65 | // system library types 66 | 67 | public TextColor ExceptionText = new(ConsoleColor.Red, null); 68 | public TextColor ExceptionName = new(ConsoleColor.Yellow, ConsoleColor.Red); 69 | 70 | // Shell 71 | 72 | // values types 73 | 74 | public TextColor Null = new(ConsoleColor.Green, null); 75 | public TextColor Quotes = new(ConsoleColor.Green, null); 76 | public TextColor Numeric = new(ConsoleColor.Cyan, null); 77 | public TextColor Boolean = new(ConsoleColor.Magenta, null); 78 | public TextColor BooleanTrue = new(ConsoleColor.Magenta, null); 79 | public TextColor BooleanFalse = new(ConsoleColor.DarkMagenta, null); 80 | public TextColor Integer = new(ConsoleColor.Cyan, null); 81 | public TextColor Double = new(ConsoleColor.Cyan, null); 82 | public TextColor Float = new(ConsoleColor.Cyan, null); 83 | public TextColor Decimal = new(ConsoleColor.Cyan, null); 84 | public TextColor Char = new(ConsoleColor.Green, null); 85 | 86 | public TextColor Label = new(ConsoleColor.Cyan, null); 87 | public TextColor Name = new(ConsoleColor.DarkYellow, null); 88 | public TextColor HighlightSymbol = new(ConsoleColor.Yellow, null); 89 | public TextColor Symbol = new(ConsoleColor.DarkYellow, null); 90 | public TextColor Value = new(ConsoleColor.DarkYellow, null); 91 | public TextColor HalfDarkLabel = new(ConsoleColor.DarkCyan, null); 92 | public TextColor DarkLabel = new(ConsoleColor.DarkBlue, null); 93 | public TextColor MediumDarkLabel = new(ConsoleColor.Blue, null); 94 | public TextColor HighlightIdentifier = new(ConsoleColor.Green, null); 95 | 96 | public TextColor MarginText = new(ConsoleColor.DarkGray, null); 97 | 98 | // colors by effect 99 | 100 | public TextColor Highlight = new(ConsoleColor.Yellow, null); 101 | public TextColor HalfDark = new(ConsoleColor.Gray, null); 102 | public TextColor Dark = new(ConsoleColor.DarkGray, null); 103 | 104 | // table 105 | 106 | public TextColor TableBorder = new(ConsoleColor.Cyan, null); 107 | public TextColor TableColumnName = new(ConsoleColor.Yellow, null); 108 | 109 | // syntax 110 | 111 | public TextColor ParameterName = new(ConsoleColor.Yellow, null); 112 | public TextColor KeyWord = new(ConsoleColor.Yellow, null); 113 | public TextColor ParameterValueType = new(ConsoleColor.DarkYellow, null); 114 | public TextColor OptionPrefix = new(ConsoleColor.Yellow, null); 115 | public TextColor OptionName = new(ConsoleColor.Yellow, null); 116 | public TextColor TypeName = new(ConsoleColor.DarkYellow, null); 117 | public TextColor OptionValue = new(ConsoleColor.DarkYellow, null); 118 | public TextColor SyntaxSymbol = new(ConsoleColor.Cyan, null); 119 | 120 | #pragma warning restore CS1591 121 | 122 | } 123 | 124 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Console/TextColor.cs: -------------------------------------------------------------------------------- 1 | using AnsiVtConsole.NetCore.Component.EchoDirective; 2 | 3 | using static AnsiVtConsole.NetCore.Component.EchoDirective.Shortcuts; 4 | 5 | namespace AnsiVtConsole.NetCore.Component.Console; 6 | 7 | /// 8 | /// foreground and background text color ConseolColor 9 | /// 10 | public sealed class TextColor 11 | { 12 | /// 13 | /// default foreground color 14 | /// 15 | public static ConsoleColor DefaultForeground { get; set; } 16 | 17 | /// 18 | /// default background color 19 | /// 20 | public static ConsoleColor DefaultBackground { get; set; } 21 | 22 | ConsoleColor? _foreground; 23 | 24 | /// 25 | /// foreground 26 | /// 27 | public ConsoleColor? Foreground 28 | { 29 | get => _foreground ?? DefaultForeground; 30 | set => _foreground = value; 31 | } 32 | 33 | ConsoleColor? _background; 34 | 35 | /// 36 | /// background 37 | /// 38 | public ConsoleColor? Background 39 | { 40 | get => _background ?? DefaultBackground; 41 | set => _background = value; 42 | } 43 | 44 | readonly string? _toStrPost = null; 45 | readonly string? _toStrPre = null; 46 | 47 | /// 48 | /// text color 49 | /// 50 | public TextColor(ConsoleColor? foreground, ConsoleColor? background = null) 51 | { 52 | Foreground = foreground; 53 | Background = background; 54 | } 55 | 56 | /// 57 | /// text color 58 | /// 59 | public TextColor(ConsoleColor? foreground, ConsoleColor? background = null, string toStrPost = "", string toStrPre = "") 60 | { 61 | Foreground = foreground; 62 | Background = background; 63 | _toStrPost = toStrPost; 64 | _toStrPre = toStrPre; 65 | } 66 | 67 | /// 68 | /// Invert 69 | /// 70 | public TextColor Invert() => new(_background, _foreground); 71 | 72 | /// 73 | /// to string 74 | /// 75 | public override string ToString() => 76 | _toStrPre + (!_foreground.HasValue ? "" : GetCmd(EchoDirectives.f + "", _foreground.Value.ToString().ToLower())) 77 | + (!_background.HasValue ? "" : GetCmd(EchoDirectives.b + "", _background.Value.ToString().ToLower())) + _toStrPost; 78 | 79 | /// 80 | /// ToStringForegroundOnly 81 | /// 82 | public string ToStringForegroundOnly() => (!_foreground.HasValue ? "" : GetCmd(EchoDirectives.f + "", _foreground.Value.ToString().ToLower())); 83 | 84 | /// 85 | /// ToString 86 | /// 87 | public string ToString(bool foregroundOnly) => 88 | _toStrPre + (!_foreground.HasValue ? "" : GetCmd(EchoDirectives.f + "", _foreground.Value.ToString().ToLower())) 89 | + ((foregroundOnly) ? "" : (!_background.HasValue ? "" : GetCmd(EchoDirectives.b + "", _background.Value.ToString().ToLower()))) + _toStrPost; 90 | 91 | #region build and convert colors operations 92 | 93 | /// 94 | /// build a color from a name 95 | /// 96 | /// color name 97 | /// console color 98 | public static ConsoleColor GetColor(string colorName) => (ConsoleColor)Enum.Parse(typeof(ConsoleColor), colorName); 99 | 100 | /// 101 | /// parse a 4 bit color 102 | /// 103 | /// console 104 | /// text of color name 105 | public static ConsoleColor? ParseColor(IAnsiVtConsole console, object? c) 106 | { 107 | if (c == null) 108 | return null; 109 | var s = (string)c; 110 | if (string.IsNullOrWhiteSpace(s)) 111 | return null; 112 | if (Enum.TryParse(s, true, out ConsoleColor r)) 113 | return r; 114 | if (console.Settings.TraceCommandErrors) 115 | console.Logger.LogError($"invalid color name: {c}"); 116 | return ConsoleColor.Black; 117 | } 118 | 119 | /// 120 | /// parse a 8 bit color 121 | /// 122 | /// console 123 | /// string representing an integer in range 0..255 (included) 124 | /// 125 | public static int Parse8BitColor(IAnsiVtConsole console, object c) 126 | { 127 | if (int.TryParse((string)c, out var r) && r >= 0 && r <= 255) 128 | return r; 129 | if (console.Settings.TraceCommandErrors) 130 | console.Logger.LogError($"invalid 8 bit color number: {c}"); 131 | return 255; 132 | } 133 | 134 | /// 135 | /// parse a 24 bit color 136 | /// 137 | /// console 138 | /// string of format: r:g:b where 0<=r,g,b <255 139 | /// 140 | public static (int r, int g, int b) Parse24BitColor(IAnsiVtConsole console, object c) 141 | { 142 | var s = (string)c; 143 | var t = s.Split(':'); 144 | if (t.Length == 3) 145 | { 146 | if (int.TryParse(t[0], out var r) && r >= 0 && r <= 255 147 | && int.TryParse(t[1], out var g) && g >= 0 && g <= 255 148 | && int.TryParse(t[2], out var b) && b >= 0 && b <= 255) 149 | { 150 | return (r, g, b); 151 | } 152 | } 153 | if (console.Settings.TraceCommandErrors) 154 | console.Logger.LogError($"invalid 24 bit color: {c}"); 155 | return (255, 255, 255); 156 | } 157 | 158 | #endregion 159 | } 160 | 161 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore.CommandLine/AnsiVtConsole.NetCore.CommandLine.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | True 8 | Exe 9 | 1.0.21.0 10 | 1.0.21.0 11 | 12 | AnsiVtConsole.NetCore.CommandLine 13 | AnsiVtConsole.NetCore.CommandLine 14 | en-US 15 | 16 | Franck Gaspoz 17 | Franck Gaspoz 18 | AnsiVtConsole.NetCoreCommandLine 19 | Command line console application 'echo' with powerfull support of ANSI/VT based on AnsiVtConsole.NetCore 20 | (c) Franck Gaspoz 2023 Licence MIT 21 | 1.18.0 22 | 1.18.0 23 | 24 | AnyCPU 25 | 26 | 27 | 28 | AnyCPU 29 | false 30 | true 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | PreserveNewest 59 | 60 | 61 | contentFiles/any/any/;content/ 62 | PreserveNewest 63 | true 64 | true 65 | True 66 | 67 | 68 | contentFiles/any/any/;content/ 69 | PreserveNewest 70 | true 71 | true 72 | True 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | PreserveNewest 84 | True 85 | contentFiles/any/;content/ 86 | true 87 | 88 | 89 | PreserveNewest 90 | True 91 | contentFiles/any/;content/ 92 | true 93 | 94 | 95 | True 96 | PreserveNewest 97 | True 98 | contentFiles/any/;content/ 99 | true 100 | 101 | 102 | 103 | 104 | 105 | contentFiles/any/;content/ 106 | PreserveNewest 107 | true 108 | True 109 | 110 | 111 | contentFiles/any/;content/ 112 | PreserveNewest 113 | true 114 | True 115 | 116 | 117 | contentFiles/any/;content/ 118 | PreserveNewest 119 | true 120 | True 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Widgets/AnimatedWidget.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Component.Widgets; 2 | 3 | /// 4 | /// widget that has a regulart threaded update 5 | /// 6 | public abstract class AnimatedWidget 7 | : Widget, IAnimatedWidget 8 | where WidgetType : class, IAnimatedWidget 9 | where OptionsBuilderType : AnimatedOptionsBuilder 10 | { 11 | /// 12 | /// frames per seconds 13 | /// 14 | public double FPS { get; private set; } 15 | 16 | /// 17 | /// is running 18 | /// 19 | public bool IsRunning { get; private set; } 20 | 21 | /// 22 | /// on start event 23 | /// 24 | public event EventHandler OnStart; 25 | 26 | /// 27 | /// on stop event 28 | /// 29 | public event EventHandler OnStop; 30 | 31 | /// 32 | /// tick coutn 33 | /// 34 | public long Tick { get; private set; } 35 | 36 | /// 37 | /// animated widget 38 | /// 39 | /// frames per seconds 40 | /// wrapped widget 41 | #pragma warning disable CS8618 42 | public AnimatedWidget( 43 | double fps, 44 | IWidget? wrappedWidget = null) 45 | : base(wrappedWidget) => SetFPS(fps); 46 | 47 | /// 48 | /// animated widget 49 | /// 50 | /// cursor x 51 | /// cursor y 52 | /// frames per seconds 53 | /// wrapped widget 54 | #pragma warning disable CS8618 55 | public AnimatedWidget( 56 | int x, 57 | int y, 58 | double fps, 59 | IWidget? wrappedWidget = null) 60 | : base(x, y, wrappedWidget) => SetFPS(fps); 61 | 62 | /// 63 | /// widget at a fixed location 64 | /// 65 | /// frames per seconds 66 | /// cursor x 67 | /// cursor y 68 | public AnimatedWidget( 69 | double fps, 70 | int x, 71 | int y) 72 | : base(x, y) 73 | => SetFPS(fps); 74 | #pragma warning restore CS8618 75 | 76 | int _timeLapse => (int)(1d / FPS * 1000d); 77 | 78 | Thread? _thread; 79 | bool _stop; 80 | 81 | /// 82 | /// set the fps 83 | /// 84 | /// fps 85 | /// this object 86 | public WidgetType SetFPS(double fps) 87 | { 88 | AssertNotRunning(); 89 | if (fps < 0) 90 | throw new ArgumentException("fps must be > 0"); 91 | FPS = fps; 92 | return (this as WidgetType)!; 93 | } 94 | 95 | /// 96 | public override WidgetType Add(IAnsiVtConsole console) 97 | { 98 | lock (console.Out.Lock) 99 | { 100 | base.Add(console); 101 | if (_thread is null) 102 | Start(); 103 | } 104 | WaitNextTick(); 105 | return (this as WidgetType)!; 106 | } 107 | 108 | /// 109 | /// starts the thread 110 | /// 111 | public WidgetType Start() 112 | { 113 | Tick = 0; 114 | StartInit(); 115 | IsRunning = true; 116 | (_thread = new(() => Run())) 117 | .Start(); 118 | OnStart?.Invoke(this, EventArgs.Empty); 119 | return (this as WidgetType)!; 120 | } 121 | 122 | /// 123 | /// wait the next animation tick 124 | /// 125 | public void WaitNextTick() 126 | { 127 | if (!IsRunning) return; 128 | var tick = Tick; 129 | while (Tick == tick) 130 | Thread.Yield(); 131 | } 132 | 133 | /// 134 | /// stops the thread 135 | /// 136 | public WidgetType Stop() 137 | { 138 | _stop = true; 139 | _thread = null; 140 | OnStop?.Invoke(this, EventArgs.Empty); 141 | return (this as WidgetType)!; 142 | } 143 | 144 | /// 145 | /// wait end of animation. if not running returns immediately 146 | /// 147 | public WidgetType Wait() 148 | { 149 | while (IsRunning) 150 | Thread.Yield(); 151 | return (this as WidgetType)!; 152 | } 153 | 154 | /// 155 | /// Wait for delay milliseconds 156 | /// 157 | public WidgetType Wait(int delay) 158 | { 159 | Thread.Sleep(delay); 160 | return (this as WidgetType)!; 161 | } 162 | 163 | void Run() 164 | { 165 | var _end = _stop = false; 166 | var str = string.Empty; 167 | while (!_end && !_stop) 168 | { 169 | var oldRightX = RightX; 170 | 171 | lock (Console!.Out.Lock) 172 | { 173 | PrepareFrame(); 174 | RenderFrame(); 175 | } 176 | 177 | if (RightX > oldRightX) 178 | { 179 | Thread.Sleep(_timeLapse); 180 | Tick++; 181 | } 182 | 183 | _end = IsEnd(); 184 | } 185 | IsRunning = false; 186 | OnStop?.Invoke(this, EventArgs.Empty); 187 | } 188 | 189 | /// 190 | /// indicates if run must end 191 | /// 192 | /// true if must end, false otherwise 193 | protected abstract bool IsEnd(); 194 | 195 | /// 196 | /// operation of the thread (step 1). Run in a console lock 197 | /// 198 | protected virtual void PrepareFrame() { } 199 | 200 | /// 201 | /// operation of the thread (step 2). Run in a console lock 202 | /// 203 | protected abstract void RenderFrame(); 204 | 205 | /// 206 | /// init at start 207 | /// 208 | protected abstract void StartInit(); 209 | 210 | /// 211 | /// assert is not running 212 | /// 213 | /// operation not allowed while animation is playing 214 | protected void AssertNotRunning() 215 | { 216 | if (IsRunning) 217 | throw new InvalidOperationException("operation not allowed while animation is playing"); 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.32014.148 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AnsiVtConsole.NetCore", "AnsiVtConsole.NetCore\AnsiVtConsole.NetCore.csproj", "{72B1CBA5-B4C1-4B1B-907E-7BCAE9CC7557}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{196A14D8-B446-482A-8B5E-9CD986A0C5A3}" 9 | ProjectSection(SolutionItems) = preProject 10 | .editorconfig = .editorconfig 11 | .gitattributes = .gitattributes 12 | .gitignore = .gitignore 13 | LICENSE.md = LICENSE.md 14 | publish-nuget-imaging.bat = publish-nuget-imaging.bat 15 | publish-nuget.bat = publish-nuget.bat 16 | AnsiVtConsole.NetCore\README.md = AnsiVtConsole.NetCore\README.md 17 | EndProjectSection 18 | EndProject 19 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "assets", "assets", "{5F978492-9C45-40F3-9D70-B3283498F57D}" 20 | ProjectSection(SolutionItems) = preProject 21 | assets\ascii-icon.png = assets\ascii-icon.png 22 | assets\example1.png = assets\example1.png 23 | assets\example2.png = assets\example2.png 24 | assets\example3.png = assets\example3.png 25 | assets\example4.png = assets\example4.png 26 | assets\example5.png = assets\example5.png 27 | assets\example6.png = assets\example6.png 28 | assets\example7.png = assets\example7.png 29 | assets\output.png = assets\output.png 30 | assets\title.png = assets\title.png 31 | EndProjectSection 32 | EndProject 33 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AnsiVtConsole.NetCore.CommandLine", "AnsiVtConsole.NetCore.CommandLine\AnsiVtConsole.NetCore.CommandLine.csproj", "{035A4809-9FC6-422F-88FD-5F9CC8DE1BBC}" 34 | EndProject 35 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AnsiVtConsole.NetCore.Imaging", "AnsiVtConsole.NetCore.Imaging\AnsiVtConsole.NetCore.Imaging.csproj", "{C4E2C3AA-A537-4A05-A1D7-797D4A3ACA0E}" 36 | EndProject 37 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{C4E95C5A-8158-48EB-89FA-5376B7FC1797}" 38 | EndProject 39 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AnsiVtConsole.NetCore.Examples.ANSI", "Examples\AnsiVtConsole.NetCore.Examples.ANSI\AnsiVtConsole.NetCore.Examples.ANSI.csproj", "{9515D9C8-353B-4967-A416-81387B8D861F}" 40 | EndProject 41 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AnsiVtConsole.NetCore.Examples.Widgets", "Examples\AnsiVtConsole.NetCore.Examples.Widgets\AnsiVtConsole.NetCore.Examples.Widgets.csproj", "{4CC80B81-0FE0-4532-92CE-446AD974E7D2}" 42 | EndProject 43 | Global 44 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 45 | Debug|Any CPU = Debug|Any CPU 46 | Debug|x86 = Debug|x86 47 | Release|Any CPU = Release|Any CPU 48 | Release|x86 = Release|x86 49 | EndGlobalSection 50 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 51 | {72B1CBA5-B4C1-4B1B-907E-7BCAE9CC7557}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 52 | {72B1CBA5-B4C1-4B1B-907E-7BCAE9CC7557}.Debug|Any CPU.Build.0 = Debug|Any CPU 53 | {72B1CBA5-B4C1-4B1B-907E-7BCAE9CC7557}.Debug|x86.ActiveCfg = Debug|x86 54 | {72B1CBA5-B4C1-4B1B-907E-7BCAE9CC7557}.Debug|x86.Build.0 = Debug|x86 55 | {72B1CBA5-B4C1-4B1B-907E-7BCAE9CC7557}.Release|Any CPU.ActiveCfg = Release|Any CPU 56 | {72B1CBA5-B4C1-4B1B-907E-7BCAE9CC7557}.Release|Any CPU.Build.0 = Release|Any CPU 57 | {72B1CBA5-B4C1-4B1B-907E-7BCAE9CC7557}.Release|x86.ActiveCfg = Release|x86 58 | {72B1CBA5-B4C1-4B1B-907E-7BCAE9CC7557}.Release|x86.Build.0 = Release|x86 59 | {035A4809-9FC6-422F-88FD-5F9CC8DE1BBC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 60 | {035A4809-9FC6-422F-88FD-5F9CC8DE1BBC}.Debug|Any CPU.Build.0 = Debug|Any CPU 61 | {035A4809-9FC6-422F-88FD-5F9CC8DE1BBC}.Debug|x86.ActiveCfg = Debug|Any CPU 62 | {035A4809-9FC6-422F-88FD-5F9CC8DE1BBC}.Debug|x86.Build.0 = Debug|Any CPU 63 | {035A4809-9FC6-422F-88FD-5F9CC8DE1BBC}.Release|Any CPU.ActiveCfg = Release|Any CPU 64 | {035A4809-9FC6-422F-88FD-5F9CC8DE1BBC}.Release|Any CPU.Build.0 = Release|Any CPU 65 | {035A4809-9FC6-422F-88FD-5F9CC8DE1BBC}.Release|x86.ActiveCfg = Release|Any CPU 66 | {035A4809-9FC6-422F-88FD-5F9CC8DE1BBC}.Release|x86.Build.0 = Release|Any CPU 67 | {C4E2C3AA-A537-4A05-A1D7-797D4A3ACA0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 68 | {C4E2C3AA-A537-4A05-A1D7-797D4A3ACA0E}.Debug|Any CPU.Build.0 = Debug|Any CPU 69 | {C4E2C3AA-A537-4A05-A1D7-797D4A3ACA0E}.Debug|x86.ActiveCfg = Debug|Any CPU 70 | {C4E2C3AA-A537-4A05-A1D7-797D4A3ACA0E}.Debug|x86.Build.0 = Debug|Any CPU 71 | {C4E2C3AA-A537-4A05-A1D7-797D4A3ACA0E}.Release|Any CPU.ActiveCfg = Release|Any CPU 72 | {C4E2C3AA-A537-4A05-A1D7-797D4A3ACA0E}.Release|Any CPU.Build.0 = Release|Any CPU 73 | {C4E2C3AA-A537-4A05-A1D7-797D4A3ACA0E}.Release|x86.ActiveCfg = Release|Any CPU 74 | {C4E2C3AA-A537-4A05-A1D7-797D4A3ACA0E}.Release|x86.Build.0 = Release|Any CPU 75 | {9515D9C8-353B-4967-A416-81387B8D861F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 76 | {9515D9C8-353B-4967-A416-81387B8D861F}.Debug|Any CPU.Build.0 = Debug|Any CPU 77 | {9515D9C8-353B-4967-A416-81387B8D861F}.Debug|x86.ActiveCfg = Debug|Any CPU 78 | {9515D9C8-353B-4967-A416-81387B8D861F}.Debug|x86.Build.0 = Debug|Any CPU 79 | {9515D9C8-353B-4967-A416-81387B8D861F}.Release|Any CPU.ActiveCfg = Release|Any CPU 80 | {9515D9C8-353B-4967-A416-81387B8D861F}.Release|Any CPU.Build.0 = Release|Any CPU 81 | {9515D9C8-353B-4967-A416-81387B8D861F}.Release|x86.ActiveCfg = Release|Any CPU 82 | {9515D9C8-353B-4967-A416-81387B8D861F}.Release|x86.Build.0 = Release|Any CPU 83 | {4CC80B81-0FE0-4532-92CE-446AD974E7D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 84 | {4CC80B81-0FE0-4532-92CE-446AD974E7D2}.Debug|Any CPU.Build.0 = Debug|Any CPU 85 | {4CC80B81-0FE0-4532-92CE-446AD974E7D2}.Debug|x86.ActiveCfg = Debug|Any CPU 86 | {4CC80B81-0FE0-4532-92CE-446AD974E7D2}.Debug|x86.Build.0 = Debug|Any CPU 87 | {4CC80B81-0FE0-4532-92CE-446AD974E7D2}.Release|Any CPU.ActiveCfg = Release|Any CPU 88 | {4CC80B81-0FE0-4532-92CE-446AD974E7D2}.Release|Any CPU.Build.0 = Release|Any CPU 89 | {4CC80B81-0FE0-4532-92CE-446AD974E7D2}.Release|x86.ActiveCfg = Release|Any CPU 90 | {4CC80B81-0FE0-4532-92CE-446AD974E7D2}.Release|x86.Build.0 = Release|Any CPU 91 | EndGlobalSection 92 | GlobalSection(SolutionProperties) = preSolution 93 | HideSolutionNode = FALSE 94 | EndGlobalSection 95 | GlobalSection(NestedProjects) = preSolution 96 | {5F978492-9C45-40F3-9D70-B3283498F57D} = {196A14D8-B446-482A-8B5E-9CD986A0C5A3} 97 | {9515D9C8-353B-4967-A416-81387B8D861F} = {C4E95C5A-8158-48EB-89FA-5376B7FC1797} 98 | {4CC80B81-0FE0-4532-92CE-446AD974E7D2} = {C4E95C5A-8158-48EB-89FA-5376B7FC1797} 99 | EndGlobalSection 100 | GlobalSection(ExtensibilityGlobals) = postSolution 101 | SolutionGuid = {E8B5B602-B2FB-4A96-9DA0-5085D1844222} 102 | EndGlobalSection 103 | EndGlobal 104 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Widgets/Animatics/ValueAnimation.cs: -------------------------------------------------------------------------------- 1 | #define dbg 2 | 3 | using System.Linq.Expressions; 4 | using System.Reflection; 5 | 6 | using AnsiVtConsole.NetCore.Component.Widgets.Animatics.Easings; 7 | 8 | namespace AnsiVtConsole.NetCore.Component.Widgets.Animatics; 9 | 10 | /// 11 | /// animation of value of type T 12 | /// 13 | /// value type 14 | public abstract class ValueAnimation : IAnimation 15 | { 16 | readonly List _targets = new(); 17 | 18 | PropertyInfo? _propertyInfo; 19 | 20 | /// 21 | public T? Value { get; private set; } 22 | 23 | /// 24 | public T? From { get; private set; } 25 | 26 | /// 27 | public T To { get; private set; } 28 | 29 | /// 30 | public T Increment { get; private set; } 31 | 32 | /// 33 | public double Duration { get; private set; } 34 | 35 | /// 36 | public Easing Easing { get; private set; } 37 | 38 | /// 39 | TValue? IAnimation.Value() 40 | where TValue : class 41 | => Value as TValue; 42 | 43 | /// 44 | TValue? IAnimation.From() 45 | where TValue : class 46 | => From as TValue; 47 | 48 | /// 49 | TValue? IAnimation.To() 50 | where TValue : class 51 | => To as TValue; 52 | 53 | /// 54 | TValue? IAnimation.Increment() 55 | where TValue : class 56 | => To as TValue; 57 | 58 | /// 59 | double IAnimation.Duration => Duration; 60 | 61 | /// 62 | /// animation 63 | /// 64 | /// from 65 | /// to 66 | /// duration 67 | /// increment 68 | /// easing function (default linear) 69 | public ValueAnimation( 70 | T from, 71 | T to, 72 | double duration, 73 | T increment, 74 | Easing? easing = null) 75 | { 76 | Increment = increment; 77 | From = from; 78 | To = to; 79 | Duration = duration; 80 | Easing = easing ?? new Linear(); 81 | } 82 | 83 | /// 84 | /// animation 85 | /// 86 | /// to 87 | /// duration 88 | /// increment 89 | /// easing function (default linear) 90 | public ValueAnimation( 91 | T to, 92 | double duration, 93 | T increment, 94 | Easing? easing = null) 95 | { 96 | Increment = increment; 97 | To = to; 98 | Duration = duration; 99 | Easing = easing ?? new Linear(); 100 | SetInitialValue(); 101 | } 102 | 103 | /// 104 | public IAnimation For(object target, string propertyName) 105 | { 106 | _propertyInfo = target.GetType() 107 | .GetProperty(propertyName) 108 | ?? throw new ArgumentException($"property {propertyName} not found in object: {target}"); 109 | 110 | _targets.Add(_targets); 111 | 112 | return this; 113 | } 114 | 115 | /// 116 | public IAnimation For(string propertyName) 117 | { 118 | _propertyInfo = typeof(TargetType) 119 | .GetProperty(propertyName) 120 | ?? throw new ArgumentException($"property {propertyName} not found in object: {typeof(TargetType)}"); 121 | 122 | return this; 123 | } 124 | 125 | /// 126 | public IAnimation For(object target, LambdaExpression expression) 127 | { 128 | Type? returnType; 129 | if (expression.Body is MemberExpression expr 130 | && expr.Member is PropertyInfo propertyInfo) 131 | returnType = expression.ReturnType; 132 | else 133 | throw new ArgumentException("expression is not valid", nameof(expression)); 134 | if (returnType != typeof(T)) 135 | throw new ArgumentException("expression is not valid. Expected return type: " + typeof(T).Name); 136 | 137 | _propertyInfo = propertyInfo; 138 | _targets.Add(target); 139 | 140 | return this; 141 | } 142 | 143 | /// 144 | public IAnimation For(LambdaExpression expression) 145 | { 146 | Type? returnType; 147 | if (expression.Body is MemberExpression expr 148 | && expr.Member is PropertyInfo propertyInfo) 149 | returnType = expression.ReturnType; 150 | else 151 | throw new ArgumentException("expression is not valid", nameof(expression)); 152 | if (returnType != typeof(T)) 153 | throw new ArgumentException("expression is not valid. Expected return type: " + typeof(T).Name); 154 | 155 | _propertyInfo = propertyInfo; 156 | 157 | return this; 158 | } 159 | 160 | /// 161 | /// this object 162 | public IAnimation Target(params object[] targets) 163 | { 164 | _targets.AddRange(targets); 165 | return this; 166 | } 167 | 168 | /// 169 | public void SetValueAt(double position, bool reverse) 170 | { 171 | var to = reverse ? From! : To!; 172 | var from = reverse ? To! : From!; 173 | var toBack = To!; 174 | var fromBack = From!; 175 | To = to!; 176 | From = from!; 177 | 178 | SetValueAt(position); 179 | 180 | To = toBack!; 181 | From = fromBack!; 182 | } 183 | 184 | /// 185 | public abstract void SetValueAt(double position); 186 | 187 | /// 188 | protected void SetInitialValue() 189 | { 190 | if (_propertyInfo is null) 191 | throw new InvalidDataException("property is not defined"); 192 | 193 | foreach (var target in _targets) 194 | From = GetValue(_propertyInfo, target); 195 | } 196 | 197 | /// 198 | /// set value of target 199 | /// 200 | /// value 201 | protected void SetValue(T value) 202 | { 203 | #if DEBUG 204 | System.Diagnostics.Debug.WriteLine("value = " + value); 205 | #endif 206 | if (_propertyInfo is null) 207 | throw new InvalidDataException("property is not defined"); 208 | 209 | foreach (var target in _targets) 210 | SetValue(_propertyInfo, target, value); 211 | } 212 | 213 | static void SetValue(PropertyInfo propertyInfo, object target, T value) 214 | => propertyInfo.SetValue(target, value); 215 | 216 | static T? GetValue(PropertyInfo propertyInfo, object target) 217 | => (T?)propertyInfo.GetValue(target); 218 | } 219 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Component/Console/WorkArea.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | 3 | using sc = System.Console; 4 | 5 | namespace AnsiVtConsole.NetCore.Component.Console; 6 | 7 | /// 8 | /// work area 9 | /// 10 | public sealed class WorkArea 11 | { 12 | readonly IAnsiVtConsole _console; 13 | 14 | /// 15 | /// id 16 | /// 17 | public readonly string Id; 18 | 19 | /// 20 | /// rect 21 | /// 22 | public readonly Rectangle Rect = Rectangle.Empty; 23 | 24 | /// 25 | /// this setting limit wide of lines (available width -1) to prevent sys console to automatically put a line break when reaching end of line (console bug ?) 26 | /// 27 | public bool AvoidConsoleAutoLineBreakAtEndOfLine = false; 28 | 29 | /// 30 | /// work area of a console 31 | /// 32 | /// console 33 | public WorkArea(IAnsiVtConsole console) 34 | { 35 | _console = console; 36 | Id = string.Empty; 37 | } 38 | 39 | /// 40 | /// work area of a console with fixed coordinates 41 | /// 42 | /// console 43 | /// workarea id 44 | /// from x 45 | /// from y 46 | /// width 47 | /// height 48 | public WorkArea( 49 | IAnsiVtConsole console, 50 | string id, 51 | int x, 52 | int y, 53 | int width, 54 | int height) 55 | { 56 | _console = console; 57 | Id = id; 58 | Rect = new Rectangle(x, y, width, height); 59 | } 60 | 61 | /// 62 | /// work area of a console from an existing one 63 | /// 64 | /// console 65 | /// workarea 66 | public WorkArea( 67 | IAnsiVtConsole console, 68 | WorkArea workArea) 69 | { 70 | _console = console; 71 | Id = workArea.Id; 72 | Rect = new Rectangle(workArea.Rect.X, workArea.Rect.Y, workArea.Rect.Width, workArea.Rect.Height); 73 | } 74 | 75 | /// 76 | /// is empty 77 | /// 78 | public bool IsEmpty => Rect.IsEmpty; 79 | 80 | /// 81 | /// is inside work area 82 | /// 83 | public bool InWorkArea => !Rect.IsEmpty; 84 | 85 | /// 86 | /// true until the contrary is detected (exception in GetCoords : sc.WindowLeft) 87 | /// 88 | public bool IsConsoleGeometryEnabled { get; private set; } = true; 89 | 90 | /// 91 | /// update the IsConsoleGeometryEnabled field 92 | /// 93 | /// value of the field 94 | public bool CheckConsoleHasGeometry() 95 | { 96 | try 97 | { 98 | var x = sc.WindowLeft; 99 | } 100 | catch (Exception) 101 | { 102 | IsConsoleGeometryEnabled = false; 103 | return false; 104 | } 105 | return true; 106 | } 107 | 108 | /// 109 | /// fix a rectangle coordianates to be valid and eventually limited inside a workarea 110 | /// 111 | /// notes:

112 | /// - (1) dos console (eg. vs debug consolehep) set WindowTop as y scroll position. WT console doesn't (still 0)

113 | /// - scroll -> native dos console set WindowTop and WindowLeft as base scroll coordinates

114 | /// - if WorkArea defined, we must use absolute coordinates and not related

115 | /// - CursorLeft and CursorTop are always good

116 | ///
117 | ///
118 | /// from x 119 | /// from y 120 | /// width 121 | /// height 122 | /// if true fit the rectangle inside workarea 123 | /// adjusted coordinates 124 | public (int x, int y, int w, int h) 125 | GetCoords(int x, int y, int w, int h, bool fitToVisibleArea = true) 126 | { 127 | // (1) dos console (eg. vs debug consolehep) set WindowTop as y scroll position. WT console doesn't (still 0) 128 | // scroll -> native dos console set WindowTop and WindowLeft as base scroll coordinates 129 | // if WorkArea defined, we must use absolute coordinates and not related 130 | // CursorLeft and CursorTop are always good 131 | lock (_console.Out.Lock!) 132 | { 133 | if (!IsConsoleGeometryEnabled) 134 | return (x, y, 1000, 1000); 135 | 136 | if (x < 0) 137 | x = sc.WindowLeft + sc.WindowWidth + x; 138 | 139 | if (y < 0) 140 | y = /*sc.WindowTop (fix 1) */ +sc.WindowHeight + y; 141 | 142 | if (fitToVisibleArea) 143 | { 144 | if (w < 0) 145 | { 146 | w = sc.WindowWidth + ((AvoidConsoleAutoLineBreakAtEndOfLine) ? -1 : 0) + (w + 1) // 1 POS TOO MUCH !! 147 | /*+ sc.WindowLeft*/; 148 | } 149 | 150 | if (h < 0) 151 | { 152 | h = sc.WindowHeight + h 153 | + sc.WindowTop; /* ?? */ 154 | } 155 | } 156 | else 157 | { 158 | if (w < 0) 159 | w = sc.BufferWidth + ((AvoidConsoleAutoLineBreakAtEndOfLine) ? -1 : 0) + (w + 1); 160 | 161 | if (h < 0) 162 | h = sc.WindowHeight + h + sc.WindowTop; 163 | } 164 | return (x, y, w, h); 165 | } 166 | } 167 | 168 | /// 169 | /// compute actual work area if possible 170 | /// 171 | /// if set, limit to visible area only 172 | /// work area 173 | public ActualWorkArea ActualWorkArea(bool fitToVisibleArea = true) 174 | { 175 | if (!IsConsoleGeometryEnabled) 176 | return new ActualWorkArea(Id, 0, 0, 0, 0); 177 | var x0 = Rect.IsEmpty ? 0 : Rect.X; 178 | var y0 = Rect.IsEmpty ? 0 : Rect.Y; 179 | var w0 = Rect.IsEmpty ? -1 : Rect.Width; 180 | var h0 = Rect.IsEmpty ? -1 : Rect.Height; 181 | var (x, y, w, h) = GetCoords(x0, y0, w0, h0, fitToVisibleArea); 182 | return new ActualWorkArea(Id, x, y, w, h); 183 | } 184 | 185 | /// 186 | /// set cursor at top of work area 187 | /// 188 | public void SetCursorAtWorkAreaTop() 189 | { 190 | if (!IsConsoleGeometryEnabled || Rect.IsEmpty) 191 | return; // TODO: set cursor even if workarea empty? 192 | 193 | lock (_console.Out.Lock!) 194 | { 195 | _console.Out.SetCursorPos(Rect.X, Rect.Y); 196 | } 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /AnsiVtConsole.NetCore/Lib/Str.cs: -------------------------------------------------------------------------------- 1 | namespace AnsiVtConsole.NetCore.Lib 2 | { 3 | static class Str 4 | { 5 | #region data to text operations 6 | 7 | public static bool IsQuotedString(string s) 8 | { 9 | if (string.IsNullOrWhiteSpace(s)) 10 | return false; 11 | return s[0] == s[^1] && (s[0] == '\'' || s[0] == '"'); 12 | } 13 | 14 | public static string AssureIsQuoted(string s) => IsQuotedString(s) ? s : DoubleQuoted(s); 15 | 16 | public static string DoubleQuoted(string s) => $"\"{s}\""; 17 | 18 | public static string Quoted(string s) => $"'{s}'"; 19 | 20 | public static string? DoubleQuoteIfString(object? o) 21 | { 22 | if (o == null) 23 | return null; 24 | if (o is string str 25 | && !str.StartsWith("\"") 26 | && !str.EndsWith("\"") 27 | ) 28 | { 29 | str = "\"" + str + "\""; 30 | return str; 31 | } 32 | return o.ToString(); 33 | } 34 | 35 | /// 36 | /// null output fallback 37 | /// 38 | public static string DumpNullStringAsText = "{null}"; 39 | 40 | public static string? DumpAsText(object? o, bool quoteStrings = true) 41 | { 42 | if (o == null) 43 | return DumpNullStringAsText ?? null; 44 | if (o is string s && quoteStrings) 45 | return $"\"{s}\""; 46 | return o.ToString(); 47 | } 48 | 49 | public static string TimeSpanDescription(TimeSpan ts, string prefix = "", string postfix = "") 50 | { 51 | var d = ts.Days; 52 | var h = ts.Hours; 53 | var m = ts.Minutes; 54 | var s = ts.Seconds; 55 | var ms = ts.Milliseconds; 56 | var lst = new List(); 57 | if (d > 0) 58 | lst.Add($"{prefix}{d}{postfix} days"); 59 | if (h > 0) 60 | lst.Add($"{prefix}{h}{postfix} hours"); 61 | if (m > 0) 62 | lst.Add($"{prefix}{m}{postfix} minutes"); 63 | if (s > 0) 64 | lst.Add($"{prefix}{s}{postfix} seconds"); 65 | if (ms >= 0) 66 | lst.Add($"{prefix}{ms}{postfix} milliseconds"); 67 | return string.Join(' ', lst); 68 | } 69 | 70 | public static string Plur(string s, int n, string postfix = "") => $"{n}{postfix} {s}" + ((n > 1) ? "s" : ""); 71 | 72 | public static string Dump(object[] t) => string.Join(',', t.Select(x => DumpAsText(x))); 73 | 74 | /// 75 | /// indicates if a string match one with wildcards
76 | /// author: PrzemekBenz https://www.codeproject.com/script/Membership/View.aspx?mid=629898
77 | /// from: https://www.codeproject.com/tips/57304/use-wildcard-characters-and-to-compare-strings
78 | /// licence: CPOL 27/7/2017
79 | ///
80 | /// wildcard pattern string 81 | /// string to check if match 82 | /// ignore case if true 83 | /// true if string match, false otherwise 84 | public static bool MatchWildcard( 85 | string pattern, 86 | string input, 87 | bool ignoreCase) 88 | { 89 | if (string.Compare(pattern, input, ignoreCase) == 0) 90 | { 91 | return true; 92 | } 93 | else if (string.IsNullOrEmpty(input)) 94 | { 95 | if (string.IsNullOrEmpty(pattern.Trim(new char[1] { '*' }))) 96 | { 97 | return true; 98 | } 99 | else 100 | { 101 | return false; 102 | } 103 | } 104 | else if (pattern.Length == 0) 105 | { 106 | return false; 107 | } 108 | else if (pattern[0] == '?') 109 | { 110 | return MatchWildcard( 111 | pattern[1..], 112 | input[1..], 113 | ignoreCase); 114 | } 115 | else if (pattern[^1] == '?') 116 | { 117 | return MatchWildcard( 118 | pattern[0..^1], 119 | input[0..^1], 120 | ignoreCase); 121 | } 122 | else if (pattern[0] == '*') 123 | { 124 | if (MatchWildcard(pattern[1..], input, ignoreCase)) 125 | { 126 | return true; 127 | } 128 | else 129 | { 130 | return MatchWildcard(pattern, input[1..], ignoreCase); 131 | } 132 | } 133 | else if (pattern[^1] == '*') 134 | { 135 | if (MatchWildcard(pattern[0..^1], input, ignoreCase)) 136 | { 137 | return true; 138 | } 139 | else 140 | { 141 | return MatchWildcard(pattern, input[0..^1], ignoreCase); 142 | } 143 | } 144 | else if (pattern[0] == input[0]) 145 | { 146 | return MatchWildcard(pattern[1..], input[1..], ignoreCase); 147 | } 148 | return false; 149 | } 150 | 151 | public static string HumanFormatOfSize(long bytes, int digits = 1, string sep = " ", string prefix = "", string postfix = "", string bigPostFix = "") 152 | { 153 | var byteChar = 'b'; 154 | var absB = bytes == long.MinValue ? long.MaxValue : Math.Abs(bytes); 155 | if (absB < 1024) 156 | { 157 | return prefix + bytes + postfix + sep + byteChar; 158 | } 159 | if (absB < 1024 * 1024) 160 | { 161 | return string.Format(prefix + "{0:F" + digits + "}" + postfix + sep + "{1}" + bigPostFix + byteChar, absB / 1024d, "K"); 162 | } 163 | var value = absB; 164 | var values = new Stack(); 165 | var ci = '?'; 166 | var t = new char[] { 'K', 'M', 'G', 'T', 'P', 'E' }; 167 | var n = 0; 168 | while (n < t.Length && value > 0) 169 | { 170 | for (var i = 40; i >= 0 && absB > 0xfffccccccccccccL >> i; i -= 10) 171 | { 172 | value >>= 10; 173 | if (value > 0) 174 | { 175 | ci = t[n++]; 176 | values.Push(value); 177 | } 178 | } 179 | } 180 | value = values.Pop(); 181 | if (values.Count > 0) 182 | value = values.Pop(); 183 | value *= Math.Sign(bytes); 184 | return string.Format(prefix + "{0:F" + digits + "}" + postfix + sep + "{1}" + bigPostFix + byteChar, value / 1024d, ci); 185 | } 186 | 187 | #endregion 188 | } 189 | } 190 | --------------------------------------------------------------------------------