Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/ui.py @ 27106:6ef17697b03d
ui: track label expansion when creating buffers
As part of profiling `hg log` performance, I noticed a lot of time
is spent in buffered writes to ui instances. This patch starts a series
that refactors buffered writes with the eventual intent to improve
performance.
Currently, labels are expanded when buffers are popped. This means
we have to preserve the original text and the label until we render
the final output. This is avoidable overhead and adds complexity
since we're retaining state.
This patch adds functionality to ui.pushbuffer() to declare whether
label expansion should be active for the buffer. Labels are still
evaluated during buffer pop. This will change in a subsequent
patch.
Since we'll need to access the "expand labels" flag on future write()
operations, we prematurely optimize how the current value is stored
to optimize for rapid retrieval.
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Sun, 22 Nov 2015 14:10:48 -0800 |
parents | 9eeca021a803 |
children | a93d53f79e6e |
comparison
equal
deleted
inserted
replaced
27101:61fbf5dc12b2 | 27106:6ef17697b03d |
---|---|
92 | 92 |
93 class ui(object): | 93 class ui(object): |
94 def __init__(self, src=None): | 94 def __init__(self, src=None): |
95 # _buffers: used for temporary capture of output | 95 # _buffers: used for temporary capture of output |
96 self._buffers = [] | 96 self._buffers = [] |
97 # _bufferstates: | 97 # 3-tuple describing how each buffer in the stack behaves. |
98 # should the temporary capture include stderr and subprocess output | 98 # Values are (capture stderr, capture subprocesses, apply labels). |
99 self._bufferstates = [] | 99 self._bufferstates = [] |
100 # When a buffer is active, defines whether we are expanding labels. | |
101 # This exists to prevent an extra list lookup. | |
102 self._bufferapplylabels = None | |
100 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False | 103 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False |
101 self._reportuntrusted = True | 104 self._reportuntrusted = True |
102 self._ocfg = config.config() # overlay | 105 self._ocfg = config.config() # overlay |
103 self._tcfg = config.config() # trusted | 106 self._tcfg = config.config() # trusted |
104 self._ucfg = config.config() # untrusted | 107 self._ucfg = config.config() # untrusted |
570 | 573 |
571 @util.propertycache | 574 @util.propertycache |
572 def paths(self): | 575 def paths(self): |
573 return paths(self) | 576 return paths(self) |
574 | 577 |
575 def pushbuffer(self, error=False, subproc=False): | 578 def pushbuffer(self, error=False, subproc=False, labeled=False): |
576 """install a buffer to capture standard output of the ui object | 579 """install a buffer to capture standard output of the ui object |
577 | 580 |
578 If error is True, the error output will be captured too. | 581 If error is True, the error output will be captured too. |
579 | 582 |
580 If subproc is True, output from subprocesses (typically hooks) will be | 583 If subproc is True, output from subprocesses (typically hooks) will be |
581 captured too.""" | 584 captured too. |
582 self._buffers.append([]) | |
583 self._bufferstates.append((error, subproc)) | |
584 | |
585 def popbuffer(self, labeled=False): | |
586 '''pop the last buffer and return the buffered output | |
587 | 585 |
588 If labeled is True, any labels associated with buffered | 586 If labeled is True, any labels associated with buffered |
589 output will be handled. By default, this has no effect | 587 output will be handled. By default, this has no effect |
590 on the output returned, but extensions and GUI tools may | 588 on the output returned, but extensions and GUI tools may |
591 handle this argument and returned styled output. If output | 589 handle this argument and returned styled output. If output |
592 is being buffered so it can be captured and parsed or | 590 is being buffered so it can be captured and parsed or |
593 processed, labeled should not be set to True. | 591 processed, labeled should not be set to True. |
592 """ | |
593 self._buffers.append([]) | |
594 self._bufferstates.append((error, subproc, labeled)) | |
595 self._bufferapplylabels = labeled | |
596 | |
597 def popbuffer(self, labeled=False): | |
598 '''pop the last buffer and return the buffered output | |
599 | |
600 If labeled is True, any labels associated with buffered | |
601 output will be handled. By default, this has no effect | |
602 on the output returned, but extensions and GUI tools may | |
603 handle this argument and returned styled output. If output | |
604 is being buffered so it can be captured and parsed or | |
605 processed, labeled should not be set to True. | |
594 ''' | 606 ''' |
595 self._bufferstates.pop() | 607 self._bufferstates.pop() |
608 if self._bufferstates: | |
609 self._bufferapplylabels = self._bufferstates[-1][2] | |
610 else: | |
611 self._bufferapplylabels = None | |
612 | |
596 return "".join(self._buffers.pop()) | 613 return "".join(self._buffers.pop()) |
597 | 614 |
598 def write(self, *args, **opts): | 615 def write(self, *args, **opts): |
599 '''write args to output | 616 '''write args to output |
600 | 617 |