1 /**
2  * Message formatting utilities
3  */
4 module birchwood.protocol.formatting;
5 
6 import birchwood.client.exceptions;
7 
8 /** 
9  * Control codes
10  */
11 public enum ControlCode: char
12 {
13     /** 
14      * Reset styling
15      */
16     Reset = '\x0F',
17 
18     /** 
19      * Bold text styling
20      */
21     Bolden = '\x02',
22 
23     /** 
24      * Italic text styling
25      */
26     Italic = '\x1D',
27 
28     /** 
29      * Underlined text styling
30      */
31     Underline = '\x1F',
32 
33     /** 
34      * Strikethough text styling
35      */
36     Strikethrough = '\x1E',
37 
38     /** 
39      * Monospace text styling
40      */
41     Monospace = '\x11',
42 
43     /** 
44      * Reverse colors (NOTE: not universally supported)
45      */
46     ReverseColors = '\x16',
47 
48     /** 
49      * ASCII color encoding scheme
50      */
51     AsciiColor = '\x03',
52 
53     /** 
54      * Hex color encoding scheme
55      */
56     HexColor = '\x04'
57 }
58 
59 
60 /** 
61  * Simple color codes
62  */
63 public enum SimpleColor: string
64 {
65     WHITE = "00",
66     BLACK = "01",
67     BLUE = "02",
68     GREEN = "03",
69     RED = "04",
70     BROWN = "05",
71     MAGENTA = "06",
72     ORANGE = "07",
73     YELLOW = "08",
74     LIGHT_GREEN = "09",
75     CYAN = "10",
76     LIGHT_CYAN = "11",
77     LIGHT_BLUE = "12",
78     PINK = "13",
79     GREY = "14",
80     LIGHT_GREY = "15",
81     DEFAULT = "99" // NOT UNIVERSALLY SUPPORTED
82 }
83 
84 /** 
85  * Return the hex control character if color is a hexadecimal color code,
86  * the ASCII control character if color is two ASCII digits, and throw an
87  * exception if it's neither.
88  *
89  * This function might be useless now that set_fg and set_fg_bg have been
90  * changed, but I'll keep it in case it's needed later.
91  *
92  * Params:
93  *   color = the color to check for
94  *
95  * Returns: the color control type
96  */
97 private char generateColorControlChar(string color)
98 {
99     if(color.length == 6)
100     {
101         return ControlCode.HexColor;
102     }
103     else if(color.length == 2)
104     {
105         return ControlCode.AsciiColor;
106     }
107     else
108     {
109         throw new BirchwoodException(ErrorType.INVALID_FORMATTING, "Invalid color code (must be either two ASCII digits or a hexadecimal code of the form RRGGBB)");
110     }
111 }
112 
113 /** 
114  * Generates a string that changes the foreground color
115  *
116  * Params:
117  *   color = the foreground color
118  *
119  * Returns:  the color control sequence
120  */
121 public string setForeground(string color)
122 {
123     char[1] control_char;
124 
125     if(color.length == 6)
126     {
127         control_char[0] = ControlCode.HexColor;
128     }
129     else if(color.length == 2)
130     {
131         control_char[0] = ControlCode.AsciiColor;
132     }
133     else
134     {
135         throw new BirchwoodException(ErrorType.INVALID_FORMATTING, "Invalid color code (must be either two ASCII digits or a hexadecimal code of the form RRGGBB)");
136     }
137 
138     return cast(string)control_char~color;
139 }
140 
141 /** 
142  * Generate a string that sets the foreground and background color
143  *
144  * Params:
145  *   fg = foreground color in hex code or ASCII color code
146  *   bg = background color
147  *
148  * Returns: the control sequence to set the style
149  */
150 public string setForegroundBackground(string fg, string bg)
151 {
152     char[1] control_char;
153 
154     if(fg.length != bg.length)
155     {
156         throw new BirchwoodException(ErrorType.INVALID_FORMATTING, "Invalid color code (cannot mix hex and ASCII)");
157     }
158 
159     if(fg.length == 6)
160     {
161         control_char[0] = ControlCode.HexColor;
162     }
163     else if(fg.length == 2)
164     {
165         control_char[0] = ControlCode.AsciiColor;
166     }
167     else
168     {
169         throw new BirchwoodException(ErrorType.INVALID_FORMATTING, "Invalid color code (must be either two ASCII digits or a hexadecimal code of the form RRGGBB)");
170     }
171 
172     return cast(string)control_char~fg~","~bg;
173 }
174 
175 /** 
176  * Generates a string that changes the foreground color (except enum)
177  *
178  * Params:
179  *   color = the foreground color
180  *
181  * Returns: the control sequence
182  */
183 public string setForeground(SimpleColor color)
184 {
185     return ControlCode.AsciiColor~color;
186 }
187 
188 /** 
189  * Generate a string that sets the foreground and background color (except enum)
190  *
191  * Params:
192  *   fg = the foreground color
193  *   bg = the background color
194  *
195  * Returns: thecolor control sequence
196  */
197 public string setForegroundBackground(SimpleColor fg, SimpleColor bg)
198 {
199     return ControlCode.AsciiColor~fg~","~bg;
200 }
201 
202 /** 
203  * Generate a string that resets the foreground
204  * and background colors
205  *
206  * Returns: The control string
207  */
208 public string resetForegroundBackground()
209 {
210     return [ControlCode.AsciiColor];
211 }
212 
213 // Format strings with functions (TODO: remove comment)
214 
215 /** 
216  * Formats the provided text as bold
217  *
218  * Params:
219  *   text = the text to bolden
220  *
221  * Returns: the boldened text 
222  */
223 public string bold(string text)
224 {
225     return ControlCode.Bolden~text~ControlCode.Bolden;
226 }
227 
228 /** 
229  * Formats the provided text in italics
230  *
231  * Params:
232  *   text = the text to italicize
233  *
234  * Returns: the italicized text
235  */
236 public string italics(string text)
237 {
238     return ControlCode.Italic~text~ControlCode.Italic;
239 }
240 
241 /** 
242  * Formats the text as underlined
243  *
244  * Params:
245  *   text = the text to underline
246  *
247  * Returns: the underlined text
248  */
249 public string underline(string text)
250 {
251     return ControlCode.Underline~text~ControlCode.Underline;
252 }
253 
254 /** 
255  * Formats the text as strikethroughed
256  *
257  * Params:
258  *   text = the text to strikethrough
259  *
260  * Returns: the strikethroughed text
261  */
262 public string strikethrough(string text)
263 {
264     return ControlCode.Strikethrough~text~ControlCode.Strikethrough;
265 }
266 
267 /** 
268  * Formats the text as monospaced
269  *
270  * Params:
271  *   text = the text to monospace
272  *
273  * Returns: the monospaced text
274  */
275 public string monospace(string text)
276 {
277     return ControlCode.Monospace~text~ControlCode.Monospace;
278 }