# HG changeset patch # User Yuya Nishihara # Date 1421571328 -32400 # Node ID 83dd8c63a0c6c2bddee10b9d7f66cec5a0486567 # Parent 054d0fcba2c4a4f65b009d92c1fd9d285e9af5f6 ui: extract helpers to write message with type or label This provides a 'type' attribute to command-server clients, which seems more solid than relying on 'ui.' labels. In future patches, type='progress' will be added to send raw progress information. diff -r 054d0fcba2c4 -r 83dd8c63a0c6 mercurial/commandserver.py --- a/mercurial/commandserver.py Sun Jan 18 18:49:59 2015 +0900 +++ b/mercurial/commandserver.py Sun Jan 18 17:55:28 2015 +0900 @@ -78,6 +78,9 @@ data length (unsigned int), encoded message and metadata, as a flat key-value dict. + + Each message should have 'type' attribute. Messages of unknown type + should be ignored. """ # teach ui that write() can take **opts diff -r 054d0fcba2c4 -r 83dd8c63a0c6 mercurial/ui.py --- a/mercurial/ui.py Sun Jan 18 18:49:59 2015 +0900 +++ b/mercurial/ui.py Sun Jan 18 17:55:28 2015 +0900 @@ -1039,6 +1039,12 @@ self._blockedtimes['stdio_blocked'] += \ (util.timer() - starttime) * 1000 + def _writemsg(self, dest, *args, **opts): + _writemsgwith(self._write, dest, *args, **opts) + + def _writemsgnobuf(self, dest, *args, **opts): + _writemsgwith(self._writenobuf, dest, *args, **opts) + def flush(self): # opencode timeblockedsection because this is a critical path starttime = util.timer() @@ -1385,18 +1391,18 @@ If ui is not interactive, the default is returned. """ if not self.interactive(): - self._write(self._fmsgout, msg, ' ', label='ui.prompt') - self._write(self._fmsgout, default or '', "\n", - label='ui.promptecho') + self._writemsg(self._fmsgout, msg, ' ', type='prompt') + self._writemsg(self._fmsgout, default or '', "\n", + type='promptecho') return default - self._writenobuf(self._fmsgout, msg, label='ui.prompt') + self._writemsgnobuf(self._fmsgout, msg, type='prompt') self.flush() try: r = self._readline() if not r: r = default if self.configbool('ui', 'promptecho'): - self._write(self._fmsgout, r, "\n", label='ui.promptecho') + self._writemsg(self._fmsgout, r, "\n", type='promptecho') return r except EOFError: raise error.ResponseExpected() @@ -1447,14 +1453,14 @@ if r.lower() in resps: return resps.index(r.lower()) # TODO: shouldn't it be a warning? - self._write(self._fmsgout, _("unrecognized response\n")) + self._writemsg(self._fmsgout, _("unrecognized response\n")) def getpass(self, prompt=None, default=None): if not self.interactive(): return default try: - self._write(self._fmsgerr, prompt or _('password: '), - label='ui.prompt') + self._writemsg(self._fmsgerr, prompt or _('password: '), + type='prompt') # disable getpass() only if explicitly specified. it's still valid # to interact with tty even if fin is not a tty. with self.timeblockedsection('stdio'): @@ -1474,24 +1480,21 @@ This adds an output label of "ui.status". ''' if not self.quiet: - opts[r'label'] = opts.get(r'label', '') + ' ui.status' - self._write(self._fmsgout, *msg, **opts) + self._writemsg(self._fmsgout, type='status', *msg, **opts) def warn(self, *msg, **opts): '''write warning message to output (stderr) This adds an output label of "ui.warning". ''' - opts[r'label'] = opts.get(r'label', '') + ' ui.warning' - self._write(self._fmsgerr, *msg, **opts) + self._writemsg(self._fmsgerr, type='warning', *msg, **opts) def error(self, *msg, **opts): '''write error message to output (stderr) This adds an output label of "ui.error". ''' - opts[r'label'] = opts.get(r'label', '') + ' ui.error' - self._write(self._fmsgerr, *msg, **opts) + self._writemsg(self._fmsgerr, type='error', *msg, **opts) def note(self, *msg, **opts): '''write note to output (if ui.verbose is True) @@ -1499,8 +1502,7 @@ This adds an output label of "ui.note". ''' if self.verbose: - opts[r'label'] = opts.get(r'label', '') + ' ui.note' - self._write(self._fmsgout, *msg, **opts) + self._writemsg(self._fmsgout, type='note', *msg, **opts) def debug(self, *msg, **opts): '''write debug message to output (if ui.debugflag is True) @@ -1508,8 +1510,7 @@ This adds an output label of "ui.debug". ''' if self.debugflag: - opts[r'label'] = opts.get(r'label', '') + ' ui.debug' - self._write(self._fmsgout, *msg, **opts) + self._writemsg(self._fmsgout, type='debug', *msg, **opts) def edit(self, text, user, extra=None, editform=None, pending=None, repopath=None, action=None): @@ -1978,3 +1979,14 @@ if name == b'stderr': return ui.ferr, ui.ferr raise error.Abort(b'invalid ui.message-output destination: %s' % name) + +def _writemsgwith(write, dest, *args, **opts): + """Write ui message with the given ui._write*() function + + The specified message type is translated to 'ui.' label if the dest + isn't a structured channel, so that the message will be colorized. + """ + # TODO: maybe change 'type' to a mandatory option + if r'type' in opts and not getattr(dest, 'structured', False): + opts[r'label'] = opts.get(r'label', '') + ' ui.%s' % opts.pop(r'type') + write(dest, *args, **opts) diff -r 054d0fcba2c4 -r 83dd8c63a0c6 tests/test-commandserver.t --- a/tests/test-commandserver.t Sun Jan 18 18:49:59 2015 +0900 +++ b/tests/test-commandserver.t Sun Jan 18 17:55:28 2015 +0900 @@ -745,11 +745,11 @@ pid: * (glob) pgid: * (glob) *** runcommand -R repo2 verify - message: '\xa2DdataTchecking changesets\nElabelJ ui.status' - message: '\xa2DdataSchecking manifests\nElabelJ ui.status' - message: '\xa2DdataX0crosschecking files in changesets and manifests\nElabelJ ui.status' - message: '\xa2DdataOchecking files\nElabelJ ui.status' - message: '\xa2DdataX/checked 0 changesets with 0 changes to 0 files\nElabelJ ui.status' + message: '\xa2DdataTchecking changesets\nDtypeFstatus' + message: '\xa2DdataSchecking manifests\nDtypeFstatus' + message: '\xa2DdataX0crosschecking files in changesets and manifests\nDtypeFstatus' + message: '\xa2DdataOchecking files\nDtypeFstatus' + message: '\xa2DdataX/checked 0 changesets with 0 changes to 0 files\nDtypeFstatus' bad message encoding: