##// END OF EJS Templates
progress: simplify spacejoin()
Brodie Rao -
r10452:59f8fff4 default
parent child Browse files
Show More
@@ -1,186 +1,180 b''
1 # progress.py show progress bars for some actions
1 # progress.py show progress bars for some actions
2 #
2 #
3 # Copyright (C) 2010 Augie Fackler <durin42@gmail.com>
3 # Copyright (C) 2010 Augie Fackler <durin42@gmail.com>
4 #
4 #
5 # This program is free software; you can redistribute it and/or modify it
5 # This program is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by the
6 # under the terms of the GNU General Public License as published by the
7 # Free Software Foundation; either version 2 of the License, or (at your
7 # Free Software Foundation; either version 2 of the License, or (at your
8 # option) any later version.
8 # option) any later version.
9 #
9 #
10 # This program is distributed in the hope that it will be useful, but
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13 # Public License for more details.
13 # Public License for more details.
14 #
14 #
15 # You should have received a copy of the GNU General Public License along
15 # You should have received a copy of the GNU General Public License along
16 # with this program; if not, write to the Free Software Foundation, Inc.,
16 # with this program; if not, write to the Free Software Foundation, Inc.,
17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
18
19 """show progress bars for some actions
19 """show progress bars for some actions
20
20
21 This extension uses the progress information logged by hg commands
21 This extension uses the progress information logged by hg commands
22 to draw progress bars that are as informative as possible. Some progress
22 to draw progress bars that are as informative as possible. Some progress
23 bars only offer indeterminate information, while others have a definite
23 bars only offer indeterminate information, while others have a definite
24 end point.
24 end point.
25
25
26 The following settings are available::
26 The following settings are available::
27
27
28 [progress]
28 [progress]
29 delay = 3 # number of seconds (float) before showing the progress bar
29 delay = 3 # number of seconds (float) before showing the progress bar
30 refresh = 0.1 # time in seconds between refreshes of the progress bar
30 refresh = 0.1 # time in seconds between refreshes of the progress bar
31 format = topic bar number # format of the progress bar
31 format = topic bar number # format of the progress bar
32 width = <none> # if set, the maximum width of the progress information
32 width = <none> # if set, the maximum width of the progress information
33 # (that is, min(width, term width) will be used)
33 # (that is, min(width, term width) will be used)
34 clear-complete = True # clear the progress bar after it's done
34 clear-complete = True # clear the progress bar after it's done
35
35
36 Valid entries for the format field are topic, bar, number, unit, and item.
36 Valid entries for the format field are topic, bar, number, unit, and item.
37 item defaults to the last 20 characters of the item, but this can be
37 item defaults to the last 20 characters of the item, but this can be
38 changed by adding either -<num> which would take the last num characters,
38 changed by adding either -<num> which would take the last num characters,
39 or +<num> for the first num characters.
39 or +<num> for the first num characters.
40 """
40 """
41
41
42 import math
42 import math
43 import sys
43 import sys
44 import time
44 import time
45
45
46 from mercurial import extensions
46 from mercurial import extensions
47 from mercurial import util
47 from mercurial import util
48
48
49 def spacejoin(*args):
49 def spacejoin(*args):
50 ret = ''
50 return ' '.join(s for s in args if s)
51 for s in args:
52 if s:
53 if ret:
54 ret += ' '
55 ret += s
56 return ret
57
51
58 class progbar(object):
52 class progbar(object):
59 def __init__(self, ui):
53 def __init__(self, ui):
60 self.ui = ui
54 self.ui = ui
61 self.resetstate()
55 self.resetstate()
62
56
63 def resetstate(self):
57 def resetstate(self):
64 self.topics = []
58 self.topics = []
65 self.printed = False
59 self.printed = False
66 self.lastprint = time.time() + float(self.ui.config(
60 self.lastprint = time.time() + float(self.ui.config(
67 'progress', 'delay', default=3))
61 'progress', 'delay', default=3))
68 self.indetcount = 0
62 self.indetcount = 0
69 self.refresh = float(self.ui.config(
63 self.refresh = float(self.ui.config(
70 'progress', 'refresh', default=0.1))
64 'progress', 'refresh', default=0.1))
71 self.order = self.ui.configlist(
65 self.order = self.ui.configlist(
72 'progress', 'format',
66 'progress', 'format',
73 default=['topic', 'bar', 'number'])
67 default=['topic', 'bar', 'number'])
74
68
75 def show(self, topic, pos, item, unit, total):
69 def show(self, topic, pos, item, unit, total):
76 termwidth = self.width()
70 termwidth = self.width()
77 self.printed = True
71 self.printed = True
78 head = ''
72 head = ''
79 needprogress = False
73 needprogress = False
80 tail = ''
74 tail = ''
81 for indicator in self.order:
75 for indicator in self.order:
82 add = ''
76 add = ''
83 if indicator == 'topic':
77 if indicator == 'topic':
84 add = topic
78 add = topic
85 elif indicator == 'number':
79 elif indicator == 'number':
86 if total:
80 if total:
87 add = ('% ' + str(len(str(total))) +
81 add = ('% ' + str(len(str(total))) +
88 's/%s') % (pos, total)
82 's/%s') % (pos, total)
89 else:
83 else:
90 add = str(pos)
84 add = str(pos)
91 elif indicator.startswith('item') and item:
85 elif indicator.startswith('item') and item:
92 slice = 'end'
86 slice = 'end'
93 if '-' in indicator:
87 if '-' in indicator:
94 wid = int(indicator.split('-')[1])
88 wid = int(indicator.split('-')[1])
95 elif '+' in indicator:
89 elif '+' in indicator:
96 slice = 'beginning'
90 slice = 'beginning'
97 wid = int(indicator.split('+')[1])
91 wid = int(indicator.split('+')[1])
98 else:
92 else:
99 wid = 20
93 wid = 20
100 if slice == 'end':
94 if slice == 'end':
101 add = item[-wid:]
95 add = item[-wid:]
102 else:
96 else:
103 add = item[:wid]
97 add = item[:wid]
104 add += (wid - len(add)) * ' '
98 add += (wid - len(add)) * ' '
105 elif indicator == 'bar':
99 elif indicator == 'bar':
106 add = ''
100 add = ''
107 needprogress = True
101 needprogress = True
108 elif indicator == 'unit' and unit:
102 elif indicator == 'unit' and unit:
109 add = unit
103 add = unit
110 if not needprogress:
104 if not needprogress:
111 head = spacejoin(head, add)
105 head = spacejoin(head, add)
112 else:
106 else:
113 tail = spacejoin(add, tail)
107 tail = spacejoin(add, tail)
114 if needprogress:
108 if needprogress:
115 used = 0
109 used = 0
116 if head:
110 if head:
117 used += len(head) + 1
111 used += len(head) + 1
118 if tail:
112 if tail:
119 used += len(tail) + 1
113 used += len(tail) + 1
120 progwidth = termwidth - used - 3
114 progwidth = termwidth - used - 3
121 if total:
115 if total:
122 amt = pos * progwidth // total
116 amt = pos * progwidth // total
123 bar = '=' * (amt) + ' ' * (progwidth - amt)
117 bar = '=' * (amt) + ' ' * (progwidth - amt)
124 else:
118 else:
125 progwidth -= 3
119 progwidth -= 3
126 self.indetcount += 1
120 self.indetcount += 1
127 # mod the count by twice the width so we can make the
121 # mod the count by twice the width so we can make the
128 # cursor bounce between the right and left sides
122 # cursor bounce between the right and left sides
129 amt = self.indetcount % (2 * progwidth)
123 amt = self.indetcount % (2 * progwidth)
130 amt -= progwidth
124 amt -= progwidth
131 bar = (' ' * int(progwidth - abs(amt)) + '<=>' +
125 bar = (' ' * int(progwidth - abs(amt)) + '<=>' +
132 ' ' * int(abs(amt)))
126 ' ' * int(abs(amt)))
133 prog = ''.join(('[', bar , ']'))
127 prog = ''.join(('[', bar , ']'))
134 out = spacejoin(head, prog, tail)
128 out = spacejoin(head, prog, tail)
135 else:
129 else:
136 out = spacejoin(head, tail)
130 out = spacejoin(head, tail)
137 sys.stdout.write('\r' + out[:termwidth])
131 sys.stdout.write('\r' + out[:termwidth])
138 sys.stdout.flush()
132 sys.stdout.flush()
139
133
140 def clear(self):
134 def clear(self):
141 sys.stdout.write('\r%s\r' % (' ' * self.width()))
135 sys.stdout.write('\r%s\r' % (' ' * self.width()))
142
136
143 def complete(self):
137 def complete(self):
144 if self.ui.configbool('progress', 'clear-complete', default=True):
138 if self.ui.configbool('progress', 'clear-complete', default=True):
145 self.clear()
139 self.clear()
146 else:
140 else:
147 sys.stdout.write('\n')
141 sys.stdout.write('\n')
148 sys.stdout.flush()
142 sys.stdout.flush()
149
143
150 def width(self):
144 def width(self):
151 tw = util.termwidth()
145 tw = util.termwidth()
152 return min(int(self.ui.config('progress', 'width', default=tw)), tw)
146 return min(int(self.ui.config('progress', 'width', default=tw)), tw)
153
147
154 def progress(self, orig, topic, pos, item='', unit='', total=None):
148 def progress(self, orig, topic, pos, item='', unit='', total=None):
155 if pos is None:
149 if pos is None:
156 if self.topics and self.topics[-1] == topic and self.printed:
150 if self.topics and self.topics[-1] == topic and self.printed:
157 self.complete()
151 self.complete()
158 self.resetstate()
152 self.resetstate()
159 else:
153 else:
160 if topic not in self.topics:
154 if topic not in self.topics:
161 self.topics.append(topic)
155 self.topics.append(topic)
162 now = time.time()
156 now = time.time()
163 if now - self.lastprint > 0.1 and topic == self.topics[-1]:
157 if now - self.lastprint > 0.1 and topic == self.topics[-1]:
164 self.lastprint = now
158 self.lastprint = now
165 self.show(topic, pos, item, unit, total)
159 self.show(topic, pos, item, unit, total)
166 return orig(topic, pos, item=item, unit=unit, total=total)
160 return orig(topic, pos, item=item, unit=unit, total=total)
167
161
168 def write(self, orig, *args):
162 def write(self, orig, *args):
169 if self.printed:
163 if self.printed:
170 self.clear()
164 self.clear()
171 return orig(*args)
165 return orig(*args)
172
166
173 sharedprog = None
167 sharedprog = None
174
168
175 def uisetup(ui):
169 def uisetup(ui):
176 if ui.interactive() and not ui.debugflag:
170 if ui.interactive() and not ui.debugflag:
177 # we instantiate one globally shared progress bar to avoid
171 # we instantiate one globally shared progress bar to avoid
178 # competing progress bars when multiple UI objects get created
172 # competing progress bars when multiple UI objects get created
179 global sharedprog
173 global sharedprog
180 if not sharedprog:
174 if not sharedprog:
181 sharedprog = progbar(ui)
175 sharedprog = progbar(ui)
182 extensions.wrapfunction(ui, 'progress', sharedprog.progress)
176 extensions.wrapfunction(ui, 'progress', sharedprog.progress)
183 extensions.wrapfunction(ui, 'write', sharedprog.write)
177 extensions.wrapfunction(ui, 'write', sharedprog.write)
184
178
185 def reposetup(ui, repo):
179 def reposetup(ui, repo):
186 uisetup(repo.ui)
180 uisetup(repo.ui)
General Comments 0
You need to be logged in to leave comments. Login now