##// END OF EJS Templates
ui: add ui.write() output labeling API...
Brodie Rao -
r10815:32b213b9 default
parent child Browse files
Show More
@@ -1,192 +1,192
1 1 # progress.py show progress bars for some actions
2 2 #
3 3 # Copyright (C) 2010 Augie Fackler <durin42@gmail.com>
4 4 #
5 5 # This program is free software; you can redistribute it and/or modify it
6 6 # under the terms of the GNU General Public License as published by the
7 7 # Free Software Foundation; either version 2 of the License, or (at your
8 8 # option) any later version.
9 9 #
10 10 # This program is distributed in the hope that it will be useful, but
11 11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13 13 # Public License for more details.
14 14 #
15 15 # You should have received a copy of the GNU General Public License along
16 16 # with this program; if not, write to the Free Software Foundation, Inc.,
17 17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 18
19 19 """show progress bars for some actions
20 20
21 21 This extension uses the progress information logged by hg commands
22 22 to draw progress bars that are as informative as possible. Some progress
23 23 bars only offer indeterminate information, while others have a definite
24 24 end point.
25 25
26 26 The following settings are available::
27 27
28 28 [progress]
29 29 delay = 3 # number of seconds (float) before showing the progress bar
30 30 refresh = 0.1 # time in seconds between refreshes of the progress bar
31 31 format = topic bar number # format of the progress bar
32 32 width = <none> # if set, the maximum width of the progress information
33 33 # (that is, min(width, term width) will be used)
34 34 clear-complete = True # clear the progress bar after it's done
35 35 disable = False # if true, don't show a progress bar
36 36 assume-tty = False # if true, ALWAYS show a progress bar, unless
37 37 # disable is given
38 38
39 39 Valid entries for the format field are topic, bar, number, unit, and
40 40 item. item defaults to the last 20 characters of the item, but this
41 41 can be changed by adding either ``-<num>`` which would take the last
42 42 num characters, or ``+<num>`` for the first num characters.
43 43 """
44 44
45 45 import sys
46 46 import time
47 47
48 48 from mercurial import extensions
49 49 from mercurial import util
50 50
51 51 def spacejoin(*args):
52 52 return ' '.join(s for s in args if s)
53 53
54 54 class progbar(object):
55 55 def __init__(self, ui):
56 56 self.ui = ui
57 57 self.resetstate()
58 58
59 59 def resetstate(self):
60 60 self.topics = []
61 61 self.printed = False
62 62 self.lastprint = time.time() + float(self.ui.config(
63 63 'progress', 'delay', default=3))
64 64 self.indetcount = 0
65 65 self.refresh = float(self.ui.config(
66 66 'progress', 'refresh', default=0.1))
67 67 self.order = self.ui.configlist(
68 68 'progress', 'format',
69 69 default=['topic', 'bar', 'number'])
70 70
71 71 def show(self, topic, pos, item, unit, total):
72 72 termwidth = self.width()
73 73 self.printed = True
74 74 head = ''
75 75 needprogress = False
76 76 tail = ''
77 77 for indicator in self.order:
78 78 add = ''
79 79 if indicator == 'topic':
80 80 add = topic
81 81 elif indicator == 'number':
82 82 if total:
83 83 add = ('% ' + str(len(str(total))) +
84 84 's/%s') % (pos, total)
85 85 else:
86 86 add = str(pos)
87 87 elif indicator.startswith('item') and item:
88 88 slice = 'end'
89 89 if '-' in indicator:
90 90 wid = int(indicator.split('-')[1])
91 91 elif '+' in indicator:
92 92 slice = 'beginning'
93 93 wid = int(indicator.split('+')[1])
94 94 else:
95 95 wid = 20
96 96 if slice == 'end':
97 97 add = item[-wid:]
98 98 else:
99 99 add = item[:wid]
100 100 add += (wid - len(add)) * ' '
101 101 elif indicator == 'bar':
102 102 add = ''
103 103 needprogress = True
104 104 elif indicator == 'unit' and unit:
105 105 add = unit
106 106 if not needprogress:
107 107 head = spacejoin(head, add)
108 108 else:
109 109 tail = spacejoin(add, tail)
110 110 if needprogress:
111 111 used = 0
112 112 if head:
113 113 used += len(head) + 1
114 114 if tail:
115 115 used += len(tail) + 1
116 116 progwidth = termwidth - used - 3
117 117 if total:
118 118 amt = pos * progwidth // total
119 119 bar = '=' * (amt - 1)
120 120 if amt > 0:
121 121 bar += '>'
122 122 bar += ' ' * (progwidth - amt)
123 123 else:
124 124 progwidth -= 3
125 125 self.indetcount += 1
126 126 # mod the count by twice the width so we can make the
127 127 # cursor bounce between the right and left sides
128 128 amt = self.indetcount % (2 * progwidth)
129 129 amt -= progwidth
130 130 bar = (' ' * int(progwidth - abs(amt)) + '<=>' +
131 131 ' ' * int(abs(amt)))
132 132 prog = ''.join(('[', bar , ']'))
133 133 out = spacejoin(head, prog, tail)
134 134 else:
135 135 out = spacejoin(head, tail)
136 136 sys.stderr.write('\r' + out[:termwidth])
137 137 sys.stderr.flush()
138 138
139 139 def clear(self):
140 140 sys.stderr.write('\r%s\r' % (' ' * self.width()))
141 141
142 142 def complete(self):
143 143 if self.ui.configbool('progress', 'clear-complete', default=True):
144 144 self.clear()
145 145 else:
146 146 sys.stderr.write('\n')
147 147 sys.stderr.flush()
148 148
149 149 def width(self):
150 150 tw = util.termwidth()
151 151 return min(int(self.ui.config('progress', 'width', default=tw)), tw)
152 152
153 153 def progress(self, orig, topic, pos, item='', unit='', total=None):
154 154 if pos is None:
155 155 if self.topics and self.topics[-1] == topic and self.printed:
156 156 self.complete()
157 157 self.resetstate()
158 158 else:
159 159 if topic not in self.topics:
160 160 self.topics.append(topic)
161 161 now = time.time()
162 162 if (now - self.lastprint >= self.refresh
163 163 and topic == self.topics[-1]):
164 164 self.lastprint = now
165 165 self.show(topic, pos, item, unit, total)
166 166 return orig(topic, pos, item=item, unit=unit, total=total)
167 167
168 def write(self, orig, *args):
168 def write(self, orig, *args, **opts):
169 169 if self.printed:
170 170 self.clear()
171 return orig(*args)
171 return orig(*args, **opts)
172 172
173 173 sharedprog = None
174 174
175 175 def uisetup(ui):
176 176 # Apps that derive a class from ui.ui() can use
177 177 # setconfig('progress', 'disable', 'True') to disable this extension
178 178 if ui.configbool('progress', 'disable'):
179 179 return
180 180 if ((sys.stderr.isatty() or ui.configbool('progress', 'assume-tty'))
181 181 and not ui.debugflag and not ui.quiet):
182 182 # we instantiate one globally shared progress bar to avoid
183 183 # competing progress bars when multiple UI objects get created
184 184 global sharedprog
185 185 if not sharedprog:
186 186 sharedprog = progbar(ui)
187 187 extensions.wrapfunction(ui, 'progress', sharedprog.progress)
188 188 extensions.wrapfunction(ui, 'write', sharedprog.write)
189 189 extensions.wrapfunction(ui, 'write_err', sharedprog.write)
190 190
191 191 def reposetup(ui, repo):
192 192 uisetup(repo.ui)
@@ -1,419 +1,476
1 1 # ui.py - user interface bits for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from i18n import _
9 9 import errno, getpass, os, socket, sys, tempfile, traceback
10 10 import config, util, error
11 11
12 12 _booleans = {'1': True, 'yes': True, 'true': True, 'on': True,
13 13 '0': False, 'no': False, 'false': False, 'off': False}
14 14
15 15 class ui(object):
16 16 def __init__(self, src=None):
17 17 self._buffers = []
18 18 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
19 19 self._reportuntrusted = True
20 20 self._ocfg = config.config() # overlay
21 21 self._tcfg = config.config() # trusted
22 22 self._ucfg = config.config() # untrusted
23 23 self._trustusers = set()
24 24 self._trustgroups = set()
25 25
26 26 if src:
27 27 self._tcfg = src._tcfg.copy()
28 28 self._ucfg = src._ucfg.copy()
29 29 self._ocfg = src._ocfg.copy()
30 30 self._trustusers = src._trustusers.copy()
31 31 self._trustgroups = src._trustgroups.copy()
32 32 self.environ = src.environ
33 33 self.fixconfig()
34 34 else:
35 35 # shared read-only environment
36 36 self.environ = os.environ
37 37 # we always trust global config files
38 38 for f in util.rcpath():
39 39 self.readconfig(f, trust=True)
40 40
41 41 def copy(self):
42 42 return self.__class__(self)
43 43
44 44 def _is_trusted(self, fp, f):
45 45 st = util.fstat(fp)
46 46 if util.isowner(st):
47 47 return True
48 48
49 49 tusers, tgroups = self._trustusers, self._trustgroups
50 50 if '*' in tusers or '*' in tgroups:
51 51 return True
52 52
53 53 user = util.username(st.st_uid)
54 54 group = util.groupname(st.st_gid)
55 55 if user in tusers or group in tgroups or user == util.username():
56 56 return True
57 57
58 58 if self._reportuntrusted:
59 59 self.warn(_('Not trusting file %s from untrusted '
60 60 'user %s, group %s\n') % (f, user, group))
61 61 return False
62 62
63 63 def readconfig(self, filename, root=None, trust=False,
64 64 sections=None, remap=None):
65 65 try:
66 66 fp = open(filename)
67 67 except IOError:
68 68 if not sections: # ignore unless we were looking for something
69 69 return
70 70 raise
71 71
72 72 cfg = config.config()
73 73 trusted = sections or trust or self._is_trusted(fp, filename)
74 74
75 75 try:
76 76 cfg.read(filename, fp, sections=sections, remap=remap)
77 77 except error.ConfigError, inst:
78 78 if trusted:
79 79 raise
80 80 self.warn(_("Ignored: %s\n") % str(inst))
81 81
82 82 if self.plain():
83 83 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
84 84 'logtemplate', 'style',
85 85 'traceback', 'verbose'):
86 86 if k in cfg['ui']:
87 87 del cfg['ui'][k]
88 88 for k, v in cfg.items('alias'):
89 89 del cfg['alias'][k]
90 90 for k, v in cfg.items('defaults'):
91 91 del cfg['defaults'][k]
92 92
93 93 if trusted:
94 94 self._tcfg.update(cfg)
95 95 self._tcfg.update(self._ocfg)
96 96 self._ucfg.update(cfg)
97 97 self._ucfg.update(self._ocfg)
98 98
99 99 if root is None:
100 100 root = os.path.expanduser('~')
101 101 self.fixconfig(root=root)
102 102
103 103 def fixconfig(self, root=None):
104 104 # translate paths relative to root (or home) into absolute paths
105 105 root = root or os.getcwd()
106 106 for c in self._tcfg, self._ucfg, self._ocfg:
107 107 for n, p in c.items('paths'):
108 108 if p and "://" not in p and not os.path.isabs(p):
109 109 c.set("paths", n, os.path.normpath(os.path.join(root, p)))
110 110
111 111 # update ui options
112 112 self.debugflag = self.configbool('ui', 'debug')
113 113 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
114 114 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
115 115 if self.verbose and self.quiet:
116 116 self.quiet = self.verbose = False
117 117 self._reportuntrusted = self.configbool("ui", "report_untrusted", True)
118 118 self.tracebackflag = self.configbool('ui', 'traceback', False)
119 119
120 120 # update trust information
121 121 self._trustusers.update(self.configlist('trusted', 'users'))
122 122 self._trustgroups.update(self.configlist('trusted', 'groups'))
123 123
124 124 def setconfig(self, section, name, value):
125 125 for cfg in (self._ocfg, self._tcfg, self._ucfg):
126 126 cfg.set(section, name, value)
127 127 self.fixconfig()
128 128
129 129 def _data(self, untrusted):
130 130 return untrusted and self._ucfg or self._tcfg
131 131
132 132 def configsource(self, section, name, untrusted=False):
133 133 return self._data(untrusted).source(section, name) or 'none'
134 134
135 135 def config(self, section, name, default=None, untrusted=False):
136 136 value = self._data(untrusted).get(section, name, default)
137 137 if self.debugflag and not untrusted and self._reportuntrusted:
138 138 uvalue = self._ucfg.get(section, name)
139 139 if uvalue is not None and uvalue != value:
140 140 self.debug(_("ignoring untrusted configuration option "
141 141 "%s.%s = %s\n") % (section, name, uvalue))
142 142 return value
143 143
144 144 def configbool(self, section, name, default=False, untrusted=False):
145 145 v = self.config(section, name, None, untrusted)
146 146 if v is None:
147 147 return default
148 148 if isinstance(v, bool):
149 149 return v
150 150 if v.lower() not in _booleans:
151 151 raise error.ConfigError(_("%s.%s not a boolean ('%s')")
152 152 % (section, name, v))
153 153 return _booleans[v.lower()]
154 154
155 155 def configlist(self, section, name, default=None, untrusted=False):
156 156 """Return a list of comma/space separated strings"""
157 157 result = self.config(section, name, untrusted=untrusted)
158 158 if result is None:
159 159 result = default or []
160 160 if isinstance(result, basestring):
161 161 result = result.replace(",", " ").split()
162 162 return result
163 163
164 164 def has_section(self, section, untrusted=False):
165 165 '''tell whether section exists in config.'''
166 166 return section in self._data(untrusted)
167 167
168 168 def configitems(self, section, untrusted=False):
169 169 items = self._data(untrusted).items(section)
170 170 if self.debugflag and not untrusted and self._reportuntrusted:
171 171 for k, v in self._ucfg.items(section):
172 172 if self._tcfg.get(section, k) != v:
173 173 self.debug(_("ignoring untrusted configuration option "
174 174 "%s.%s = %s\n") % (section, k, v))
175 175 return items
176 176
177 177 def walkconfig(self, untrusted=False):
178 178 cfg = self._data(untrusted)
179 179 for section in cfg.sections():
180 180 for name, value in self.configitems(section, untrusted):
181 181 yield section, name, str(value).replace('\n', '\\n')
182 182
183 183 def plain(self):
184 184 return 'HGPLAIN' in os.environ
185 185
186 186 def username(self):
187 187 """Return default username to be used in commits.
188 188
189 189 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
190 190 and stop searching if one of these is set.
191 191 If not found and ui.askusername is True, ask the user, else use
192 192 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
193 193 """
194 194 user = os.environ.get("HGUSER")
195 195 if user is None:
196 196 user = self.config("ui", "username")
197 197 if user is None:
198 198 user = os.environ.get("EMAIL")
199 199 if user is None and self.configbool("ui", "askusername"):
200 200 user = self.prompt(_("enter a commit username:"), default=None)
201 201 if user is None and not self.interactive():
202 202 try:
203 203 user = '%s@%s' % (util.getuser(), socket.getfqdn())
204 204 self.warn(_("No username found, using '%s' instead\n") % user)
205 205 except KeyError:
206 206 pass
207 207 if not user:
208 208 raise util.Abort(_('no username supplied (see "hg help config")'))
209 209 if "\n" in user:
210 210 raise util.Abort(_("username %s contains a newline\n") % repr(user))
211 211 return user
212 212
213 213 def shortuser(self, user):
214 214 """Return a short representation of a user name or email address."""
215 215 if not self.verbose:
216 216 user = util.shortuser(user)
217 217 return user
218 218
219 219 def _path(self, loc):
220 220 p = self.config('paths', loc)
221 221 if p:
222 222 if '%%' in p:
223 223 self.warn("(deprecated '%%' in path %s=%s from %s)\n" %
224 224 (loc, p, self.configsource('paths', loc)))
225 225 p = p.replace('%%', '%')
226 226 p = util.expandpath(p)
227 227 return p
228 228
229 229 def expandpath(self, loc, default=None):
230 230 """Return repository location relative to cwd or from [paths]"""
231 231 if "://" in loc or os.path.isdir(os.path.join(loc, '.hg')):
232 232 return loc
233 233
234 234 path = self._path(loc)
235 235 if not path and default is not None:
236 236 path = self._path(default)
237 237 return path or loc
238 238
239 239 def pushbuffer(self):
240 240 self._buffers.append([])
241 241
242 def popbuffer(self):
242 def popbuffer(self, labeled=False):
243 '''pop the last buffer and return the buffered output
244
245 If labeled is True, any labels associated with buffered
246 output will be handled. By default, this has no effect
247 on the output returned, but extensions and GUI tools may
248 handle this argument and returned styled output. If output
249 is being buffered so it can be captured and parsed or
250 processed, labeled should not be set to True.
251 '''
243 252 return "".join(self._buffers.pop())
244 253
245 def write(self, *args):
254 def write(self, *args, **opts):
255 '''write args to output
256
257 By default, this method simply writes to the buffer or stdout,
258 but extensions or GUI tools may override this method,
259 write_err(), popbuffer(), and label() to style output from
260 various parts of hg.
261
262 An optional keyword argument, "label", can be passed in.
263 This should be a string containing label names separated by
264 space. Label names take the form of "topic.type". For example,
265 ui.debug() issues a label of "ui.debug".
266
267 When labeling output for a specific command, a label of
268 "cmdname.type" is recommended. For example, status issues
269 a label of "status.modified" for modified files.
270 '''
246 271 if self._buffers:
247 272 self._buffers[-1].extend([str(a) for a in args])
248 273 else:
249 274 for a in args:
250 275 sys.stdout.write(str(a))
251 276
252 def write_err(self, *args):
277 def write_err(self, *args, **opts):
253 278 try:
254 279 if not getattr(sys.stdout, 'closed', False):
255 280 sys.stdout.flush()
256 281 for a in args:
257 282 sys.stderr.write(str(a))
258 283 # stderr may be buffered under win32 when redirected to files,
259 284 # including stdout.
260 285 if not getattr(sys.stderr, 'closed', False):
261 286 sys.stderr.flush()
262 287 except IOError, inst:
263 288 if inst.errno != errno.EPIPE:
264 289 raise
265 290
266 291 def flush(self):
267 292 try: sys.stdout.flush()
268 293 except: pass
269 294 try: sys.stderr.flush()
270 295 except: pass
271 296
272 297 def interactive(self):
273 298 i = self.configbool("ui", "interactive", None)
274 299 if i is None:
275 300 try:
276 301 return sys.stdin.isatty()
277 302 except AttributeError:
278 303 # some environments replace stdin without implementing isatty
279 304 # usually those are non-interactive
280 305 return False
281 306
282 307 return i
283 308
284 309 def _readline(self, prompt=''):
285 310 if sys.stdin.isatty():
286 311 try:
287 312 # magically add command line editing support, where
288 313 # available
289 314 import readline
290 315 # force demandimport to really load the module
291 316 readline.read_history_file
292 317 # windows sometimes raises something other than ImportError
293 318 except Exception:
294 319 pass
295 320 line = raw_input(prompt)
296 321 # When stdin is in binary mode on Windows, it can cause
297 322 # raw_input() to emit an extra trailing carriage return
298 323 if os.linesep == '\r\n' and line and line[-1] == '\r':
299 324 line = line[:-1]
300 325 return line
301 326
302 327 def prompt(self, msg, default="y"):
303 328 """Prompt user with msg, read response.
304 329 If ui is not interactive, the default is returned.
305 330 """
306 331 if not self.interactive():
307 332 self.write(msg, ' ', default, "\n")
308 333 return default
309 334 try:
310 335 r = self._readline(msg + ' ')
311 336 if not r:
312 337 return default
313 338 return r
314 339 except EOFError:
315 340 raise util.Abort(_('response expected'))
316 341
317 342 def promptchoice(self, msg, choices, default=0):
318 343 """Prompt user with msg, read response, and ensure it matches
319 344 one of the provided choices. The index of the choice is returned.
320 345 choices is a sequence of acceptable responses with the format:
321 346 ('&None', 'E&xec', 'Sym&link') Responses are case insensitive.
322 347 If ui is not interactive, the default is returned.
323 348 """
324 349 resps = [s[s.index('&')+1].lower() for s in choices]
325 350 while True:
326 351 r = self.prompt(msg, resps[default])
327 352 if r.lower() in resps:
328 353 return resps.index(r.lower())
329 354 self.write(_("unrecognized response\n"))
330 355
331 356 def getpass(self, prompt=None, default=None):
332 357 if not self.interactive():
333 358 return default
334 359 try:
335 360 return getpass.getpass(prompt or _('password: '))
336 361 except EOFError:
337 362 raise util.Abort(_('response expected'))
338 def status(self, *msg):
363 def status(self, *msg, **opts):
364 '''write status message to output (if ui.quiet is False)
365
366 This adds an output label of "ui.status".
367 '''
339 368 if not self.quiet:
340 self.write(*msg)
341 def warn(self, *msg):
342 self.write_err(*msg)
343 def note(self, *msg):
369 opts['label'] = opts.get('label', '') + ' ui.status'
370 self.write(*msg, **opts)
371 def warn(self, *msg, **opts):
372 '''write warning message to output (stderr)
373
374 This adds an output label of "ui.warning".
375 '''
376 opts['label'] = opts.get('label', '') + ' ui.warning'
377 self.write_err(*msg, **opts)
378 def note(self, *msg, **opts):
379 '''write note to output (if ui.verbose is True)
380
381 This adds an output label of "ui.note".
382 '''
344 383 if self.verbose:
345 self.write(*msg)
346 def debug(self, *msg):
384 opts['label'] = opts.get('label', '') + ' ui.note'
385 self.write(*msg, **opts)
386 def debug(self, *msg, **opts):
387 '''write debug message to output (if ui.debugflag is True)
388
389 This adds an output label of "ui.debug".
390 '''
347 391 if self.debugflag:
348 self.write(*msg)
392 opts['label'] = opts.get('label', '') + ' ui.debug'
393 self.write(*msg, **opts)
349 394 def edit(self, text, user):
350 395 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
351 396 text=True)
352 397 try:
353 398 f = os.fdopen(fd, "w")
354 399 f.write(text)
355 400 f.close()
356 401
357 402 editor = self.geteditor()
358 403
359 404 util.system("%s \"%s\"" % (editor, name),
360 405 environ={'HGUSER': user},
361 406 onerr=util.Abort, errprefix=_("edit failed"))
362 407
363 408 f = open(name)
364 409 t = f.read()
365 410 f.close()
366 411 finally:
367 412 os.unlink(name)
368 413
369 414 return t
370 415
371 416 def traceback(self, exc=None):
372 417 '''print exception traceback if traceback printing enabled.
373 418 only to call in exception handler. returns true if traceback
374 419 printed.'''
375 420 if self.tracebackflag:
376 421 if exc:
377 422 traceback.print_exception(exc[0], exc[1], exc[2])
378 423 else:
379 424 traceback.print_exc()
380 425 return self.tracebackflag
381 426
382 427 def geteditor(self):
383 428 '''return editor to use'''
384 429 return (os.environ.get("HGEDITOR") or
385 430 self.config("ui", "editor") or
386 431 os.environ.get("VISUAL") or
387 432 os.environ.get("EDITOR", "vi"))
388 433
389 434 def progress(self, topic, pos, item="", unit="", total=None):
390 435 '''show a progress message
391 436
392 437 With stock hg, this is simply a debug message that is hidden
393 438 by default, but with extensions or GUI tools it may be
394 439 visible. 'topic' is the current operation, 'item' is a
395 440 non-numeric marker of the current position (ie the currently
396 441 in-process file), 'pos' is the current numeric position (ie
397 442 revision, bytes, etc.), unit is a corresponding unit label,
398 443 and total is the highest expected pos.
399 444
400 445 Multiple nested topics may be active at a time.
401 446
402 447 All topics should be marked closed by setting pos to None at
403 448 termination.
404 449 '''
405 450
406 451 if pos == None or not self.debugflag:
407 452 return
408 453
409 454 if unit:
410 455 unit = ' ' + unit
411 456 if item:
412 457 item = ' ' + item
413 458
414 459 if total:
415 460 pct = 100.0 * pos / total
416 461 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
417 462 % (topic, item, pos, total, unit, pct))
418 463 else:
419 464 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
465
466 def label(self, msg, label):
467 '''style msg based on supplied label
468
469 Like ui.write(), this just returns msg unchanged, but extensions
470 and GUI tools can override it to allow styling output without
471 writing it.
472
473 ui.write(s, 'label') is equivalent to
474 ui.write(ui.label(s, 'label')).
475 '''
476 return msg
General Comments 0
You need to be logged in to leave comments. Login now