[PATCH stable] color/progress: subclass ui instead of using wrapfunction (issue2096)
Steve Borho
steve at borho.org
Wed Jul 7 14:48:27 CDT 2010
On Thu, Jul 1, 2010 at 9:46 PM, Brodie Rao <brodie at bitheap.org> wrote:
> # HG changeset patch
> # User Brodie Rao <brodie at bitheap.org>
> # Date 1278030206 18000
> # Branch stable
> # Node ID 8e1d1b67fb3f61e1932330b182a8af98c4fb59c4
> # Parent 239f3210c970615dc1d5f861a92b61b4662a71a5
> color/progress: subclass ui instead of using wrapfunction (issue2096)
>
> This resolves the issue of hg cmd --mq not being colorized. This was due
> to color wrapping only the instance of ui passed to dispatch._runcommand(),
> which isn't the same ui object that mq.mqcommand() receives. After dispatch
> calls extensions.loadall(), it makes sure any changes to ui.__class__ in
> uisetup are propagated.
>
> progress is updated to wrap ui in the same manner because wrapfunction
> doesn't play well when ui.__class__ has been replaced by another extension
> (orig will point to the old class method instead of color's).
+1 from me. Anyone have any complaints?
> diff --git a/hgext/color.py b/hgext/color.py
> --- a/hgext/color.py
> +++ b/hgext/color.py
> @@ -74,7 +74,7 @@ Any value other than 'ansi', 'win32', or
>
> import os, sys
>
> -from mercurial import commands, dispatch, extensions
> +from mercurial import commands, dispatch, extensions, ui as uimod
> from mercurial.i18n import _
>
> # start and stop parameters for effects
> @@ -140,49 +140,50 @@ def configstyles(ui):
> % (e, status))
> _styles[status] = ' '.join(good)
>
> -_buffers = None
> -def style(msg, label):
> - effects = []
> - for l in label.split():
> - s = _styles.get(l, '')
> - if s:
> - effects.append(s)
> - effects = ''.join(effects)
> - if effects:
> - return '\n'.join([render_effects(s, effects)
> - for s in msg.split('\n')])
> - return msg
> +class colorui(uimod.ui):
> + def popbuffer(self, labeled=False):
> + if labeled:
> + return ''.join(self.label(a, label) for a, label
> + in self._buffers.pop())
> + return ''.join(a for a, label in self._buffers.pop())
>
> -def popbuffer(orig, labeled=False):
> - global _buffers
> - if labeled:
> - return ''.join(style(a, label) for a, label in _buffers.pop())
> - return ''.join(a for a, label in _buffers.pop())
> + _colormode = 'ansi'
> + def write(self, *args, **opts):
> + label = opts.get('label', '')
> + if self._buffers:
> + self._buffers[-1].extend([(str(a), label) for a in args])
> + elif self._colormode == 'win32':
> + for a in args:
> + win32print(a, orig, **opts)
> + else:
> + return super(colorui, self).write(
> + *[self.label(str(a), label) for a in args], **opts)
>
> -mode = 'ansi'
> -def write(orig, *args, **opts):
> - label = opts.get('label', '')
> - global _buffers
> - if _buffers:
> - _buffers[-1].extend([(str(a), label) for a in args])
> - elif mode == 'win32':
> - for a in args:
> - win32print(a, orig, **opts)
> - else:
> - return orig(*[style(str(a), label) for a in args], **opts)
> + def write_err(self, *args, **opts):
> + label = opts.get('label', '')
> + if self._colormode == 'win32':
> + for a in args:
> + win32print(a, orig, **opts)
> + else:
> + return super(colorui, self).write(
> + *[self.label(str(a), label) for a in args], **opts)
>
> -def write_err(orig, *args, **opts):
> - label = opts.get('label', '')
> - if mode == 'win32':
> - for a in args:
> - win32print(a, orig, **opts)
> - else:
> - return orig(*[style(str(a), label) for a in args], **opts)
> + def label(self, msg, label):
> + effects = []
> + for l in label.split():
> + s = _styles.get(l, '')
> + if s:
> + effects.append(s)
> + effects = ''.join(effects)
> + if effects:
> + return '\n'.join([render_effects(s, effects)
> + for s in msg.split('\n')])
> + return msg
> +
>
> def uisetup(ui):
> if ui.plain():
> return
> - global mode
> mode = ui.config('color', 'mode', 'auto')
> if mode == 'auto':
> if os.name == 'nt' and 'TERM' not in os.environ:
> @@ -202,14 +203,11 @@ def uisetup(ui):
> if (opts['color'] == 'always' or
> (opts['color'] == 'auto' and (os.environ.get('TERM') != 'dumb'
> and ui_.formatted()))):
> - global _buffers
> - _buffers = ui_._buffers
> - extensions.wrapfunction(ui_, 'popbuffer', popbuffer)
> - extensions.wrapfunction(ui_, 'write', write)
> - extensions.wrapfunction(ui_, 'write_err', write_err)
> - ui_.label = style
> + colorui._colormode = mode
> + colorui.__bases__ = (ui_.__class__,)
> + ui_.__class__ = colorui
> extstyles()
> - configstyles(ui)
> + configstyles(ui_)
> return orig(ui_, opts, cmd, cmdfunc)
> extensions.wrapfunction(dispatch, '_runcommand', colorcmd)
>
> diff --git a/hgext/progress.py b/hgext/progress.py
> --- a/hgext/progress.py
> +++ b/hgext/progress.py
> @@ -45,7 +45,6 @@ num characters, or ``+<num>`` for the fi
> import sys
> import time
>
> -from mercurial import extensions
> from mercurial import util
>
> def spacejoin(*args):
> @@ -159,7 +158,7 @@ class progbar(object):
> tw = util.termwidth()
> return min(int(self.ui.config('progress', 'width', default=tw)), tw)
>
> - def progress(self, orig, topic, pos, item='', unit='', total=None):
> + def progress(self, topic, pos, item='', unit='', total=None):
> if pos is None:
> if self.topics and self.topics[-1] == topic and self.printed:
> self.complete()
> @@ -172,29 +171,35 @@ class progbar(object):
> and topic == self.topics[-1]):
> self.lastprint = now
> self.show(topic, pos, item, unit, total)
> - return orig(topic, pos, item=item, unit=unit, total=total)
> -
> - def write(self, orig, *args, **opts):
> - if self.printed:
> - self.clear()
> - return orig(*args, **opts)
> -
> -sharedprog = None
>
> def uisetup(ui):
> + class progressui(ui.__class__):
> + _progbar = None
> +
> + def progress(self, *args, **opts):
> + self._progbar.progress(*args, **opts)
> + return super(progressui, self).progress(*args, **opts)
> +
> + def write(self, *args, **opts):
> + if self._progbar.printed:
> + self._progbar.clear()
> + return super(progressui, self).write(*args, **opts)
> +
> + def write_err(self, *args, **opts):
> + if self._progbar.printed:
> + self._progbar.clear()
> + return super(progressui, self).write_err(*args, **opts)
> +
> # Apps that derive a class from ui.ui() can use
> # setconfig('progress', 'disable', 'True') to disable this extension
> if ui.configbool('progress', 'disable'):
> return
> if shouldprint(ui) and not ui.debugflag and not ui.quiet:
> + ui.__class__ = progressui
> # we instantiate one globally shared progress bar to avoid
> # competing progress bars when multiple UI objects get created
> - global sharedprog
> - if not sharedprog:
> - sharedprog = progbar(ui)
> - extensions.wrapfunction(ui, 'progress', sharedprog.progress)
> - extensions.wrapfunction(ui, 'write', sharedprog.write)
> - extensions.wrapfunction(ui, 'write_err', sharedprog.write)
> + if not progressui._progbar:
> + progressui._progbar = progbar(ui)
>
> def reposetup(ui, repo):
> uisetup(repo.ui)
> diff --git a/mercurial/dispatch.py b/mercurial/dispatch.py
> --- a/mercurial/dispatch.py
> +++ b/mercurial/dispatch.py
> @@ -388,6 +388,8 @@ def _dispatch(ui, args):
> # times so we keep track of configured extensions in _loaded.
> extensions.loadall(lui)
> exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
> + # Propagate any changes to lui.__class__ by extensions
> + ui.__class__ = lui.__class__
>
> # (uisetup and extsetup are handled in extensions.loadall)
>
> diff --git a/tests/test-mq b/tests/test-mq
> --- a/tests/test-mq
> +++ b/tests/test-mq
> @@ -80,6 +80,9 @@ echo ' .hgignore:'
> cat .hg/patches/.hgignore
> echo ' series:'
> cat .hg/patches/series
> +
> +echo '% status --mq with color (issue2096)'
> +hg status --mq --config extensions.color= --color=always
> cd ..
>
> echo '% init --mq without repo'
> diff --git a/tests/test-mq.out b/tests/test-mq.out
> --- a/tests/test-mq.out
> +++ b/tests/test-mq.out
> @@ -93,6 +93,11 @@ bleh
> series:
> A
> B
> +% status --mq with color (issue2096)
> + [0;32;1mA .hgignore [0m
> + [0;32;1mA A [0m
> + [0;32;1mA B [0m
> + [0;32;1mA series [0m
> % init --mq without repo
> abort: There is no Mercurial repository here (.hg not found)
> % init --mq with repo path
>
--
Steve Borho
More information about the Mercurial-devel
mailing list