comparison mercurial/ui.py @ 10815:32b213b9b22c

ui: add ui.write() output labeling API This adds output labeling support with the following methods: - ui.write(..., label='topic.name topic2.name2 ...') - ui.write_err(.., label=...) - ui.popbuffer(labeled=False) - ui.label(msg, label) By adding an API to label output directly, the color extension can forgo parsing command output and instead override the above methods to insert ANSI color codes. GUI tools can also override the above methods and use the labels to do GUI-specific styling. popbuffer gains a labeled argument that, when set to True, returns its buffered output with labels handled. In the case of the color extension, this would return output with color codes embedded. For existing users that use this method to capture and parse output, labels are discarded and output returned as normal when labeled is False (the default). Existing wrappers of ui.write() and ui.write_err() should make sure to accept its new **opts argument.
author Brodie Rao <brodie@bitheap.org>
date Fri, 02 Apr 2010 15:22:00 -0500
parents 992723445a29
children 0a548640e012
comparison
equal deleted inserted replaced
10814:cd0c49bdbfd9 10815:32b213b9b22c
237 return path or loc 237 return path or loc
238 238
239 def pushbuffer(self): 239 def pushbuffer(self):
240 self._buffers.append([]) 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 return "".join(self._buffers.pop()) 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 if self._buffers: 271 if self._buffers:
247 self._buffers[-1].extend([str(a) for a in args]) 272 self._buffers[-1].extend([str(a) for a in args])
248 else: 273 else:
249 for a in args: 274 for a in args:
250 sys.stdout.write(str(a)) 275 sys.stdout.write(str(a))
251 276
252 def write_err(self, *args): 277 def write_err(self, *args, **opts):
253 try: 278 try:
254 if not getattr(sys.stdout, 'closed', False): 279 if not getattr(sys.stdout, 'closed', False):
255 sys.stdout.flush() 280 sys.stdout.flush()
256 for a in args: 281 for a in args:
257 sys.stderr.write(str(a)) 282 sys.stderr.write(str(a))
333 return default 358 return default
334 try: 359 try:
335 return getpass.getpass(prompt or _('password: ')) 360 return getpass.getpass(prompt or _('password: '))
336 except EOFError: 361 except EOFError:
337 raise util.Abort(_('response expected')) 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 if not self.quiet: 368 if not self.quiet:
340 self.write(*msg) 369 opts['label'] = opts.get('label', '') + ' ui.status'
341 def warn(self, *msg): 370 self.write(*msg, **opts)
342 self.write_err(*msg) 371 def warn(self, *msg, **opts):
343 def note(self, *msg): 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 if self.verbose: 383 if self.verbose:
345 self.write(*msg) 384 opts['label'] = opts.get('label', '') + ' ui.note'
346 def debug(self, *msg): 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 if self.debugflag: 391 if self.debugflag:
348 self.write(*msg) 392 opts['label'] = opts.get('label', '') + ' ui.debug'
393 self.write(*msg, **opts)
349 def edit(self, text, user): 394 def edit(self, text, user):
350 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt", 395 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
351 text=True) 396 text=True)
352 try: 397 try:
353 f = os.fdopen(fd, "w") 398 f = os.fdopen(fd, "w")
415 pct = 100.0 * pos / total 460 pct = 100.0 * pos / total
416 self.debug('%s:%s %s/%s%s (%4.2f%%)\n' 461 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
417 % (topic, item, pos, total, unit, pct)) 462 % (topic, item, pos, total, unit, pct))
418 else: 463 else:
419 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit)) 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