1 /*******************************************************************************
2 
3     Static console tracer
4 
5     Static console tracer - moves the cursor back to its original position after
6     printing the required text.
7 
8     Copyright:
9         Copyright (c) 2009-2016 dunnhumby Germany GmbH.
10         All rights reserved.
11 
12     License:
13         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
14         Alternatively, this file may be distributed under the terms of the Tango
15         3-Clause BSD License (see LICENSE_BSD.txt for details).
16 
17 *******************************************************************************/
18 
19 module ocean.util.log.StaticTrace;
20 
21 import ocean.core.TypeConvert;
22 import ocean.io.Console;
23 import ocean.io.model.IConduit;
24 import ocean.io.Terminal;
25 import ocean.text.convert.Formatter;
26 import ocean.text.Search;
27 import ocean.meta.types.Qualifiers;
28 
29 
30 /*******************************************************************************
31 
32     Construct StaticTrace when this module is loaded
33 
34 *******************************************************************************/
35 
36 /// global static trace instance
37 public static StaticSyncPrint StaticTrace;
38 
39 static this()
40 {
41     StaticTrace = new StaticSyncPrint(Cerr.stream);
42 }
43 
44 
45 
46 /*******************************************************************************
47 
48     Static trace class - internal only
49 
50 *******************************************************************************/
51 
52 public class StaticSyncPrint
53 {
54     /***************************************************************************
55 
56         Buffer used for string formatting.
57 
58     ***************************************************************************/
59 
60     private mstring formatted;
61 
62     /***************************************************************************
63 
64         Find Fruct to find the \n's
65 
66     ***************************************************************************/
67 
68     private typeof(find(cstring.init)) finder;
69 
70     /***************************************************************************
71 
72         Outputstream to use.
73 
74     ***************************************************************************/
75 
76     private OutputStream output;
77 
78     /***************************************************************************
79 
80         C'tor
81 
82         Params:
83             output = Outputstream to use.
84 
85     ***************************************************************************/
86 
87     public this ( OutputStream output )
88     {
89         this.finder = find(cast(cstring) "\n");
90         this.output = output;
91     }
92 
93     /***************************************************************************
94 
95         Outputs a string to the console.
96 
97         Params:
98             Args = Tuple of arguments to format
99             fmt = format string (same format as tanog.util.log.Trace)
100             args = variadic list of values referenced in format string
101 
102         Returns:
103             this instance for method chaining
104 
105     ***************************************************************************/
106 
107     public typeof(this) format (Args...) ( cstring fmt, Args args )
108     {
109         formatted.length = 0;
110         assumeSafeAppend(this.formatted);
111 
112         sformat(formatted, fmt, args);
113 
114         size_t lines = 0;
115         istring nl = "";
116 
117         foreach ( token; this.finder.tokens(this.formatted) )
118         {
119             with ( this.output )
120             {
121                 write(nl);
122                 write(token);
123                 write(Terminal.CSI);
124                 write(Terminal.ERASE_REST_OF_LINE);
125                 flush();
126             }
127 
128             nl = "\n";
129 
130             lines++;
131         }
132 
133         with (Terminal) if ( lines == 1 )
134         {
135             with ( this.output )
136             {
137                 write(CSI);
138                 write("0");
139                 write(HORIZONTAL_MOVE_CURSOR);
140                 flush();
141             }
142         }
143         else with ( this.output )
144         {
145             formatted.length = 0;
146             assumeSafeAppend(this.formatted);
147             sformat(formatted, "{}", lines - 1);
148 
149             write(CSI);
150             write(formatted);
151             write(LINE_UP);
152             flush();
153         }
154 
155         return this;
156     }
157 
158 
159     /***************************************************************************
160 
161         Flushes the output to the console.
162 
163         Returns:
164             this instance for method chaining
165 
166     ***************************************************************************/
167 
168     public typeof(this) flush ( )
169     {
170         this.output.flush();
171         return this;
172     }
173 }
174 
175 unittest
176 {
177     class FakeStream : OutputStream
178     {
179             override size_t write (const(void)[] src) { return src.length; }
180             override OutputStream copy (InputStream src, size_t max = -1) { return this; }
181             override OutputStream output () { return this; }
182             override long seek (long offset, Anchor anchor = Anchor.Begin) { return offset; }
183             override IConduit conduit () { return null; }
184             override IOStream flush () { return this; }
185             override void close () {}
186     }
187 
188     auto trace = new StaticSyncPrint(new FakeStream);
189     trace.format("static trace says hello {}", 1);
190 }