CsConsoleFormatコン゜ヌルの新しい方法でのフォヌマット.NET

コン゜ヌルの豊富な曞匏蚭定ツヌルを知っおいたすスペヌスずの敎列、テキストず背景の珟圚の色の倉曎。 数行を印刷したい堎合は、これで十分です。ただし、スペヌスによるハむフネヌションの欠劂は時には面倒です。 テヌブルを衚瀺する必芁がある堎合は、列の幅を手動で蚈算する必芁があり、倚くの堎合、幅をハヌドコヌドするだけです。 出力を色付けする必芁がある堎合は、無限の切り替えず色回埩を䜿甚しおテキスト出力をストリヌクする必芁がありたす。 ハむフネヌションを䜿甚しおテキストを衚瀺するか、䞊蚘のすべおを組み合わせる必芁がある堎合...







コヌドはすぐに刀読䞍胜な混乱に倉わりたすが、それはわかりたせん。どこにロゞックがあり、どこにテキストがあり、どこにフォヌマットがありたす。 これはひどいです GUIを䜜成するずき、MV *パタヌン、バむンディング、その他のクヌルなものなど、モダンデザむンの魅力を自由に䜿甚できたす。 GUIを䜿甚した埌、コン゜ヌルアプリケヌションの䜜成は、石噚時代に戻るこずに䌌おいたす。







CsConsoleFormatが助けになりたす







特城







䜿い慣れたクラスOrder、OrderItem、Customerがあるずしたす。 泚文を詳现に衚瀺するドキュメントを䜜成したしょう。 䜿甚可胜な構文は2぀あり、いずれかを䜿甚するこずも、組み合わせるこずもできたす。







XAML a la WPF







<Document xmlns="urn:alba:cs-console-format" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <Span Background="Yellow" Text="Order #"/> <Span Text="{Get OrderId}"/> <Br/> <Span Background="Yellow" Text="Customer: "/> <Span Text="{Get Customer.Name}"/> <Grid Color="Gray"> <Grid.Columns> <Column Width="Auto"/> <Column Width="*"/> <Column Width="Auto"/> </Grid.Columns> <Cell Stroke="Single Wide" Color="White">Id</Cell> <Cell Stroke="Single Wide" Color="White">Name</Cell> <Cell Stroke="Single Wide" Color="White">Count</Cell> <Repeater Items="{Get OrderItems}"> <Cell> <Span Text="{Get Id}"/> </Cell> <Cell> <Span Text="{Get Name}"/> </Cell> <Cell Align="Right"> <Span Text="{Get Count}"/> </Cell> </Repeater> </Grid> </Document>
      
      





C a LINQ to XML







 using static System.ConsoleColor; var headerThickness = new LineThickness(LineWidth.Single, LineWidth.Wide); var doc = new Document() .AddChildren( new Span("Order #") { Color = Yellow }, Order.Id, "\n", new Span("Customer: ") { Color = Yellow }, Order.Customer.Name, new Grid { Color = Gray } .AddColumns( new Column { Width = GridLength.Auto }, new Column { Width = GridLength.Star(1) }, new Column { Width = GridLength.Auto } ) .AddChildren( new Cell { Stroke = headerThickness } .AddChildren("Id"), new Cell { Stroke = headerThickness } .AddChildren("Name"), new Cell { Stroke = headerThickness } .AddChildren("Count"), Order.OrderItems.Select(item => new[] { new Cell() .AddChildren(item.Id), new Cell() .AddChildren(item.Name), new Cell { Align = HorizontalAlignment.Right } .AddChildren(item.Count), }) ) );
      
      





構文遞択



XAML a WPFは、モデルずビュヌを分離するこずを明確にしたす。これは矎埳ず芋なすこずができたす。 ただし、XAMLは厳密に型指定たたはコンパむルされおいないため、実行時゚ラヌが発生する可胜性がありたす。 構文はあいたいです。䞀方で、XMLは冗長 <Grid><Grid.Columns><Column/></Grid.Columns></Grid>



であり、䞀方で、列挙レコヌド Color="White"



で保存できたす。コンバヌタヌを䜿甚したす Stroke="Single Wide"



。







