1 /*******************************************************************************
2 
3     Provides the current size of the terminal. Updates the values when
4     the size changes.
5 
6     Copyright:
7         Copyright (c) 2009-2016 dunnhumby Germany GmbH.
8         All rights reserved.
9 
10     License:
11         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
12         Alternatively, this file may be distributed under the terms of the Tango
13         3-Clause BSD License (see LICENSE_BSD.txt for details).
14 
15 *******************************************************************************/
16 
17 module ocean.io.Terminal;
18 
19 /*******************************************************************************
20 
21     C functions and structures to get terminal information
22 
23 ******************************************************************************/
24 
25 import ocean.meta.types.Qualifiers;
26 
27 import core.sys.posix.signal;
28 
29 debug(Term) import ocean.io.Stdout;
30 
31 
32 private
33 {
34     static immutable TIOCGWINSZ = 0x5413;
35     static immutable SIGWINCH = 28;
36 
37     /***************************************************************************
38 
39         Function to get information about the terminal, taken from the C header
40 
41     ***************************************************************************/
42 
43     extern (C) int ioctl ( int d, int request, ... );
44 
45     struct winsize
46     {
47         ushort ws_row;
48         ushort ws_col;
49         ushort ws_xpixel;
50         ushort ws_ypixel;
51     }
52 }
53 
54 /*******************************************************************************
55 
56     Struct containing information and helpers to handle terminals
57 
58     Most of the control sequences can be prefixed with a ASCII digit string
59     (referred to by 'n' from now on) representing usually how often the
60     command should be executed.
61 
62     Cases where this is not the case are documented.
63 
64     Example:
65     -----
66     // Move the cursor four lines up
67     Stdout.formatln("{}4{}", Terminal.CSI, Terminal.CURSOR_UP);
68     -----
69 
70 ******************************************************************************/
71 
72 struct Terminal
73 {
74     /***************************************************************************
75 
76         Amount of columns available in the terminal
77 
78     ***************************************************************************/
79 
80     public static ushort columns;
81 
82     /***************************************************************************
83 
84         Amount of rows (lines) available in the terminal
85 
86     ***************************************************************************/
87 
88     public static ushort rows;
89 
90     /***************************************************************************
91 
92         Start Sequence
93 
94     ***************************************************************************/
95 
96     public enum istring CSI        = "\x1B[";
97 
98     /***************************************************************************
99 
100         Colours
101 
102     ***************************************************************************/
103 
104     public struct Foreground
105     {
106         public enum istring BLACK              = "30m";
107         public enum istring RED                = "31m";
108         public enum istring GREEN              = "32m";
109         public enum istring YELLOW             = "33m";
110         public enum istring BLUE               = "34m";
111         public enum istring MAGENTA            = "35m";
112         public enum istring CYAN               = "36m";
113         public enum istring WHITE              = "37m";
114         public enum istring DEFAULT_UNDERSCORE = "38m";
115         public enum istring DEFAULT            = "39m";
116     }
117 
118     public struct Background
119     {
120         public enum istring BLACK              = "40m";
121         public enum istring RED                = "41m";
122         public enum istring GREEN              = "42m";
123         public enum istring YELLOW             = "43m";
124         public enum istring BLUE               = "44m";
125         public enum istring MAGENTA            = "45m";
126         public enum istring CYAN               = "46m";
127         public enum istring WHITE              = "47m";
128         public enum istring DEFAULT            = "49m";
129     }
130 
131 
132     /***************************************************************************
133 
134         Colour arrays, one for foreground and one for background colours
135         Each uses the Colour enum values as index
136 
137         The enum can be useful for passing to functions in order to specify
138         one of the colours defined in this module with validation
139         (as opposed to accepting a generic string).
140 
141     ***************************************************************************/
142 
143     public enum Colour
144     {
145         Black,
146         Red,
147         Green,
148         Yellow,
149         Blue,
150         Magenta,
151         Cyan,
152         White,
153         Default
154     }
155 
156     public static immutable(istring[]) fg_colour_codes = [
157         Colour.Black: Foreground.BLACK,
158         Colour.Red: Foreground.RED,
159         Colour.Green: Foreground.GREEN,
160         Colour.Yellow: Foreground.YELLOW,
161         Colour.Blue: Foreground.BLUE,
162         Colour.Magenta: Foreground.MAGENTA,
163         Colour.Cyan: Foreground.CYAN,
164         Colour.White: Foreground.WHITE,
165         Colour.Default: Foreground.DEFAULT
166     ];
167 
168     public static immutable(istring[]) bg_colour_codes = [
169         Colour.Black: Background.BLACK,
170         Colour.Red: Background.RED,
171         Colour.Green: Background.GREEN,
172         Colour.Yellow: Background.YELLOW,
173         Colour.Blue: Background.BLUE,
174         Colour.Magenta: Background.MAGENTA,
175         Colour.Cyan: Background.CYAN,
176         Colour.White: Background.WHITE,
177         Colour.Default: Background.DEFAULT
178     ];
179 
180 
181     /***************************************************************************
182 
183         Bold / non-bold text.
184 
185     ***************************************************************************/
186 
187     public enum istring BOLD = "1m";
188 
189     public enum istring NON_BOLD = "22m";
190 
191     /***************************************************************************
192 
193         Command for cursor up
194 
195     ***************************************************************************/
196 
197     public enum istring CURSOR_UP = "A";
198 
199     /***************************************************************************
200 
201         Moves the cursor n lines up and places it at the beginning of the line
202 
203     ***************************************************************************/
204 
205     public enum istring LINE_UP = "F";
206 
207     /***************************************************************************
208 
209         Command for scrolling up
210 
211     ***************************************************************************/
212 
213     public enum istring SCROLL_UP = "S";
214 
215     /***************************************************************************
216 
217         Command for inserting a line
218 
219     ***************************************************************************/
220 
221     public enum istring INSERT_LINE = "L";
222 
223     /***************************************************************************
224 
225         Command for erasing the rest of the line
226 
227         Erases part of the line.
228         If n is zero (or missing), clear from cursor to the end of the line.
229         If n is one, clear from cursor to beginning of the line.
230         If n is two, clear entire line. Cursor position does not change.
231 
232     ***************************************************************************/
233 
234     public enum istring ERASE_REST_OF_LINE = "K";
235 
236     /***************************************************************************
237 
238         Command for erasing everything below and right of the cursor
239 
240         Clears part of the screen.
241         If n is zero (or missing), clear from cursor to end of screen.
242         If n is one, clear from cursor to beginning of the screen.
243         If n is two, clear entire screen (and moves cursor to upper
244         left on MS-DOS ANSI.SYS).
245 
246     ***************************************************************************/
247 
248     public enum istring ERASE_REST_OF_SCREEN = "J";
249 
250     /***************************************************************************
251 
252         Command for hiding the cursor
253 
254     ***************************************************************************/
255 
256     public enum istring HIDE_CURSOR = "?25l";
257 
258     /***************************************************************************
259 
260         Command for showing the cursor
261 
262     ***************************************************************************/
263 
264     public enum istring SHOW_CURSOR = "?25h";
265 
266     /***************************************************************************
267 
268         Moves the cursor to column n.
269 
270     ***************************************************************************/
271 
272     public enum istring HORIZONTAL_MOVE_CURSOR = "G";
273 }
274 
275 /*******************************************************************************
276 
277     Static Constructor.
278 
279     Registers the signal handler for window size changes and gets the size
280     the first time.
281 
282 ******************************************************************************/
283 
284 static this ( )
285 {
286     sigaction_t act;
287     with (act)
288     {
289         sa_flags = SA_SIGINFO;
290         sa_sigaction = &window_size_changed;
291     }
292 
293     sigaction(SIGWINCH, &act, null);
294     window_size_changed(0, null, null);
295 
296     debug(Term) Stdout.formatln("Termsize: {} {}", Terminal.rows, Terminal.columns);
297 }
298 
299 /*******************************************************************************
300 
301     Signal handler.
302 
303     Updates TermInfo with the current terminal size
304 
305     Params:
306         signal = the signal that caused the call (should always be SIGWINCH)(unused)
307         info   = information about the signal (unused)
308         data   = context information (unused)
309 
310 *******************************************************************************/
311 
312 extern (C) private void window_size_changed ( int signal, siginfo_t* info,
313                                               void* data )
314 {
315     winsize max;
316     ioctl(0, TIOCGWINSZ, &max);
317 
318     Terminal.columns = max.ws_col;
319     Terminal.rows    = max.ws_row;
320 }