monotone

monotone Mtn Source Tree

Root/ui.cc

1#include "config.h"
2#include "platform.hh"
3#include "sanity.hh"
4#include "ui.hh"
5#include "transforms.hh"
6
7#include <iostream>
8#include <iomanip>
9#include <boost/lexical_cast.hpp>
10
11// copyright (C) 2002, 2003 graydon hoare <graydon@pobox.com>
12// all rights reserved.
13// licensed to the public under the terms of the GNU GPL (>= 2)
14// see the file COPYING for details
15
16// this file contains a couple utilities to deal with the user
17// interface. the global user_interface object 'ui' owns clog, so no
18// writing to it directly!
19
20using namespace std;
21using boost::lexical_cast;
22struct user_interface ui;
23
24ticker::ticker(string const & tickname, std::string const & s, size_t mod,
25 bool kilocount) :
26 ticks(0),
27 mod(mod),
28 kilocount(kilocount),
29 name(tickname),
30 shortname(s)
31{
32 I(ui.tickers.find(tickname) == ui.tickers.end());
33 ui.tickers.insert(make_pair(tickname,this));
34}
35
36ticker::~ticker()
37{
38 I(ui.tickers.find(name) != ui.tickers.end());
39 if (ui.some_tick_is_dirty)
40 {
41 ui.write_ticks();
42 }
43 ui.tickers.erase(name);
44 ui.finish_ticking();
45}
46
47void
48ticker::operator++()
49{
50 I(ui.tickers.find(name) != ui.tickers.end());
51 ticks++;
52 ui.some_tick_is_dirty = true;
53 if (ticks % mod == 0)
54 ui.write_ticks();
55}
56
57void
58ticker::operator+=(size_t t)
59{
60 I(ui.tickers.find(name) != ui.tickers.end());
61 size_t old = ticks;
62
63 ticks += t;
64 if (t != 0)
65 {
66 ui.some_tick_is_dirty = true;
67 if (ticks % mod == 0 || (ticks / mod) > (old / mod))
68 ui.write_ticks();
69 }
70}
71
72
73tick_write_count::tick_write_count() : last_tick_len(0)
74{
75}
76
77tick_write_count::~tick_write_count()
78{
79}
80
81void tick_write_count::write_ticks()
82{
83 string tickline = "\rmonotone:";
84 for (map<string,ticker *>::const_iterator i = ui.tickers.begin();
85 i != ui.tickers.end(); ++i)
86 {
87 string suffix;
88 ostringstream disptick;
89 if (i->second->kilocount && i->second->ticks >= 10000)
90 { // automatic unit conversion is enabled
91 float div;
92 if (i->second->ticks >= 1048576) {
93 // ticks >=1MB, use Mb
94 div = 1048576;
95 suffix = "M";
96 } else {
97 // ticks <1MB, use kb
98 div = 1024;
99 suffix = "k";
100 }
101 disptick << std::fixed << std::setprecision(1) <<
102 (i->second->ticks / div);
103 } else {
104 // no automatic unit conversion.
105 disptick << i->second->ticks;
106 }
107 tickline +=
108 string(" [")
109 + i->first + ": " + disptick.str()
110 + suffix
111 + "]";
112 }
113 tickline += ui.tick_trailer;
114
115 size_t curr_sz = tickline.size();
116 if (curr_sz < last_tick_len)
117 tickline += string(last_tick_len - curr_sz, ' ');
118 last_tick_len = curr_sz;
119
120 unsigned int tw = terminal_width();
121 if (tw && tickline.size() > tw)
122 {
123 // first character in tickline is "\r", which does not take up any
124 // width, so we add 1 to compensate.
125 tickline.resize(tw + 1);
126 }
127
128 clog << tickline;
129 clog.flush();
130}
131
132void tick_write_count::clear_line()
133{
134 clog << endl;
135}
136
137
138tick_write_dot::tick_write_dot()
139{
140}
141
142tick_write_dot::~tick_write_dot()
143{
144}
145
146void tick_write_dot::write_ticks()
147{
148 string tickline1, tickline2;
149 bool first_tick = true;
150
151 if (ui.last_write_was_a_tick)
152 {
153 tickline1 = "";
154 tickline2 = "";
155 }
156 else
157 {
158 tickline1 = "monotone: ticks: ";
159 tickline2 = "\nmonotone: ";
160 }
161
162 for (map<string,ticker *>::const_iterator i = ui.tickers.begin();
163 i != ui.tickers.end(); ++i)
164 {
165 map<string,size_t>::const_iterator old = last_ticks.find(i->first);
166
167 if (!ui.last_write_was_a_tick)
168 {
169 if (!first_tick)
170 tickline1 += ", ";
171
172 tickline1 +=
173 i->second->shortname + "=\"" + i->second->name + "\""
174 + "/" + lexical_cast<string>(i->second->mod);
175 first_tick = false;
176 }
177
178 if (old == last_ticks.end()
179 || ((i->second->ticks / i->second->mod)
180 > (old->second / i->second->mod)))
181 {
182 tickline2 += i->second->shortname;
183
184 if (old == last_ticks.end())
185 last_ticks.insert(make_pair(i->first, i->second->ticks));
186 else
187 last_ticks[i->first] = i->second->ticks;
188 }
189 }
190
191 clog << tickline1 << tickline2;
192 clog.flush();
193}
194
195void tick_write_dot::clear_line()
196{
197 clog << endl;
198}
199
200
201user_interface::user_interface() :
202 last_write_was_a_tick(false),
203 t_writer(0)
204{
205 clog.sync_with_stdio(false);
206 clog.unsetf(ios_base::unitbuf);
207 if (have_smart_terminal())
208 set_tick_writer(new tick_write_count);
209 else
210 set_tick_writer(new tick_write_dot);
211}
212
213user_interface::~user_interface()
214{
215 delete t_writer;
216}
217
218void
219user_interface::finish_ticking()
220{
221 if (tickers.size() == 0 &&
222 last_write_was_a_tick)
223 {
224 tick_trailer = "";
225 t_writer->clear_line();
226 last_write_was_a_tick = false;
227 }
228}
229
230void
231user_interface::set_tick_trailer(string const & t)
232{
233 tick_trailer = t;
234}
235
236void
237user_interface::set_tick_writer(tick_writer * t)
238{
239 if (t_writer != 0)
240 delete t_writer;
241 t_writer = t;
242}
243
244void
245user_interface::write_ticks()
246{
247 t_writer->write_ticks();
248 last_write_was_a_tick = true;
249 some_tick_is_dirty = false;
250}
251
252void
253user_interface::warn(string const & warning)
254{
255 if (issued_warnings.find(warning) == issued_warnings.end())
256 inform("warning: " + warning);
257 issued_warnings.insert(warning);
258}
259
260void
261user_interface::fatal(string const & fatal)
262{
263 inform("fatal: " + fatal);
264 inform("this is almost certainly a bug in monotone.\n");
265 inform("please send this error message, the output of 'monotone --full-version',\n");
266 inform("and a description of what you were doing to " PACKAGE_BUGREPORT ".\n");
267}
268
269
270static inline string
271sanitize(string const & line)
272{
273 // FIXME: you might want to adjust this if you're using a charset
274 // which has safe values in the sub-0x20 range. ASCII, UTF-8,
275 // and most ISO8859-x sets do not.
276 string tmp;
277 tmp.reserve(line.size());
278 for (size_t i = 0; i < line.size(); ++i)
279 {
280 if ((line[i] == '\n')
281 || (line[i] >= static_cast<char>(0x20)
282 && line[i] != static_cast<char>(0x7F)))
283 tmp += line[i];
284 else
285 tmp += ' ';
286 }
287 return tmp;
288}
289
290void
291user_interface::ensure_clean_line()
292{
293 if (last_write_was_a_tick)
294 {
295 write_ticks();
296 t_writer->clear_line();
297 }
298 last_write_was_a_tick = false;
299}
300
301void
302user_interface::inform(string const & line)
303{
304 string prefixedLine;
305 prefix_lines_with("monotone: ", line, prefixedLine);
306 ensure_clean_line();
307 clog << sanitize(prefixedLine) << endl;
308 clog.flush();
309}

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status