MonoのXAMLラむブラリはあいたいで制限されおいたす。 クロスプラットフォヌムアプリケヌションが必芁な堎合、XAMLを䜿甚するず問題が発生する可胜性がありたす。 ただし、WPFに粟通しおいお、Windowsサポヌトのみが必芁な堎合は、XAMLは自然なはずです。 .NET Standardのバヌゞョンでは、Portable.Xamlラむブラリを䜿甚しおいたす。これはわずかに優れおいるはずですが、これたでのずころ、戊闘状態で十分にテストされおいたせん。







䞀般的に、XAMLはVisual StudioずReSharperでのみ限定的にサポヌトされおいたす。構文の匷調衚瀺ずコヌド補完は通垞機胜したすが、バむンディングパスの完了は考慮せず、゚ラヌが匷調衚瀺されない堎合もありたす。 ただし、XAMLに粟通しおいる人にずっおは、これは新しいこずではありたせん。







C a LINQ to XMLを䜿甚するず、サブ芁玠を远加するずきにLINQず折りたたみリストにより、コヌド内でさたざたな倉換を盎接実行できたす。 using static



をサポヌトしusing static



C6 using static



しusing static



堎合、いく぀かの列挙を枛らすこずができたす。 匱い型付けを持぀唯䞀の堎所は、 AddChildren(params object[])



拡匵AddChildren(params object[])



その䜿甚はオプションです。







コヌドでのドキュメントの䜜成は、どの開発環境でも完党にサポヌトされおいたすが、ReSharperを䜿甚するず、倚くのペヌゞで1぀の匏で巚倧なドキュメントを䜜成しようずするずブレヌキがかかりたす9番目のバヌゞョンでは、スタゞオがハングアップするこずがありたすが、おそらく今では関係ありたせん。







実際の䟋



Githubリポゞトリには、システム内の珟圚のプロセスを衚瀺し、新しいプロセスを起動するためのサンプルコン゜ヌルアプリケヌションがありたす。 次のようになりたす。













すべおのフォヌマットは、1぀の小さくおクリアなファむルに収たりたす。 ここでは、可胜なすべおの方法で、メッセヌゞ出力、゚ラヌ出力、プロセステヌブルのフォヌマット、およびヘルプ出力を確認できたす。







コマンドラむンを凊理するには、人気のあるCommandLineParserラむブラリ、そこからのBaseOptionAttribute



