Last active
December 10, 2021 03:57
-
-
Save krowe/756d334d7e29113f4f466e8cc9269a7c to your computer and use it in GitHub Desktop.
Konsole Library - This is a single C# file which provides many common functions for formatting console output.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Text; | |
using System.Text.RegularExpressions; | |
namespace BuildSite { | |
public class Kolor { | |
public ConsoleColor Foreground { get; set; } = ConsoleColor.Gray; | |
public ConsoleColor Background { get; set; } = ConsoleColor.Black; | |
public Kolor() { Set();} | |
public Kolor(ConsoleColor foreground, ConsoleColor background=ConsoleColor.Black) => Set(foreground, background); | |
public Kolor(Kolor clone) => Set(clone.Foreground, clone.Background); | |
public void Set(ConsoleColor foreground=ConsoleColor.Gray, ConsoleColor background=ConsoleColor.Black) { Foreground=foreground; Background=background; } | |
public void ApplyToKonsole() { | |
if(Foreground!=Console.ForegroundColor) Console.ForegroundColor=Foreground; | |
if(Background!=Console.BackgroundColor) Console.BackgroundColor=Background; | |
} | |
public static Kolor Current { get { return new Kolor(Console.ForegroundColor, Console.BackgroundColor); } } | |
public static Kolor Normal { get => new Kolor(); } | |
public static Kolor Bold { get => new Kolor(ConsoleColor.White); } | |
public static Kolor Small { get => new Kolor(ConsoleColor.DarkGray); } | |
public static Kolor Head { get => new Kolor(ConsoleColor.Yellow); } | |
public static Kolor Lines { get => new Kolor(ConsoleColor.White); } | |
public static Kolor DefinitionTerm { get => new Kolor(ConsoleColor.DarkGreen); } | |
public static Kolor DefinitionData { get => new Kolor(ConsoleColor.White); } | |
public static Kolor Info { get => new Kolor(ConsoleColor.DarkCyan); } | |
public static Kolor Msg { get => new Kolor(ConsoleColor.Cyan); } | |
public static Kolor Warn { get => new Kolor(ConsoleColor.DarkRed); } | |
public static Kolor Error { get => new Kolor(ConsoleColor.Red); } | |
public static Kolor InfoLabel { get => new Kolor(ConsoleColor.DarkYellow); } | |
public static Kolor MsgLabel { get => new Kolor(ConsoleColor.Yellow); } | |
public static Kolor WarnLabel { get => new Kolor(ConsoleColor.DarkYellow); } | |
public static Kolor ErrorLabel { get => new Kolor(ConsoleColor.Yellow); } | |
public static Kolor ProgressBar { get => new Kolor(ConsoleColor.DarkGray); } | |
public static Kolor ProgressBarComplete { get => new Kolor(ConsoleColor.Blue); } | |
public static Kolor ProgressBarBracket { get => new Kolor(ConsoleColor.Yellow); } | |
public static Kolor ProgressBarBracketComplete { get => new Kolor(ConsoleColor.DarkGreen); } | |
} // END class Kolor | |
public class Lokation { | |
int _X; | |
int _Y; | |
public int X { get=>_X; set=>_X=value; } | |
public int Y { get=>_Y; set=>_Y=value; } | |
public int Column { get=>_X; set=>_X=value; } | |
public int Row { get=>_Y; set=>_Y=value; } | |
public Lokation() => Set(); | |
public Lokation(int column, int row) => Set(column,row); | |
public Lokation(Lokation clone) => Set(clone); | |
public void Set(int x=0, int y=0) { X=x; Y=y; } | |
public void Set(Lokation clone) { X=clone.X; Y=clone.Y; } | |
public override string ToString() { return String.Format("{0},{1}", X, Y); } | |
public void ApplyToKonsoleCursor() { Console.CursorLeft=Column; Console.CursorTop=Row; } | |
public static Lokation Current { get { return new Lokation(Console.CursorLeft, Console.CursorTop); } } | |
} // END class Lokation | |
public class Konsole { | |
public const int TabWidth = 8; | |
public static string NewLine { get=>Console.Out.NewLine; set=>Console.Out.NewLine=Console.Error.NewLine=value; } | |
public static string NewLineReplacement = " #[!NEWLINE!]# "; | |
#region Console Methods | |
public static void Write(string msg=null, Kolor color=null) { | |
if(String.IsNullOrEmpty(msg)) return; | |
Kolor oldColor=Kolor.Current; | |
if(color==null) color=Kolor.Normal; | |
color.ApplyToKonsole(); | |
Console.Write(msg); | |
oldColor.ApplyToKonsole(); | |
} | |
public static void Write(Lokation location, string msg=null, Kolor color=null, int display_width=0, bool cursor_return=true) { | |
Lokation oldPosition=Lokation.Current; | |
int display_space_available=Console.BufferWidth-location.Column; | |
if(display_space_available<=0) return; | |
if(display_width<1) display_width=Console.BufferWidth; | |
if(display_width>display_space_available) display_width=display_space_available; | |
location.ApplyToKonsoleCursor(); | |
if(msg==null) msg=""; | |
int msg_space_avaliable=display_space_available-msg.Length; | |
if(msg_space_avaliable<0) msg=msg.Substring(0, -msg_space_avaliable); | |
else if(msg_space_avaliable>0) msg+=new string(' ', msg_space_avaliable); | |
Write(msg, color); | |
if(cursor_return) oldPosition.ApplyToKonsoleCursor(); | |
} | |
public static void WriteLine(string msg=null, Kolor color=null, bool backcolor_fill=true) { | |
if(String.IsNullOrEmpty(msg)) { Console.WriteLine(); return; } | |
string[] outWords=msg.Replace("\r", " ").Replace("\n", NewLineReplacement).Split(new char[] {' '}, StringSplitOptions.RemoveEmptyEntries); | |
if(outWords!=null&&outWords.Length>0) { | |
Kolor oldColor=Kolor.Current; | |
if(color==null) color=Kolor.Normal; | |
color.ApplyToKonsole(); | |
int initialColumn=Console.CursorLeft; // We use this to automatically determine where the left column should be. | |
string word, wordSpacer, wordChunk, NewLineReplacementWord=NewLineReplacement.Trim(); | |
int wrapWidth=Console.BufferWidth-initialColumn, testLineWidth, wordPos; | |
if(wrapWidth>3) { // We skip output altogether if we can't even display 3 characters wide. | |
for(int dx=0; dx<outWords.Length; dx++) { | |
word=outWords[dx]; | |
if(String.IsNullOrEmpty(word)) continue; | |
wordSpacer=dx==outWords.Length-1? "": " "; | |
if(word==NewLineReplacementWord) { | |
Console.Write(new string(' ', Console.BufferWidth-Console.CursorLeft)); | |
} else if(word.Length<=wrapWidth) { // The word is shorter or equal to wrapWidth, we'll wrap normally. | |
testLineWidth=Console.CursorLeft+word.Length; | |
if(testLineWidth==Console.BufferWidth) { // This just barely fits so do not add a spacer and just use the newline as your spacer. | |
if(dx==outWords.Length-1) Console.Write(word); | |
else {Console.Write(word); } // We still need an indent if this isn't the last word. | |
} else if(testLineWidth<Console.BufferWidth) { // Just display normally. | |
Console.Write(word+wordSpacer); | |
} else { // When added, this word makes the line longer than wrapWidth so we need to first wrap the line. | |
Console.Write(new string(' ', Console.BufferWidth-Console.CursorLeft)+word+wordSpacer); | |
} | |
} else { // The word is longer than wrapWidth, we'll wrap the word itself to wrapWidth cols wide. | |
wordPos=Console.BufferWidth-Console.CursorLeft; | |
wordChunk=word.Substring(0, wordPos); // Get the portion that it'll take to finish the current line. | |
Console.Write(wordChunk); | |
while(wordPos<word.Length) { | |
wordChunk=word.Substring(wordPos, Math.Min(wrapWidth, word.Length-wordPos)); // Get the portion that it'll take to finish the current line. | |
Console.Write(wordChunk); | |
wordPos+=wordChunk.Length; | |
if(wordPos<word.Length) { Console.WriteLine(); } | |
else Console.Write(wordSpacer); | |
} | |
} | |
} | |
if(Console.CursorLeft>0) Console.Write(new string(' ', Console.BufferWidth-Console.CursorLeft)); | |
} | |
oldColor.ApplyToKonsole(); | |
} | |
} | |
public static void Info(string msg) { Write("..", Kolor.Info); Write(" Info: ", Kolor.InfoLabel); Wrap(msg, Kolor.DefinitionData); } | |
public static void Msg(string msg) { Write("**", Kolor.Msg); Write(" Message: ", Kolor.MsgLabel); Wrap(msg, Kolor.DefinitionData); } | |
public static void Warn(string msg) { Write("##", Kolor.Warn); Write(" Warning: ", Kolor.WarnLabel); Wrap(msg, Kolor.DefinitionData); } | |
public static void Error(string msg) { Write("!!", Kolor.Error); Write(" Error: ", Kolor.ErrorLabel); Wrap(msg, Kolor.DefinitionData); } | |
public static void Define(string term, string description, int term_col_width=20, Kolor term_color=null, Kolor descr_color=null, | |
WrapOptions options=WrapOptions.FillToEol|WrapOptions.PreserveIndent|WrapOptions.IndentInBlack, WrapPadding pad=WrapPadding.None) { | |
string term_fmt="{0,"+term_col_width+"}: "; | |
if(term_color==null) term_color=Kolor.DefinitionTerm; | |
if(descr_color==null) descr_color=Kolor.DefinitionData; | |
Write(String.Format(term_fmt, ShortenString(term, term_col_width-2)), term_color); | |
Wrap(description, descr_color, options , pad); | |
} | |
public static void ProgressBar(decimal complete=0, int width=20, bool show_value=true) { | |
if(width>Console.BufferWidth-Console.CursorLeft) width=Console.BufferWidth-Console.CursorLeft; | |
if(width<5) width=5; | |
if(complete<0) complete=0; else if(complete>100) complete=100; | |
int ticks_complete=Convert.ToInt32(width*(Convert.ToDouble(complete)/100f)), ticks_remaining=width-ticks_complete; | |
if(ticks_complete>0) Write(new string('█', ticks_complete), Kolor.ProgressBarComplete); | |
if(ticks_remaining>0) Write(new string('▒', ticks_remaining), Kolor.ProgressBar); | |
if(show_value) Write(String.Format(" {0:0}%", complete)); | |
} | |
public static void ProgressBar(Lokation location=null, decimal complete=0, int width=20, bool show_value=true, bool cursor_return=true) { | |
Lokation originalCursorLoc=Lokation.Current; | |
location.ApplyToKonsoleCursor(); | |
ProgressBar(complete, width, show_value); | |
if(cursor_return) originalCursorLoc.ApplyToKonsoleCursor(); | |
} | |
#endregion | |
#region Wrap Method | |
[Flags] public enum WrapOptions {None=0, FillToEol=1, PreserveIndent=2, IndentInBlack=4}; | |
public static string WrapOptions_ToString(WrapOptions options) { | |
string ret=""; | |
if((options&WrapOptions.FillToEol)>0) ret+=(ret.Length>0? ", ": "")+"FillToEol"; | |
if((options&WrapOptions.PreserveIndent)>0) ret+=(ret.Length>0? ", ": "")+"PreserveIndent"; | |
if((options&WrapOptions.IndentInBlack)>0) ret+=(ret.Length>0? ", ": "")+"IndentInBlack"; | |
return ret.Length>0? ret: "None"; | |
} | |
[Flags] public enum WrapPadding {None=0, Top=1, Left=2, Bottom=4, Right=8}; | |
public static string WrapPadding_ToString(WrapPadding pad) { | |
string ret=""; | |
if((pad&WrapPadding.Top)>0) ret+=(ret.Length>0? ", ": "")+"Top"; | |
if((pad&WrapPadding.Left)>0) ret+=(ret.Length>0? ", ": "")+"Left"; | |
if((pad&WrapPadding.Bottom)>0) ret+=(ret.Length>0? ", ": "")+"Bottom"; | |
if((pad&WrapPadding.Right)>0) ret+=(ret.Length>0? ", ": "")+"Right"; | |
return ret.Length>0? ret: "None"; | |
} | |
public const WrapOptions Default_WrapOptions = WrapOptions.FillToEol|WrapOptions.PreserveIndent|WrapOptions.IndentInBlack; | |
public static void Wrap(string msg, Kolor color=null, WrapOptions options=Default_WrapOptions, WrapPadding pad=WrapPadding.None) { | |
string[] outWords=msg.Replace("\r", " ").Replace("\n", NewLineReplacement).Split(new char[] {' '}, StringSplitOptions.RemoveEmptyEntries); | |
if(outWords!=null&&outWords.Length>0) { | |
bool preserveIndent=(options&WrapOptions.PreserveIndent)>0, fillToEol=(options&WrapOptions.FillToEol)>0, indentInBlack=(options&WrapOptions.IndentInBlack)>0, | |
padLeft=(pad&WrapPadding.Left)>0, padRight=(pad&WrapPadding.Right)>0, | |
finalDx=false; | |
Kolor oldColor=Kolor.Current; | |
if(color==null) color=Kolor.Normal; | |
color.ApplyToKonsole(); | |
int initialColumn=Console.CursorLeft; // We use this to automatically determine where the left column should be. | |
string indent=preserveIndent? new string(' ', initialColumn): "", NewLineReplacementWord=NewLineReplacement.Trim(), word, wordChunk/*, wordSpacer*/; | |
int wrapWidth=preserveIndent? Console.BufferWidth-initialColumn: Console.BufferWidth, testLineWidth, wordPos; | |
if(padLeft) wrapWidth--; | |
if(padRight) wrapWidth--; | |
if(wrapWidth>3) { // We skip output altogether if we can't even display 3 characters wide. | |
if((pad&WrapPadding.Top)>0) { | |
_EolFill(fillToEol); | |
if(preserveIndent) _Wrap__Indent(indentInBlack, indent, color.Background); | |
} | |
if(padLeft) Console.Write(" "); | |
for(int dx=0; dx<outWords.Length; dx++) { | |
word=outWords[dx]; | |
if(String.IsNullOrEmpty(word)) continue; | |
finalDx=dx==outWords.Length-1; | |
//wordSpacer=finalDx==false&&outWords[dx+1]!=NewLineReplacementWord? " ": ""; | |
if(word==NewLineReplacementWord) { | |
_EolFill(fillToEol); | |
if(preserveIndent&&finalDx==false) | |
_Wrap__Indent(indentInBlack, indent, color.Background); | |
if(padLeft) Console.Write(" "); | |
} else if(word.Length<=wrapWidth) { // The word is shorter or equal to wrapWidth, we'll wrap normally. | |
testLineWidth=Console.CursorLeft+word.Length; | |
if(padRight) testLineWidth++; | |
if(testLineWidth<Console.BufferWidth) { // Just display normally. | |
if(Console.CursorLeft>initialColumn+(padLeft?1:0)) Console.Write(" "); | |
Console.Write(word); | |
if(Console.CursorLeft<=initialColumn) { | |
if(preserveIndent&&finalDx==false&&outWords[dx+1]!=NewLineReplacementWord) | |
_Wrap__Indent(indentInBlack, indent, color.Background); | |
if(padLeft) Console.Write(" "); | |
} | |
} else { // When added, this word makes the line longer than wrapWidth so we need to first wrap the line. | |
_EolFill(fillToEol); | |
if(preserveIndent) _Wrap__Indent(indentInBlack, indent, color.Background); | |
if(padLeft) Console.Write(" "); | |
Console.Write(word); | |
} | |
} else { // The word is longer than wrapWidth, we'll wrap the word itself to wrapWidth cols wide. | |
if(Console.CursorLeft>initialColumn) Console.Write(" "); | |
wordPos=Console.BufferWidth-Console.CursorLeft; | |
if(padRight) wordPos--; | |
wordChunk=word.Substring(0, wordPos); // Get the portion that it'll take to finish the current line. | |
Console.Write(wordChunk); | |
if(padRight) _EolFill(fillToEol); | |
if(preserveIndent) _Wrap__Indent(indentInBlack, indent, color.Background); | |
if(padLeft) Console.Write(" "); | |
while(wordPos<word.Length) { | |
wordChunk=word.Substring(wordPos, Math.Min(wrapWidth, word.Length-wordPos)); // Get the portion that it'll take to finish the current line. | |
wordPos+=wordChunk.Length; | |
Console.Write(wordChunk); | |
//if(Console.CursorLeft==Console.BufferWidth-1) _Wrap__EolFill(fillToEol); | |
if(wordPos<word.Length) { | |
if(padRight) _EolFill(fillToEol); | |
if(preserveIndent) _Wrap__Indent(indentInBlack, indent, color.Background); | |
if(padLeft) Console.Write(" "); | |
} | |
} | |
} | |
if(!preserveIndent) initialColumn=0; // If we aren't preserving the indent then we want to set this to zero so that we don't need to check the value of preserveIndent any more than needed in the loop. | |
} | |
if(Console.CursorLeft>0) _EolFill(fillToEol); | |
if((pad&WrapPadding.Bottom)>0) { | |
if(preserveIndent) _Wrap__Indent(indentInBlack, indent, color.Background); | |
_EolFill(fillToEol); | |
} | |
} | |
oldColor.ApplyToKonsole(); | |
} else Console.WriteLine(); // If we were passed an empty string we should still output a newline in order to maintain consistency. | |
} | |
private static void _EolFill(bool fillToEol) { | |
if(fillToEol) Console.Write(new string(' ', Console.BufferWidth-Console.CursorLeft)); else Console.WriteLine(); | |
} | |
private static void _Wrap__Indent(bool indentInBlack, string indent, ConsoleColor background) { | |
if(indentInBlack&&Console.BackgroundColor!=ConsoleColor.Black) { | |
Console.BackgroundColor=ConsoleColor.Black; | |
Console.Write(indent); | |
Console.BackgroundColor=background; | |
} else Console.Write(indent); | |
} | |
#endregion | |
#region Head Methods | |
[Flags] public enum HeadOptions {None=0, FillToEol=1, Center=2, CenterInBox=4, IndentInBlack=8, Underline=16, Overline=32}; | |
public static string HeadOptions_ToString(HeadOptions options) { | |
string ret=""; | |
if((options&HeadOptions.FillToEol)>0) ret+=(ret.Length>0? ", ": "")+"FillToEol"; | |
if((options&HeadOptions.Center)>0) ret+=(ret.Length>0? ", ": "")+"Center"; | |
if((options&HeadOptions.CenterInBox)>0) ret+=(ret.Length>0? ", ": "")+"CenterInBox"; | |
if((options&HeadOptions.IndentInBlack)>0) ret+=(ret.Length>0? ", ": "")+"IndentInBlack"; | |
if((options&HeadOptions.Underline)>0) ret+=(ret.Length>0? ", ": "")+"Underline"; | |
if((options&HeadOptions.Overline)>0) ret+=(ret.Length>0? ", ": "")+"Overline"; | |
return ret.Length>0? ret: "None"; | |
} | |
[Flags] public enum HeadPadding {None=0, AboveOverline=1, Left=2, BelowUnderline=4, Right=8, BelowOverline=16, AboveUnderline=32}; | |
public static string HeadPadding_ToString(HeadPadding pad) { | |
string ret=""; | |
if((pad&HeadPadding.AboveOverline)>0) ret+=(ret.Length>0? ", ": "")+"AboveOverline"; | |
if((pad&HeadPadding.Left)>0) ret+=(ret.Length>0? ", ": "")+"Left"; | |
if((pad&HeadPadding.BelowUnderline)>0) ret+=(ret.Length>0? ", ": "")+"BelowUnderline"; | |
if((pad&HeadPadding.Right)>0) ret+=(ret.Length>0? ", ": "")+"Right"; | |
if((pad&HeadPadding.BelowOverline)>0) ret+=(ret.Length>0? ", ": "")+"BelowOverline"; | |
if((pad&HeadPadding.AboveUnderline)>0) ret+=(ret.Length>0? ", ": "")+"AboveUnderline"; | |
return ret.Length>0? ret: "None"; | |
} | |
public static int Default_HeadExtendLines = 0; | |
public static string Default_HeadLineFormat = "-"; | |
public static HeadOptions Default_HeadOptions = HeadOptions.Underline; | |
public static HeadPadding Default_HeadPadding = HeadPadding.None; | |
public static void Head(string msg, int extendLines=-1, string lineFormat=null, | |
Kolor color=null, HeadOptions? options=null, HeadPadding? pad=null, | |
Kolor line_color=null) { | |
if(String.IsNullOrWhiteSpace(msg)) return; | |
Kolor oldColor=Kolor.Current; | |
if(extendLines<0) extendLines=Default_HeadExtendLines; | |
if(String.IsNullOrEmpty(lineFormat)) lineFormat=Default_HeadLineFormat; | |
if(color==null) color=Kolor.Head; | |
if(options==null||options.HasValue==false) options=Default_HeadOptions; | |
if(pad==null||pad.HasValue==false) pad=Default_HeadPadding; | |
if(line_color==null) line_color=Kolor.Lines; | |
string[] lines = msg.Split(new[] { NewLine }, StringSplitOptions.None); | |
int longestLineLen=0; | |
foreach(string line in lines) if(line!=null&&line.Length>longestLineLen) longestLineLen=line.Length; | |
int lineLen=longestLineLen+(extendLines*2); | |
if(lineLen>Console.BufferWidth) lineLen=Console.BufferWidth; | |
string lineString=new StringBuilder().Insert(0, lineFormat, (lineLen/lineFormat.Length)).ToString().Substring(0, lineLen), | |
msgPad=extendLines>0? new string(' ', extendLines):""; | |
bool fillToEol=(options&HeadOptions.FillToEol)>0, centerHeading=(options&HeadOptions.Center)>0, indentInBlack=(options&HeadOptions.IndentInBlack)>0; | |
int startCol=centerHeading? ((Console.BufferWidth-lineLen)/2): 0; | |
string indent=new string(' ', startCol), thisLine; | |
line_color.ApplyToKonsole(); | |
if((pad&HeadPadding.AboveOverline)>0) _EolFill(fillToEol); | |
if((options&HeadOptions.Overline)>0) { | |
_Wrap__Indent(indentInBlack, indent, line_color.Background); | |
if((pad&HeadPadding.Left)>0) Console.Write(" "); | |
Console.Write(lineString); | |
if((pad&HeadPadding.Right)>0) Console.Write(" "); | |
_EolFill(fillToEol); | |
} | |
if((pad&HeadPadding.BelowOverline)>0) { | |
_Wrap__Indent(indentInBlack, indent, line_color.Background); | |
if((pad&HeadPadding.Left)>0) Console.Write(" "); | |
Console.Write(msgPad+(new string(' ', longestLineLen))+msgPad); | |
if((pad&HeadPadding.Right)>0) Console.Write(" "); | |
_EolFill(fillToEol); | |
} | |
color.ApplyToKonsole(); | |
foreach(string line in lines) { | |
_Wrap__Indent(indentInBlack, indent, line_color.Background); | |
if((pad&HeadPadding.Left)>0) Console.Write(" "); | |
thisLine=(options&HeadOptions.CenterInBox)>0? | |
(new string(' ',(longestLineLen-line.Length)/2)+line+new string(' ', (longestLineLen-line.Length)/2)): | |
(line+new string(' ', longestLineLen-line.Length)); | |
if(thisLine.Length<longestLineLen) thisLine+=" "; | |
Console.Write(msgPad+thisLine+msgPad); | |
if((pad&HeadPadding.Right)>0) Console.Write(" "); | |
_EolFill(fillToEol); | |
} | |
line_color.ApplyToKonsole(); | |
if((pad&HeadPadding.AboveUnderline)>0) { | |
_Wrap__Indent(indentInBlack, indent, line_color.Background); | |
if((pad&HeadPadding.Left)>0) Console.Write(" "); | |
Console.Write(msgPad+(new string(' ', longestLineLen))+msgPad); | |
if((pad&HeadPadding.Right)>0) Console.Write(" "); | |
_EolFill(fillToEol); | |
} | |
if((options&HeadOptions.Underline)>0) { | |
_Wrap__Indent(indentInBlack, indent, line_color.Background); | |
if((pad&HeadPadding.Left)>0) Console.Write(" "); | |
Console.Write(lineString); | |
if((pad&HeadPadding.Right)>0) Console.Write(" "); | |
_EolFill(fillToEol); | |
} | |
if((pad&HeadPadding.BelowUnderline)>0) _EolFill(fillToEol); | |
oldColor.ApplyToKonsole(); | |
} | |
#endregion | |
#region Helper Methods | |
public static string ShortenString(string str, int max_len=30) { | |
if(String.IsNullOrEmpty(str)) return ""; | |
if(str.Length<=max_len) return str; | |
return str.Substring(0, max_len-3)+"..."; | |
} | |
#endregion | |
} // END class ConsoleUtility | |
} // END namespace BuildSite |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment