1 module jcli.text.helptext; 2 3 import jcli.text, std; 4 5 struct HelpTextDescription 6 { 7 uint indent; 8 string text; 9 } 10 11 struct HelpText 12 { 13 enum ARG_NAME_PERCENT = 0.1; 14 enum ARG_GUTTER_PERCENT = 0.05; 15 enum ARG_DESC_PERCENT = 0.3; 16 17 private 18 { 19 TextBuffer _text; 20 size_t _argNameWidth; 21 size_t _argDescWidth; 22 size_t _argGutterWidth; 23 size_t _rowCursor; 24 string _cached; 25 } 26 27 static HelpText make(size_t width) 28 { 29 HelpText t; 30 t._text = new TextBuffer(width, TextBuffer.AUTO_GROW); 31 t._argNameWidth = cast(size_t)((cast(double)width) * ARG_NAME_PERCENT).round; 32 t._argDescWidth = cast(size_t)((cast(double)width) * ARG_DESC_PERCENT).round; 33 t._argGutterWidth = cast(size_t)((cast(double)width) * ARG_GUTTER_PERCENT).round; 34 return t; 35 } 36 37 void addLine(string text) 38 { 39 size_t _1; 40 this._text.setCellsString( 41 0, this._rowCursor, TextBuffer.ALL, 1, 42 text, 43 _1, this._rowCursor 44 ); 45 this._rowCursor += 1; 46 } 47 48 void addLineWithPrefix(string prefix, string text, Nullable!AnsiStyleSet prefixStyle = Nullable!AnsiStyleSet.init) 49 { 50 size_t x; 51 this._text.setCellsString( 52 0, this._rowCursor, prefix.length, 1, 53 prefix, 54 x, this._rowCursor, 55 prefixStyle 56 ); 57 this._text.setCellsString( 58 x + 1, this._rowCursor, TextBuffer.ALL, 1, 59 text, 60 x, this._rowCursor 61 ); 62 } 63 64 void addHeaderWithText(string header, string text) 65 { 66 size_t _1; 67 this._text.setCellsString( 68 0, this._rowCursor, TextBuffer.ALL, 1, 69 header, 70 _1, this._rowCursor, 71 AnsiStyleSet.init.style(AnsiStyle.init.bold).nullable 72 ); 73 this._rowCursor += 1; 74 this._text.setCellsString( 75 (this._text.width > 4) ? 4 : 0, this._rowCursor, TextBuffer.ALL, TextBuffer.AUTO_GROW, 76 text, 77 _1, this._rowCursor, 78 ); 79 this._rowCursor += 2; 80 } 81 82 void addHeader(string header) 83 { 84 size_t _1; 85 this._text.setCellsString( 86 0, this._rowCursor, TextBuffer.ALL, 1, 87 header, 88 _1, this._rowCursor, 89 AnsiStyleSet.init.style(AnsiStyle.init.bold).nullable 90 ); 91 this._rowCursor += 1; 92 } 93 94 void addArgument(string name, HelpTextDescription[] description) 95 { 96 size_t _1; 97 size_t nameRow; 98 size_t descRow = this._rowCursor; 99 this._text.setCellsString( 100 4, this._rowCursor, this._argNameWidth, TextBuffer.AUTO_GROW, 101 name, 102 _1, nameRow 103 ); 104 105 foreach(desc; description) 106 { 107 const indent = desc.indent * 4; 108 this._text.setCellsString( 109 this._argNameWidth + this._argGutterWidth + indent, descRow, this._argDescWidth - indent, TextBuffer.AUTO_GROW, 110 desc.text, 111 _1, descRow 112 ); 113 descRow++; 114 } 115 this._rowCursor = max(nameRow, descRow); 116 } 117 118 string finish() 119 { 120 if(this._cached) 121 return this._cached; 122 123 Appender!(char[]) output; 124 this._text.onRefresh = (row, cells) 125 { 126 AnsiStyleSet style; 127 foreach(cell; cells) 128 { 129 if(cell.style != style && g_jcliTextUseColour) 130 { 131 style = cell.style; 132 output.put(ANSI_COLOUR_RESET); 133 output.put(ANSI_CSI); 134 135 char[AnsiStyleSet.MAX_CHARS_NEEDED] chars; 136 output.put(style.toSequence(chars)); 137 output.put(ANSI_COLOUR_END); 138 } 139 output.put(cell.ch[0..cell.chLen]); 140 } 141 output.put(ANSI_COLOUR_RESET); 142 output.put('\n'); 143 }; 144 this._text.refresh(); 145 this._cached = output.data.assumeUnique; 146 return this._cached; 147 } 148 }