From f556e047379cdf67aff62975a1a1cd9baf5969a6 Mon Sep 17 00:00:00 2001 From: Damian Orzechowski <114909782+damian-orzechowski@users.noreply.github.com> Date: Wed, 28 Dec 2022 12:31:36 +0100 Subject: [PATCH] Fix/4130 disable color output for cli (#4785) * Disable Cli color scheme by default. Color scheme can be passed as option. * Use System.Console by default Co-authored-by: lukasz.rozmej --- .../Nethermind.Cli/Console/CliConsole.cs | 123 +++++++++--------- .../Console/ColorfulCliConsole.cs | 112 ++++++++++++++++ .../Nethermind.Cli/Console/ICliConsole.cs | 4 + .../Nethermind.Cli/Nethermind.Cli.csproj | 1 + src/Nethermind/Nethermind.Cli/Program.cs | 119 ++++++++++------- .../Properties/launchSettings.json | 8 ++ 6 files changed, 257 insertions(+), 110 deletions(-) create mode 100644 src/Nethermind/Nethermind.Cli/Console/ColorfulCliConsole.cs create mode 100644 src/Nethermind/Nethermind.Cli/Properties/launchSettings.json diff --git a/src/Nethermind/Nethermind.Cli/Console/CliConsole.cs b/src/Nethermind/Nethermind.Cli/Console/CliConsole.cs index 012b26e61af..274d5ed0284 100644 --- a/src/Nethermind/Nethermind.Cli/Console/CliConsole.cs +++ b/src/Nethermind/Nethermind.Cli/Console/CliConsole.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Drawing; using System.Runtime.InteropServices; using Nethermind.Core; @@ -11,11 +10,10 @@ namespace Nethermind.Cli.Console; public class CliConsole : ICliConsole { - private static ColorScheme _colorScheme = DraculaColorScheme.Instance; + protected static Terminal _terminal; + public Terminal Terminal { get => _terminal; } - private static Terminal _terminal; - - private static readonly Dictionary Terminals = new Dictionary + protected static readonly Dictionary Terminals = new Dictionary { ["cmd.exe"] = Terminal.Cmd, ["cmd"] = Terminal.Cmder, @@ -23,42 +21,26 @@ public class CliConsole : ICliConsole ["cygwin"] = Terminal.Cygwin }; - public Terminal Init(ColorScheme colorScheme) + public CliConsole() { - _colorScheme = colorScheme; - Colorful.Console.BackgroundColor = colorScheme.BackgroundColor; - Colorful.Console.ForegroundColor = colorScheme.Text; - _terminal = GetTerminal(); - if (_terminal != Terminal.Powershell) - { - Colorful.Console.ResetColor(); - } - - if (_terminal != Terminal.Cygwin) - { - Colorful.Console.Clear(); - } - - string version = ProductInfo.Version; - - Colorful.Console.WriteLine("**********************************************", _colorScheme.Comment); - Colorful.Console.WriteLine(); - Colorful.Console.WriteLine("Nethermind CLI {0}", GetColor(_colorScheme.Good), version); - Colorful.Console.WriteLine(" https://github.com/NethermindEth/nethermind", GetColor(_colorScheme.Interesting)); - Colorful.Console.WriteLine(" https://nethermind.readthedocs.io/en/latest/", GetColor(_colorScheme.Interesting)); - Colorful.Console.WriteLine(); - Colorful.Console.WriteLine("powered by:", _colorScheme.Text); - Colorful.Console.WriteLine(" https://github.com/sebastienros/jint", GetColor(_colorScheme.Interesting)); - Colorful.Console.WriteLine(" https://github.com/tomakita/Colorful.Console", GetColor(_colorScheme.Interesting)); - Colorful.Console.WriteLine(" https://github.com/tonerdo/readline", GetColor(_colorScheme.Interesting)); - Colorful.Console.WriteLine(); - Colorful.Console.WriteLine("**********************************************", _colorScheme.Comment); - Colorful.Console.WriteLine(); - - return _terminal; + _terminal = PrepareConsoleForTerminal(); + + System.Console.WriteLine("**********************************************"); + System.Console.WriteLine(); + System.Console.WriteLine("Nethermind CLI {0}", ProductInfo.Version); + System.Console.WriteLine(" https://github.com/NethermindEth/nethermind"); + System.Console.WriteLine(" https://nethermind.readthedocs.io/en/latest/"); + System.Console.WriteLine(); + System.Console.WriteLine("powered by:"); + System.Console.WriteLine(" https://github.com/sebastienros/jint"); + System.Console.WriteLine(" https://github.com/tomakita/Colorful.Console"); + System.Console.WriteLine(" https://github.com/tonerdo/readline"); + System.Console.WriteLine(); + System.Console.WriteLine("**********************************************"); + System.Console.WriteLine(); } - private Terminal GetTerminal() + protected Terminal GetTerminal() { if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { @@ -66,7 +48,7 @@ private Terminal GetTerminal() RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? Terminal.MacBash : Terminal.Unknown; } - var title = Colorful.Console.Title.ToLowerInvariant(); + var title = System.Console.Title.ToLowerInvariant(); foreach (var (key, value) in Terminals) { if (title.Contains(key)) @@ -78,63 +60,78 @@ private Terminal GetTerminal() return Terminal.Unknown; } - private Color GetColor(Color defaultColor) + protected Terminal PrepareConsoleForTerminal() + { + _terminal = GetTerminal(); + if (_terminal != Terminal.Powershell) + { + System.Console.ResetColor(); + } + + if (_terminal != Terminal.Cygwin) + { + System.Console.Clear(); + } + return _terminal; + } + + public virtual void WriteException(Exception e) { - return _terminal == Terminal.LinuxBash ? _colorScheme.Text : defaultColor; + System.Console.WriteLine(e.ToString()); } - public void WriteException(Exception e) + public virtual void WriteErrorLine(string errorMessage) { - Colorful.Console.WriteLine(e.ToString(), GetColor(_colorScheme.ErrorColor)); + System.Console.WriteLine(errorMessage); } - public void WriteErrorLine(string errorMessage) + public virtual void WriteLine(object objectToWrite) { - Colorful.Console.WriteLine(errorMessage, GetColor(_colorScheme.ErrorColor)); + System.Console.WriteLine(objectToWrite.ToString()); } - public void WriteLine(object objectToWrite) + public virtual void Write(object objectToWrite) { - Colorful.Console.WriteLine(objectToWrite.ToString(), _colorScheme.Text); + System.Console.Write(objectToWrite.ToString()); } - public void Write(object objectToWrite) + public virtual void WriteCommentLine(object objectToWrite) { - Colorful.Console.Write(objectToWrite.ToString(), _colorScheme.Text); + System.Console.WriteLine(objectToWrite.ToString()); } - public void WriteCommentLine(object objectToWrite) + public virtual void WriteLessImportant(object objectToWrite) { - Colorful.Console.WriteLine(objectToWrite.ToString(), _colorScheme.Comment); + System.Console.Write(objectToWrite.ToString()); } - public void WriteLessImportant(object objectToWrite) + public virtual void WriteKeyword(string keyword) { - Colorful.Console.Write(objectToWrite.ToString(), GetColor(_colorScheme.LessImportant)); + System.Console.Write(keyword); } - public void WriteKeyword(string keyword) + public virtual void WriteInteresting(string interesting) { - Colorful.Console.Write(keyword, GetColor(_colorScheme.Keyword)); + System.Console.WriteLine(interesting); } - public void WriteInteresting(string interesting) + public virtual void WriteLine() { - Colorful.Console.WriteLine(interesting, GetColor(_colorScheme.Interesting)); + System.Console.WriteLine(); } - public void WriteLine() + public virtual void WriteGood(string goodText) { - Colorful.Console.WriteLine(); + System.Console.WriteLine(goodText); } - public void WriteGood(string goodText) + public virtual void WriteString(object result) { - Colorful.Console.WriteLine(goodText, GetColor(_colorScheme.Good)); + System.Console.WriteLine(result); } - public void WriteString(object result) + public void ResetColor() { - Colorful.Console.WriteLine(result, GetColor(_colorScheme.String)); + System.Console.ResetColor(); } } diff --git a/src/Nethermind/Nethermind.Cli/Console/ColorfulCliConsole.cs b/src/Nethermind/Nethermind.Cli/Console/ColorfulCliConsole.cs new file mode 100644 index 00000000000..9e8bfc467f9 --- /dev/null +++ b/src/Nethermind/Nethermind.Cli/Console/ColorfulCliConsole.cs @@ -0,0 +1,112 @@ +// Copyright (c) 2022 Demerzel Solutions Limited +// This file is part of the Nethermind library. +// +// The Nethermind library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The Nethermind library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the Nethermind. If not, see . + +using System; +using System.Drawing; +using Nethermind.Core; + +namespace Nethermind.Cli.Console; + +public class ColorfulCliConsole : CliConsole +{ + private static ColorScheme _colorScheme = DraculaColorScheme.Instance; + + public ColorfulCliConsole(ColorScheme colorScheme) + { + _colorScheme = colorScheme; + Colorful.Console.BackgroundColor = colorScheme.BackgroundColor; + _terminal = PrepareConsoleForTerminal(); + + if (Terminal != Terminal.Cmder) + { + Colorful.Console.ForegroundColor = colorScheme.Text; + } + + Colorful.Console.WriteLine("**********************************************", _colorScheme.Comment); + Colorful.Console.WriteLine(); + Colorful.Console.WriteLine("Nethermind CLI {0}", GetColor(_colorScheme.Good), ProductInfo.Version); + Colorful.Console.WriteLine(" https://github.com/NethermindEth/nethermind", GetColor(_colorScheme.Interesting)); + Colorful.Console.WriteLine(" https://nethermind.readthedocs.io/en/latest/", GetColor(_colorScheme.Interesting)); + Colorful.Console.WriteLine(); + Colorful.Console.WriteLine("powered by:", _colorScheme.Text); + Colorful.Console.WriteLine(" https://github.com/sebastienros/jint", GetColor(_colorScheme.Interesting)); + Colorful.Console.WriteLine(" https://github.com/tomakita/Colorful.Console", GetColor(_colorScheme.Interesting)); + Colorful.Console.WriteLine(" https://github.com/tonerdo/readline", GetColor(_colorScheme.Interesting)); + Colorful.Console.WriteLine(); + Colorful.Console.WriteLine("**********************************************", _colorScheme.Comment); + Colorful.Console.WriteLine(); + } + + private Color GetColor(Color defaultColor) + { + return _terminal == Terminal.LinuxBash ? _colorScheme.Text : defaultColor; + } + + public override void WriteException(Exception e) + { + Colorful.Console.WriteLine(e.ToString(), GetColor(_colorScheme.ErrorColor)); + } + + public override void WriteErrorLine(string errorMessage) + { + Colorful.Console.WriteLine(errorMessage, GetColor(_colorScheme.ErrorColor)); + } + + public override void WriteLine(object objectToWrite) + { + Colorful.Console.WriteLine(objectToWrite.ToString(), _colorScheme.Text); + } + + public override void Write(object objectToWrite) + { + Colorful.Console.Write(objectToWrite.ToString(), _colorScheme.Text); + } + + public override void WriteCommentLine(object objectToWrite) + { + Colorful.Console.WriteLine(objectToWrite.ToString(), _colorScheme.Comment); + } + + public override void WriteLessImportant(object objectToWrite) + { + Colorful.Console.Write(objectToWrite.ToString(), GetColor(_colorScheme.LessImportant)); + } + + public override void WriteKeyword(string keyword) + { + Colorful.Console.Write(keyword, GetColor(_colorScheme.Keyword)); + } + + public override void WriteInteresting(string interesting) + { + Colorful.Console.WriteLine(interesting, GetColor(_colorScheme.Interesting)); + } + + public override void WriteLine() + { + Colorful.Console.WriteLine(); + } + + public override void WriteGood(string goodText) + { + Colorful.Console.WriteLine(goodText, GetColor(_colorScheme.Good)); + } + + public override void WriteString(object result) + { + Colorful.Console.WriteLine(result, GetColor(_colorScheme.String)); + } +} diff --git a/src/Nethermind/Nethermind.Cli/Console/ICliConsole.cs b/src/Nethermind/Nethermind.Cli/Console/ICliConsole.cs index 0e24a3a412c..2b924620288 100644 --- a/src/Nethermind/Nethermind.Cli/Console/ICliConsole.cs +++ b/src/Nethermind/Nethermind.Cli/Console/ICliConsole.cs @@ -28,5 +28,9 @@ public interface ICliConsole void WriteGood(string goodText); void WriteString(object result); + + void ResetColor(); + + Terminal Terminal { get; } } } diff --git a/src/Nethermind/Nethermind.Cli/Nethermind.Cli.csproj b/src/Nethermind/Nethermind.Cli/Nethermind.Cli.csproj index f0d7fef40b3..033aeb83cf5 100644 --- a/src/Nethermind/Nethermind.Cli/Nethermind.Cli.csproj +++ b/src/Nethermind/Nethermind.Cli/Nethermind.Cli.csproj @@ -15,6 +15,7 @@ + diff --git a/src/Nethermind/Nethermind.Cli/Program.cs b/src/Nethermind/Nethermind.Cli/Program.cs index 3bba35556a1..cc26d70ace1 100644 --- a/src/Nethermind/Nethermind.Cli/Program.cs +++ b/src/Nethermind/Nethermind.Cli/Program.cs @@ -2,12 +2,15 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Collections.Generic; using System.IO; using System.Runtime.CompilerServices; using System.Text; using Jint.Native; +using Microsoft.Extensions.CommandLineUtils; using Nethermind.Cli.Console; using Nethermind.Cli.Modules; +using Nethermind.Config; using Nethermind.JsonRpc.Modules.Trace; using Nethermind.Logging; using Nethermind.Serialization.Json; @@ -17,45 +20,67 @@ namespace Nethermind.Cli { public static class Program { - private static readonly ColorScheme ColorScheme = DraculaColorScheme.Instance; - private static readonly CliConsole CliConsole = new CliConsole(); - private static readonly StatementHistoryManager HistoryManager = new StatementHistoryManager(CliConsole); - - private static readonly ILogManager LogManager = new OneLoggerLogManager(new CliLogger(CliConsole)); + private static readonly Dictionary _availableColorSchemes = new(){ {"basic", BasicColorScheme.Instance }, + {"dracula", DraculaColorScheme.Instance }}; private static readonly IJsonSerializer Serializer = new EthereumJsonSerializer(); - private static readonly Terminal Terminal = CliConsole.Init(DraculaColorScheme.Instance); - private static readonly ICliEngine Engine = new CliEngine(CliConsole); - private static readonly INodeManager NodeManager = new NodeManager(Engine, Serializer, CliConsole, LogManager); + public static void Main(string[] args) + { + CommandLineApplication app = new() { Name = "Nethermind.Cli" }; + _ = app.HelpOption("-?|-h|--help"); - private static readonly CliModuleLoader ModuleLoader = new CliModuleLoader(Engine, NodeManager, CliConsole); + var colorSchemeOption = app.Option("-cs|--colorScheme ", "Color Scheme. Possible values: Basic|Dracula", CommandOptionType.SingleValue); - public static void Main() - { - RegisterConverters(); - Engine.JintEngine.SetValue("serialize", new Action(v => + app.OnExecute(() => + { + ColorScheme? cs; + ICliConsole cliConsole = colorSchemeOption.HasValue() && (cs = MapColorScheme(colorSchemeOption.Value())) != null + ? new ColorfulCliConsole(cs) + : new CliConsole(); + + var historyManager = new StatementHistoryManager(cliConsole); + ILogManager logManager = new OneLoggerLogManager(new CliLogger(cliConsole)); + ICliEngine engine = new CliEngine(cliConsole); + INodeManager nodeManager = new NodeManager(engine, Serializer, cliConsole, logManager); + var moduleLoader = new CliModuleLoader(engine, nodeManager, cliConsole); + + RegisterConverters(); + engine.JintEngine.SetValue("serialize", new Action(v => + { + string text = Serializer.Serialize(v.ToObject(), true); + cliConsole.WriteGood(text); + })); + + moduleLoader.DiscoverAndLoadModules(); + ReadLine.AutoCompletionHandler = new AutoCompletionHandler(moduleLoader); + + nodeManager.SwitchUri(new Uri("http://localhost:8545")); + historyManager.Init(); + TestConnection(nodeManager, engine, cliConsole); + cliConsole.WriteLine(); + RunEvalLoop(engine, historyManager, cliConsole); + + cliConsole.ResetColor(); + return ExitCodes.Ok; + }); + + try { - string text = Serializer.Serialize(v.ToObject(), true); - CliConsole.WriteGood(text); - })); - - ModuleLoader.DiscoverAndLoadModules(); - ReadLine.AutoCompletionHandler = new AutoCompletionHandler(ModuleLoader); - - NodeManager.SwitchUri(new Uri("http://localhost:8545")); - HistoryManager.Init(); - TestConnection(); - CliConsole.WriteLine(); - RunEvalLoop(); + app.Execute(args); + } + catch (CommandParsingException) + { + app.ShowHelp(); + } } - private static void TestConnection() + private static void TestConnection(INodeManager nodeManager, ICliEngine cliEngine, ICliConsole cliConsole) { - CliConsole.WriteLine($"Connecting to {NodeManager.CurrentUri}"); - JsValue result = Engine.Execute("web3.clientVersion"); + cliConsole.WriteLine($"Connecting to {nodeManager.CurrentUri}"); + JsValue result = cliEngine.Execute("web3.clientVersion"); if (result != JsValue.Null) { - CliConsole.WriteGood("Connected"); + cliConsole.WriteGood("Connected"); } } @@ -88,27 +113,22 @@ internal static string RemoveDangerousCharacters(string statement) return cleaned.ToString(); } - private static void RunEvalLoop() + private static void RunEvalLoop(ICliEngine engine, StatementHistoryManager historyManager, ICliConsole console) { while (true) { try { - if (Terminal != Terminal.Cmder) - { - Colorful.Console.ForegroundColor = ColorScheme.Text; - } - const int bufferSize = 1024 * 16; string statement; using (Stream inStream = System.Console.OpenStandardInput(bufferSize)) { Colorful.Console.SetIn(new StreamReader(inStream, Colorful.Console.InputEncoding, false, bufferSize)); - CliConsole.WriteLessImportant("nethermind> "); - statement = Terminal == Terminal.Cygwin ? Colorful.Console.ReadLine() : ReadLine.Read(); + console.WriteLessImportant("nethermind> "); + statement = console.Terminal == Terminal.Cygwin ? Colorful.Console.ReadLine() : ReadLine.Read(); statement = RemoveDangerousCharacters(statement); - HistoryManager.UpdateHistory(statement); + historyManager.UpdateHistory(statement); } if (statement == "exit") @@ -116,32 +136,32 @@ private static void RunEvalLoop() break; } - JsValue result = Engine.Execute(statement); - WriteResult(result); + JsValue result = engine.Execute(statement); + WriteResult(console, result); } catch (Exception e) { - CliConsole.WriteException(e); + console.WriteException(e); } } } - private static void WriteResult(JsValue result) + private static void WriteResult(ICliConsole cliConsole, JsValue result) { if (result.IsObject() && result.AsObject().Class == "Function") { - CliConsole.WriteGood(result.ToString()); - CliConsole.WriteLine(); + cliConsole.WriteGood(result.ToString()); + cliConsole.WriteLine(); } else if (!result.IsNull()) { string text = Serializer.Serialize(result.ToObject(), true); - CliConsole.WriteGood(text); + cliConsole.WriteGood(text); } else { - CliConsole.WriteLessImportant("null"); - CliConsole.WriteLine(); + cliConsole.WriteLessImportant("null"); + cliConsole.WriteLine(); } } @@ -155,5 +175,10 @@ private static void RegisterConverters() Serializer.RegisterConverter(new ParityVmTraceConverter()); Serializer.RegisterConverter(new TransactionForRpcWithTraceTypesConverter()); } + + private static ColorScheme? MapColorScheme(string colorSchemeOption) + { + return _availableColorSchemes.TryGetValue(colorSchemeOption.ToLower(), out var scheme) ? scheme : null; + } } } diff --git a/src/Nethermind/Nethermind.Cli/Properties/launchSettings.json b/src/Nethermind/Nethermind.Cli/Properties/launchSettings.json new file mode 100644 index 00000000000..23a6e4f64f4 --- /dev/null +++ b/src/Nethermind/Nethermind.Cli/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "Nethermind.Cli": { + "commandName": "Project", + "commandLineArgs": "--colorScheme=dracula" + } + } +} \ No newline at end of file