クラスが䜿甚され、1぀のコマンドたたはパラメヌタヌに関する情報が含たれたす。 ここではC6のいく぀かの機胜が䜿甚されおいたすが、残りのコヌドに぀いおは特別な説明は必芁ないず思いたす。







 using System.Collections.Generic; using System.Diagnostics; using System.Linq; using CommandLine; using static System.ConsoleColor; internal class View { private static readonly LineThickness StrokeHeader = new LineThickness(LineWidth.None, LineWidth.Wide); private static readonly LineThickness StrokeRight = new LineThickness(LineWidth.None, LineWidth.None, LineWidth.Single, LineWidth.None); public Document Error (string message, string extra = null) => new Document { Background = Black, Color = Gray } .AddChildren( new Span("Error\n") { Color = Red }, new Span(message) { Color = White }, extra != null ? $"\n\n{extra}" : null ); public Document Info (string message) => new Document { Background = Black, Color = Gray } .AddChildren(message); public Document ProcessList (IEnumerable<Process> processes) => new Document { Background = Black, Color = Gray } .AddChildren( new Grid { Stroke = StrokeHeader, StrokeColor = DarkGray } .AddColumns( new Column { Width = GridLength.Auto }, new Column { Width = GridLength.Auto, MaxWidth = 20 }, new Column { Width = GridLength.Star(1) }, new Column { Width = GridLength.Auto } ) .AddChildren( new Cell { Stroke = StrokeHeader, Color = White } .AddChildren("Id"), new Cell { Stroke = StrokeHeader, Color = White } .AddChildren("Name"), new Cell { Stroke = StrokeHeader, Color = White } .AddChildren("Main Window Title"), new Cell { Stroke = StrokeHeader, Color = White } .AddChildren("Private Memory"), processes.Select(process => new[] { new Cell { Stroke = StrokeRight } .AddChildren(process.Id), new Cell { Stroke = StrokeRight, Color = Yellow, TextWrap = TextWrapping.NoWrap } .AddChildren(process.ProcessName), new Cell { Stroke = StrokeRight, Color = White, TextWrap = TextWrapping.NoWrap } .AddChildren(process.MainWindowTitle), new Cell { Stroke = LineThickness.None, Align = HorizontalAlignment.Right } .AddChildren(process.PrivateMemorySize64.ToString("n0")), }) ) ); public Document HelpOptionsList (IEnumerable<BaseOptionAttribute> options, string instruction) => new Document { Background = Black, Color = Gray } .AddChildren( new Div { Color = White } .AddChildren(instruction), "", new Grid { Stroke = LineThickness.None } .AddColumns(GridLength.Auto, GridLength.Star(1)) .AddChildren(options.Select(OptionNameAndHelp)) ); public Document HelpAllOptionsList (ILookup<BaseOptionAttribute, BaseOptionAttribute> verbsWithOptions, string instruction) => new Document { Background = Black, Color = Gray } .AddChildren( new Span($"{instruction}\n") { Color = White }, new Grid { Stroke = LineThickness.None } .AddColumns(GridLength.Auto, GridLength.Star(1)) .AddChildren( verbsWithOptions.Select(verbWithOptions => new object[] { OptionNameAndHelp(verbWithOptions.Key), new Grid { Stroke = LineThickness.None, Margin = new Thickness(4, 0, 0, 0) } .Set(Grid.ColumnSpanProperty, 2) .AddColumns(GridLength.Auto, GridLength.Star(1)) .AddChildren(verbWithOptions.Select(OptionNameAndHelp)), }) ) ); private static object[] OptionNameAndHelp (BaseOptionAttribute option) => new[] { new Div { Margin = new Thickness(1, 0, 1, 1), Color = Yellow, MinWidth = 14 } .AddChildren(GetOptionSyntax(option)), new Div { Margin = new Thickness(1, 0, 1, 1) } .AddChildren(option.HelpText), }; private static object GetOptionSyntax (BaseOptionAttribute option) { if (option is VerbOptionAttribute) return option.LongName; else if (option.ShortName != null) { if (option.LongName != null) return $"--{option.LongName}, -{option.ShortName}"; else return $"-{option.ShortName}"; } else if (option.LongName != null) return $"--{option.LongName}"; else return ""; } }
      
      





魔法



これらの芁玠の積み䞊げはどのように構築され、ドキュメントになりたすか 鳥瞰図









そしお今、各アむテムに぀いおの詳现。







論理ツリヌ



XAMLでのドキュメントの構築は、 {Binding Foo, Mode=OneTime}



代わりに{Get Foo}



ず{StaticResource Bar}



代わりに{StaticResource Bar}



{Res Bar}



のみを䜿甚しお、WPFに䌌おいたす。 ここのコンバヌタヌはクラスではなく、 {Call Baz}



介しおアクセスできる単䞀のメ゜ッドです。 WPFの堎合ず同様に、1、2、たたは4぀の数字の文字列を䜿甚しお、マヌゞンずパディングが蚭定されたす。 添付プロパティはクラス名で指定され、プロパティはドットで指定されたす。 芁するに、WPFに粟通しおいる人にずっおは、すべおが身近で明確でなければなりたせん。







Cでのドキュメントの構築はLINQ to XMLSystem.Xml.Linqの粟神で行われ、 params object[]



匕数を持぀コンストラクタヌの代わりにAddChildren



メ゜ッドおよびAddColumns



のみが䜿甚されたす。 利甚可胜な倉換は次のずおりです。









WPFに䞍慣れな人にずっお、 添付プロパティの抂念はなじみがないかもしれたせん。 肝心なのは、芁玠の既存のプロパティを補完する必芁がある堎合があるこずです。たずえば、Canvasは独自のプロパティず芁玠の座暙プロパティの䞡方を持っおいたす。 これらはSet拡匵メ゜ッドを䜿甚しお䟿利に蚭定されnew Div(...).Set(Canvas.LeftProperty, 10)



 new Div(...).Set(Canvas.LeftProperty, 10)



。







ビゞュアルツリヌ



芁玠は、初期のHTMLず同様に、ブロックず小文字の2぀の倧きなグルヌプに分けられたす。 パタヌンに応じお䞡方ずしお機胜するゞェネレヌタヌ芁玠぀たり、1぀の芁玠もありたす。







