1 /*
2  * Copyright (c) 2018-2020 sel-project
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in all
12  * copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  *
22  */
23 /**
24  * Copyright: Copyright (c) 2018-2020 sel-project
25  * License: MIT
26  * Authors: Kripth
27  * Source: $(HTTP github.com/sel-project/sel-util/terminal/sel/terminal.d, sel/terminal.d)
28  */
29 module sel.terminal;
30 
31 import std.string : indexOf;
32 
33 import sel.format;
34 
35 import terminal : Terminal, Color, Foreground;
36 
37 private Terminal _terminal;
38 
39 static this() {
40 	_terminal = new Terminal();
41 }
42 
43 void write(Terminal terminal, string message) {
44 	synchronized writeImpl(terminal, message);
45 }
46 
47 void write(string message) {
48 	write(_terminal, message);
49 }
50 
51 void writeln(Terminal terminal, string message) {
52 	write(terminal, message);
53 	terminal.reset();
54 	terminal.write("\n");
55 }
56 
57 void writeln(string message) {
58 	writeln(_terminal, message);
59 }
60 
61 void writeImpl(Terminal terminal, string message) {
62 	immutable i = message.indexOf('§');
63 	if(i != -1 && i < message.length - 2) {
64 		immutable c = message[i+2];
65 		if(c >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c >= 'k' && c <= 'o' || c == 'r') {
66 			terminal.write(message[0..i]);
67 			applyFormat(terminal, c);
68 			writeImpl(terminal, message[i+3..$]);
69 		} else {
70 			terminal.write(message[0..i+1]);
71 			writeImpl(terminal, message[i+2..$]);
72 		}
73 	} else {
74 		terminal.write(message);
75 	}
76 }
77 
78 enum char charOf(string code) = code[2];
79 
80 private __gshared Foreground[char] __table;
81 
82 shared static this() {
83 	
84 	import std.process : environment;
85 	
86 	if(environment.get("TERM").indexOf("256") != -1) {
87 		
88 		// should support 24-bit colours
89 		
90 		Foreground rgb(uint num) {
91 			return Foreground((num >> 16) & 0xFF, (num >> 8) & 0xFF, num & 0xFF);
92 		}
93 		
94 		with(Format) {
95 			
96 			__table[charOf!black] = rgb(0x000000);
97 			__table[charOf!darkBlue] = rgb(0x0000AA);
98 			__table[charOf!darkGreen] = rgb(0x00AA00);
99 			__table[charOf!darkAqua] = rgb(0x00AAAA);
100 			__table[charOf!darkRed] = rgb(0xAA0000);
101 			__table[charOf!darkPurple] = rgb(0xAA00AA);
102 			__table[charOf!gold] = rgb(0xFFAA00);
103 			__table[charOf!gray] = rgb(0xAAAAAA);
104 			__table[charOf!darkGray] = rgb(0x555555);
105 			__table[charOf!blue] = rgb(0x5555FF);
106 			__table[charOf!green] = rgb(0x55FF55);
107 			__table[charOf!aqua] = rgb(0x55FFFF);
108 			__table[charOf!red] = rgb(0xFF5555);
109 			__table[charOf!lightPurple] = rgb(0xFF55FF);
110 			__table[charOf!yellow] = rgb(0xFFFF55);
111 			__table[charOf!white] = rgb(0xFFFFFF);
112 			
113 		}
114 		
115 	} else {
116 
117 		with(Format) {
118 		
119 			__table[charOf!black] = Color.black;
120 			__table[charOf!darkBlue] = Color.blue;
121 			__table[charOf!darkGreen] = Color.green;
122 			__table[charOf!darkAqua] = Color.cyan;
123 			__table[charOf!darkRed] = Color.red;
124 			__table[charOf!darkPurple] = Color.magenta;
125 			__table[charOf!gold] = Color.yellow;
126 			__table[charOf!gray] = Color.lightGray;
127 			__table[charOf!darkGray] = Color.gray;
128 			__table[charOf!blue] = Color.brightBlue;
129 			__table[charOf!green] = Color.brightGreen;
130 			__table[charOf!aqua] = Color.brightCyan;
131 			__table[charOf!red] = Color.brightRed;
132 			__table[charOf!lightPurple] = Color.brightMagenta;
133 			__table[charOf!yellow] = Color.brightYellow;
134 			__table[charOf!white] = Color.white;
135 
136 		}
137 		
138 	}
139 	
140 }
141 
142 private void applyFormat(Terminal terminal, char c) {
143 	switch(c) with(Format) {
144 		case charOf!obfuscated: break; // not supported
145 		case charOf!bold:
146 			terminal.bold = true;
147 			break;
148 		case charOf!strikethrough:
149 			terminal.strikethrough = true;
150 			break;
151 		case charOf!underlined:
152 			terminal.underlined = true;
153 			break;
154 		case charOf!italic:
155 			terminal.italic = true;
156 			break;
157 		case charOf!reset:
158 			terminal.reset();
159 			break;
160 		default:
161 			terminal.foreground = __table[c];
162 			break;
163 	}
164 }
165 
166 unittest {
167 
168 	foreach(immutable member ; __traits(allMembers, Format)) {
169 		with(Format) writeln(mixin(member) ~ member);
170 	}
171 
172 	foreach(immutable member ; __traits(allMembers, Format)) {
173 		with(Format) write(mixin(member) ~ "#");
174 	}
175 
176 	_terminal.writeln();
177 
178 }