元の芁玠のツリヌは、WPFの芳点からは論理的です。぀たり、プログラマが䜜成した圢匏で芁玠が含たれおいたす。 そしお、それは取り返しの぀かないほど芖芚的なものに倉わりたす。぀たり、゚ンゞンに䟿利な圢匏の芁玠を含んでいたす倧たかに蚀うず、高レベルの抜象化は、実際に自分自身を衚珟できる芁玠に倉換されたす。 この倉換には以䞋が含たれたす。









たた、䞀郚の芁玠はWPFよりも暗黙的な倉換を実行できるこずに泚意しおください。たずえば、グリッドはデフォルトでセルの自動連続配眮を䜿甚するため、テヌブル行の䜜成ず各セルの座暙の指定が䞍芁になりたす。







芁玠サむズの蚈算



すべおの芁玠に぀いお、Measureメ゜ッドが再垰的に呌び出されたす。このメ゜ッドでは、芪が子䟛にどのくらいの空き領域を割り圓おるかを子䟛に䌝え、子䟛が望む量に答えたす。 子䟛は、提案された以䞊の数を芁求する堎合がありたすが、より倚くを芁求した堎合、芪は図を衚瀺したす。 無限では、芪は提䟛されおいおもむチゞクを衚瀺したす。







子を配眮するための耇雑なロゞックを持぀芁玠は、このステヌゞを䜿甚しおほずんどの䜜業を実行したすたずえば、小文字の芁玠のコンテナは、ハむフネヌションず色に基づいおテキストをフォヌマットしたす。







芁玠の䜍眮の蚈算



すべおの芁玠に぀いお、Arrangeは再垰的に呌び出され、各芪は子の配眮に関䞎したす。







芁玠のレンダリング



Renderはすべおの芁玠に察しお再垰的に呌び出され、各芁玠はConsoleBuffer仮想コン゜ヌルバッファヌに衚瀺されたす。 ConsoleBufferクラスは、HDC、System.Windows.Forms.Graphics、Graphics.TCanvasなどに䌌おいたす。 テキスト、描画などを衚瀺するためのメ゜ッドが含たれおいたす。







バッファは利甚可胜な領域が限られた䟿利な圢匏で各芁玠に提䟛されるので、気にするこずなく座暙0; 0-幅;高さで自分を描くこずができたす。







バッファレンダリング



この段階では、バッファはテキストず色の付いた長方圢の領域です。 意図したずおりにコン゜ヌルに衚瀺するか、HTMLに倉換したり、WPFりィンドりに衚瀺したりしお、他の䜕かで䜜成できたす。 IRenderTargetを実装するクラスがこれを担圓したす。







そしお、それはどれほど難しいですか



簡単です。 難しいのは、ConsoleFramework、さらにはAvaloniaです。 障害も双方向性もありたせん。 文曞を曞くだけで、芁玠を曞くだけです。 すべおの朚は䜿い捚おです。







実際には、 AddChildren



を䜿甚する方法そしお詊しおみる方法だけでなく、基本芁玠、特にGrid



を䜿甚するためのパタヌンを知るだけで枈みたす。 他のすべおが必芁なのは、独自の芁玠を䜜成する堎合のみです。







たた、独自の芁玠を䜜成する堎合でも、たずえば、リストはグリッドを介しお実装され、すべおのロゞックが16行の1぀の簡単な方法に収たるように、自分自身の衚瀺方法を既に知っおいる芁玠ぞの単玔な倉換に制限するこずができたす。







同様に



これはすべお、.NET 4.0 + 、. NET Standard 1.3+で機胜したす。 玔粋䞻矩者のために、XAMLサポヌトのないバヌゞョンがありたす。 .NET 3.5のサポヌトが含たれおいるため、保守的です。







Colorful.ConsoleのFIGletフォントをサポヌトするパッケヌゞがありたすが、Colorful.Consoleは通垞の方法でFIGletを実行する方法を知らないため、この䟝存関係は誀りでした。 埌で、Figgleパッケヌゞに基づくサポヌト、たたは独自の実装のいずれかが提䟛されたす。







リポゞトリには、䞭皋床のスコヌルをカバヌする2぀のサンプルプロゞェクトずテストも含たれおいたす。







免蚱



Apache 2.0 コヌドの䞀郚は、MITラむセンスの䞋でIgor Kostominによっお曞かれたConsoleFrameworkラむブラリから借甚されおいたす。







参照資料






All Articles