##// END OF EJS Templates
templater: avoid recursive evaluation of string literals completely...
FUJIWARA Katsunori -
r20661:7e627fe6 stable
parent child Browse files
Show More
@@ -1,557 +1,555 b''
1 # color.py color output for the status and qseries commands
1 # color.py color output for the status and qseries commands
2 #
2 #
3 # Copyright (C) 2007 Kevin Christen <kevin.christen@gmail.com>
3 # Copyright (C) 2007 Kevin Christen <kevin.christen@gmail.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 '''colorize output from some commands
8 '''colorize output from some commands
9
9
10 This extension modifies the status and resolve commands to add color
10 This extension modifies the status and resolve commands to add color
11 to their output to reflect file status, the qseries command to add
11 to their output to reflect file status, the qseries command to add
12 color to reflect patch status (applied, unapplied, missing), and to
12 color to reflect patch status (applied, unapplied, missing), and to
13 diff-related commands to highlight additions, removals, diff headers,
13 diff-related commands to highlight additions, removals, diff headers,
14 and trailing whitespace.
14 and trailing whitespace.
15
15
16 Other effects in addition to color, like bold and underlined text, are
16 Other effects in addition to color, like bold and underlined text, are
17 also available. By default, the terminfo database is used to find the
17 also available. By default, the terminfo database is used to find the
18 terminal codes used to change color and effect. If terminfo is not
18 terminal codes used to change color and effect. If terminfo is not
19 available, then effects are rendered with the ECMA-48 SGR control
19 available, then effects are rendered with the ECMA-48 SGR control
20 function (aka ANSI escape codes).
20 function (aka ANSI escape codes).
21
21
22 Default effects may be overridden from your configuration file::
22 Default effects may be overridden from your configuration file::
23
23
24 [color]
24 [color]
25 status.modified = blue bold underline red_background
25 status.modified = blue bold underline red_background
26 status.added = green bold
26 status.added = green bold
27 status.removed = red bold blue_background
27 status.removed = red bold blue_background
28 status.deleted = cyan bold underline
28 status.deleted = cyan bold underline
29 status.unknown = magenta bold underline
29 status.unknown = magenta bold underline
30 status.ignored = black bold
30 status.ignored = black bold
31
31
32 # 'none' turns off all effects
32 # 'none' turns off all effects
33 status.clean = none
33 status.clean = none
34 status.copied = none
34 status.copied = none
35
35
36 qseries.applied = blue bold underline
36 qseries.applied = blue bold underline
37 qseries.unapplied = black bold
37 qseries.unapplied = black bold
38 qseries.missing = red bold
38 qseries.missing = red bold
39
39
40 diff.diffline = bold
40 diff.diffline = bold
41 diff.extended = cyan bold
41 diff.extended = cyan bold
42 diff.file_a = red bold
42 diff.file_a = red bold
43 diff.file_b = green bold
43 diff.file_b = green bold
44 diff.hunk = magenta
44 diff.hunk = magenta
45 diff.deleted = red
45 diff.deleted = red
46 diff.inserted = green
46 diff.inserted = green
47 diff.changed = white
47 diff.changed = white
48 diff.trailingwhitespace = bold red_background
48 diff.trailingwhitespace = bold red_background
49
49
50 resolve.unresolved = red bold
50 resolve.unresolved = red bold
51 resolve.resolved = green bold
51 resolve.resolved = green bold
52
52
53 bookmarks.current = green
53 bookmarks.current = green
54
54
55 branches.active = none
55 branches.active = none
56 branches.closed = black bold
56 branches.closed = black bold
57 branches.current = green
57 branches.current = green
58 branches.inactive = none
58 branches.inactive = none
59
59
60 tags.normal = green
60 tags.normal = green
61 tags.local = black bold
61 tags.local = black bold
62
62
63 rebase.rebased = blue
63 rebase.rebased = blue
64 rebase.remaining = red bold
64 rebase.remaining = red bold
65
65
66 shelve.age = cyan
66 shelve.age = cyan
67 shelve.newest = green bold
67 shelve.newest = green bold
68 shelve.name = blue bold
68 shelve.name = blue bold
69
69
70 histedit.remaining = red bold
70 histedit.remaining = red bold
71
71
72 The available effects in terminfo mode are 'blink', 'bold', 'dim',
72 The available effects in terminfo mode are 'blink', 'bold', 'dim',
73 'inverse', 'invisible', 'italic', 'standout', and 'underline'; in
73 'inverse', 'invisible', 'italic', 'standout', and 'underline'; in
74 ECMA-48 mode, the options are 'bold', 'inverse', 'italic', and
74 ECMA-48 mode, the options are 'bold', 'inverse', 'italic', and
75 'underline'. How each is rendered depends on the terminal emulator.
75 'underline'. How each is rendered depends on the terminal emulator.
76 Some may not be available for a given terminal type, and will be
76 Some may not be available for a given terminal type, and will be
77 silently ignored.
77 silently ignored.
78
78
79 Note that on some systems, terminfo mode may cause problems when using
79 Note that on some systems, terminfo mode may cause problems when using
80 color with the pager extension and less -R. less with the -R option
80 color with the pager extension and less -R. less with the -R option
81 will only display ECMA-48 color codes, and terminfo mode may sometimes
81 will only display ECMA-48 color codes, and terminfo mode may sometimes
82 emit codes that less doesn't understand. You can work around this by
82 emit codes that less doesn't understand. You can work around this by
83 either using ansi mode (or auto mode), or by using less -r (which will
83 either using ansi mode (or auto mode), or by using less -r (which will
84 pass through all terminal control codes, not just color control
84 pass through all terminal control codes, not just color control
85 codes).
85 codes).
86
86
87 Because there are only eight standard colors, this module allows you
87 Because there are only eight standard colors, this module allows you
88 to define color names for other color slots which might be available
88 to define color names for other color slots which might be available
89 for your terminal type, assuming terminfo mode. For instance::
89 for your terminal type, assuming terminfo mode. For instance::
90
90
91 color.brightblue = 12
91 color.brightblue = 12
92 color.pink = 207
92 color.pink = 207
93 color.orange = 202
93 color.orange = 202
94
94
95 to set 'brightblue' to color slot 12 (useful for 16 color terminals
95 to set 'brightblue' to color slot 12 (useful for 16 color terminals
96 that have brighter colors defined in the upper eight) and, 'pink' and
96 that have brighter colors defined in the upper eight) and, 'pink' and
97 'orange' to colors in 256-color xterm's default color cube. These
97 'orange' to colors in 256-color xterm's default color cube. These
98 defined colors may then be used as any of the pre-defined eight,
98 defined colors may then be used as any of the pre-defined eight,
99 including appending '_background' to set the background to that color.
99 including appending '_background' to set the background to that color.
100
100
101 By default, the color extension will use ANSI mode (or win32 mode on
101 By default, the color extension will use ANSI mode (or win32 mode on
102 Windows) if it detects a terminal. To override auto mode (to enable
102 Windows) if it detects a terminal. To override auto mode (to enable
103 terminfo mode, for example), set the following configuration option::
103 terminfo mode, for example), set the following configuration option::
104
104
105 [color]
105 [color]
106 mode = terminfo
106 mode = terminfo
107
107
108 Any value other than 'ansi', 'win32', 'terminfo', or 'auto' will
108 Any value other than 'ansi', 'win32', 'terminfo', or 'auto' will
109 disable color.
109 disable color.
110 '''
110 '''
111
111
112 import os
112 import os
113
113
114 from mercurial import commands, dispatch, extensions, ui as uimod, util
114 from mercurial import commands, dispatch, extensions, ui as uimod, util
115 from mercurial import templater, error
115 from mercurial import templater, error
116 from mercurial.i18n import _
116 from mercurial.i18n import _
117
117
118 testedwith = 'internal'
118 testedwith = 'internal'
119
119
120 # start and stop parameters for effects
120 # start and stop parameters for effects
121 _effects = {'none': 0, 'black': 30, 'red': 31, 'green': 32, 'yellow': 33,
121 _effects = {'none': 0, 'black': 30, 'red': 31, 'green': 32, 'yellow': 33,
122 'blue': 34, 'magenta': 35, 'cyan': 36, 'white': 37, 'bold': 1,
122 'blue': 34, 'magenta': 35, 'cyan': 36, 'white': 37, 'bold': 1,
123 'italic': 3, 'underline': 4, 'inverse': 7,
123 'italic': 3, 'underline': 4, 'inverse': 7,
124 'black_background': 40, 'red_background': 41,
124 'black_background': 40, 'red_background': 41,
125 'green_background': 42, 'yellow_background': 43,
125 'green_background': 42, 'yellow_background': 43,
126 'blue_background': 44, 'purple_background': 45,
126 'blue_background': 44, 'purple_background': 45,
127 'cyan_background': 46, 'white_background': 47}
127 'cyan_background': 46, 'white_background': 47}
128
128
129 def _terminfosetup(ui, mode):
129 def _terminfosetup(ui, mode):
130 '''Initialize terminfo data and the terminal if we're in terminfo mode.'''
130 '''Initialize terminfo data and the terminal if we're in terminfo mode.'''
131
131
132 global _terminfo_params
132 global _terminfo_params
133 # If we failed to load curses, we go ahead and return.
133 # If we failed to load curses, we go ahead and return.
134 if not _terminfo_params:
134 if not _terminfo_params:
135 return
135 return
136 # Otherwise, see what the config file says.
136 # Otherwise, see what the config file says.
137 if mode not in ('auto', 'terminfo'):
137 if mode not in ('auto', 'terminfo'):
138 return
138 return
139
139
140 _terminfo_params.update((key[6:], (False, int(val)))
140 _terminfo_params.update((key[6:], (False, int(val)))
141 for key, val in ui.configitems('color')
141 for key, val in ui.configitems('color')
142 if key.startswith('color.'))
142 if key.startswith('color.'))
143
143
144 try:
144 try:
145 curses.setupterm()
145 curses.setupterm()
146 except curses.error, e:
146 except curses.error, e:
147 _terminfo_params = {}
147 _terminfo_params = {}
148 return
148 return
149
149
150 for key, (b, e) in _terminfo_params.items():
150 for key, (b, e) in _terminfo_params.items():
151 if not b:
151 if not b:
152 continue
152 continue
153 if not curses.tigetstr(e):
153 if not curses.tigetstr(e):
154 # Most terminals don't support dim, invis, etc, so don't be
154 # Most terminals don't support dim, invis, etc, so don't be
155 # noisy and use ui.debug().
155 # noisy and use ui.debug().
156 ui.debug("no terminfo entry for %s\n" % e)
156 ui.debug("no terminfo entry for %s\n" % e)
157 del _terminfo_params[key]
157 del _terminfo_params[key]
158 if not curses.tigetstr('setaf') or not curses.tigetstr('setab'):
158 if not curses.tigetstr('setaf') or not curses.tigetstr('setab'):
159 # Only warn about missing terminfo entries if we explicitly asked for
159 # Only warn about missing terminfo entries if we explicitly asked for
160 # terminfo mode.
160 # terminfo mode.
161 if mode == "terminfo":
161 if mode == "terminfo":
162 ui.warn(_("no terminfo entry for setab/setaf: reverting to "
162 ui.warn(_("no terminfo entry for setab/setaf: reverting to "
163 "ECMA-48 color\n"))
163 "ECMA-48 color\n"))
164 _terminfo_params = {}
164 _terminfo_params = {}
165
165
166 def _modesetup(ui, coloropt):
166 def _modesetup(ui, coloropt):
167 global _terminfo_params
167 global _terminfo_params
168
168
169 auto = coloropt == 'auto'
169 auto = coloropt == 'auto'
170 always = not auto and util.parsebool(coloropt)
170 always = not auto and util.parsebool(coloropt)
171 if not always and not auto:
171 if not always and not auto:
172 return None
172 return None
173
173
174 formatted = always or (os.environ.get('TERM') != 'dumb' and ui.formatted())
174 formatted = always or (os.environ.get('TERM') != 'dumb' and ui.formatted())
175
175
176 mode = ui.config('color', 'mode', 'auto')
176 mode = ui.config('color', 'mode', 'auto')
177 realmode = mode
177 realmode = mode
178 if mode == 'auto':
178 if mode == 'auto':
179 if os.name == 'nt' and 'TERM' not in os.environ:
179 if os.name == 'nt' and 'TERM' not in os.environ:
180 # looks line a cmd.exe console, use win32 API or nothing
180 # looks line a cmd.exe console, use win32 API or nothing
181 realmode = 'win32'
181 realmode = 'win32'
182 else:
182 else:
183 realmode = 'ansi'
183 realmode = 'ansi'
184
184
185 if realmode == 'win32':
185 if realmode == 'win32':
186 _terminfo_params = {}
186 _terminfo_params = {}
187 if not w32effects:
187 if not w32effects:
188 if mode == 'win32':
188 if mode == 'win32':
189 # only warn if color.mode is explicitly set to win32
189 # only warn if color.mode is explicitly set to win32
190 ui.warn(_('warning: failed to set color mode to %s\n') % mode)
190 ui.warn(_('warning: failed to set color mode to %s\n') % mode)
191 return None
191 return None
192 _effects.update(w32effects)
192 _effects.update(w32effects)
193 elif realmode == 'ansi':
193 elif realmode == 'ansi':
194 _terminfo_params = {}
194 _terminfo_params = {}
195 elif realmode == 'terminfo':
195 elif realmode == 'terminfo':
196 _terminfosetup(ui, mode)
196 _terminfosetup(ui, mode)
197 if not _terminfo_params:
197 if not _terminfo_params:
198 if mode == 'terminfo':
198 if mode == 'terminfo':
199 ## FIXME Shouldn't we return None in this case too?
199 ## FIXME Shouldn't we return None in this case too?
200 # only warn if color.mode is explicitly set to win32
200 # only warn if color.mode is explicitly set to win32
201 ui.warn(_('warning: failed to set color mode to %s\n') % mode)
201 ui.warn(_('warning: failed to set color mode to %s\n') % mode)
202 realmode = 'ansi'
202 realmode = 'ansi'
203 else:
203 else:
204 return None
204 return None
205
205
206 if always or (auto and formatted):
206 if always or (auto and formatted):
207 return realmode
207 return realmode
208 return None
208 return None
209
209
210 try:
210 try:
211 import curses
211 import curses
212 # Mapping from effect name to terminfo attribute name or color number.
212 # Mapping from effect name to terminfo attribute name or color number.
213 # This will also force-load the curses module.
213 # This will also force-load the curses module.
214 _terminfo_params = {'none': (True, 'sgr0'),
214 _terminfo_params = {'none': (True, 'sgr0'),
215 'standout': (True, 'smso'),
215 'standout': (True, 'smso'),
216 'underline': (True, 'smul'),
216 'underline': (True, 'smul'),
217 'reverse': (True, 'rev'),
217 'reverse': (True, 'rev'),
218 'inverse': (True, 'rev'),
218 'inverse': (True, 'rev'),
219 'blink': (True, 'blink'),
219 'blink': (True, 'blink'),
220 'dim': (True, 'dim'),
220 'dim': (True, 'dim'),
221 'bold': (True, 'bold'),
221 'bold': (True, 'bold'),
222 'invisible': (True, 'invis'),
222 'invisible': (True, 'invis'),
223 'italic': (True, 'sitm'),
223 'italic': (True, 'sitm'),
224 'black': (False, curses.COLOR_BLACK),
224 'black': (False, curses.COLOR_BLACK),
225 'red': (False, curses.COLOR_RED),
225 'red': (False, curses.COLOR_RED),
226 'green': (False, curses.COLOR_GREEN),
226 'green': (False, curses.COLOR_GREEN),
227 'yellow': (False, curses.COLOR_YELLOW),
227 'yellow': (False, curses.COLOR_YELLOW),
228 'blue': (False, curses.COLOR_BLUE),
228 'blue': (False, curses.COLOR_BLUE),
229 'magenta': (False, curses.COLOR_MAGENTA),
229 'magenta': (False, curses.COLOR_MAGENTA),
230 'cyan': (False, curses.COLOR_CYAN),
230 'cyan': (False, curses.COLOR_CYAN),
231 'white': (False, curses.COLOR_WHITE)}
231 'white': (False, curses.COLOR_WHITE)}
232 except ImportError:
232 except ImportError:
233 _terminfo_params = False
233 _terminfo_params = False
234
234
235 _styles = {'grep.match': 'red bold',
235 _styles = {'grep.match': 'red bold',
236 'grep.linenumber': 'green',
236 'grep.linenumber': 'green',
237 'grep.rev': 'green',
237 'grep.rev': 'green',
238 'grep.change': 'green',
238 'grep.change': 'green',
239 'grep.sep': 'cyan',
239 'grep.sep': 'cyan',
240 'grep.filename': 'magenta',
240 'grep.filename': 'magenta',
241 'grep.user': 'magenta',
241 'grep.user': 'magenta',
242 'grep.date': 'magenta',
242 'grep.date': 'magenta',
243 'bookmarks.current': 'green',
243 'bookmarks.current': 'green',
244 'branches.active': 'none',
244 'branches.active': 'none',
245 'branches.closed': 'black bold',
245 'branches.closed': 'black bold',
246 'branches.current': 'green',
246 'branches.current': 'green',
247 'branches.inactive': 'none',
247 'branches.inactive': 'none',
248 'diff.changed': 'white',
248 'diff.changed': 'white',
249 'diff.deleted': 'red',
249 'diff.deleted': 'red',
250 'diff.diffline': 'bold',
250 'diff.diffline': 'bold',
251 'diff.extended': 'cyan bold',
251 'diff.extended': 'cyan bold',
252 'diff.file_a': 'red bold',
252 'diff.file_a': 'red bold',
253 'diff.file_b': 'green bold',
253 'diff.file_b': 'green bold',
254 'diff.hunk': 'magenta',
254 'diff.hunk': 'magenta',
255 'diff.inserted': 'green',
255 'diff.inserted': 'green',
256 'diff.trailingwhitespace': 'bold red_background',
256 'diff.trailingwhitespace': 'bold red_background',
257 'diffstat.deleted': 'red',
257 'diffstat.deleted': 'red',
258 'diffstat.inserted': 'green',
258 'diffstat.inserted': 'green',
259 'histedit.remaining': 'red bold',
259 'histedit.remaining': 'red bold',
260 'ui.prompt': 'yellow',
260 'ui.prompt': 'yellow',
261 'log.changeset': 'yellow',
261 'log.changeset': 'yellow',
262 'rebase.rebased': 'blue',
262 'rebase.rebased': 'blue',
263 'rebase.remaining': 'red bold',
263 'rebase.remaining': 'red bold',
264 'resolve.resolved': 'green bold',
264 'resolve.resolved': 'green bold',
265 'resolve.unresolved': 'red bold',
265 'resolve.unresolved': 'red bold',
266 'shelve.age': 'cyan',
266 'shelve.age': 'cyan',
267 'shelve.newest': 'green bold',
267 'shelve.newest': 'green bold',
268 'shelve.name': 'blue bold',
268 'shelve.name': 'blue bold',
269 'status.added': 'green bold',
269 'status.added': 'green bold',
270 'status.clean': 'none',
270 'status.clean': 'none',
271 'status.copied': 'none',
271 'status.copied': 'none',
272 'status.deleted': 'cyan bold underline',
272 'status.deleted': 'cyan bold underline',
273 'status.ignored': 'black bold',
273 'status.ignored': 'black bold',
274 'status.modified': 'blue bold',
274 'status.modified': 'blue bold',
275 'status.removed': 'red bold',
275 'status.removed': 'red bold',
276 'status.unknown': 'magenta bold underline',
276 'status.unknown': 'magenta bold underline',
277 'tags.normal': 'green',
277 'tags.normal': 'green',
278 'tags.local': 'black bold'}
278 'tags.local': 'black bold'}
279
279
280
280
281 def _effect_str(effect):
281 def _effect_str(effect):
282 '''Helper function for render_effects().'''
282 '''Helper function for render_effects().'''
283
283
284 bg = False
284 bg = False
285 if effect.endswith('_background'):
285 if effect.endswith('_background'):
286 bg = True
286 bg = True
287 effect = effect[:-11]
287 effect = effect[:-11]
288 attr, val = _terminfo_params[effect]
288 attr, val = _terminfo_params[effect]
289 if attr:
289 if attr:
290 return curses.tigetstr(val)
290 return curses.tigetstr(val)
291 elif bg:
291 elif bg:
292 return curses.tparm(curses.tigetstr('setab'), val)
292 return curses.tparm(curses.tigetstr('setab'), val)
293 else:
293 else:
294 return curses.tparm(curses.tigetstr('setaf'), val)
294 return curses.tparm(curses.tigetstr('setaf'), val)
295
295
296 def render_effects(text, effects):
296 def render_effects(text, effects):
297 'Wrap text in commands to turn on each effect.'
297 'Wrap text in commands to turn on each effect.'
298 if not text:
298 if not text:
299 return text
299 return text
300 if not _terminfo_params:
300 if not _terminfo_params:
301 start = [str(_effects[e]) for e in ['none'] + effects.split()]
301 start = [str(_effects[e]) for e in ['none'] + effects.split()]
302 start = '\033[' + ';'.join(start) + 'm'
302 start = '\033[' + ';'.join(start) + 'm'
303 stop = '\033[' + str(_effects['none']) + 'm'
303 stop = '\033[' + str(_effects['none']) + 'm'
304 else:
304 else:
305 start = ''.join(_effect_str(effect)
305 start = ''.join(_effect_str(effect)
306 for effect in ['none'] + effects.split())
306 for effect in ['none'] + effects.split())
307 stop = _effect_str('none')
307 stop = _effect_str('none')
308 return ''.join([start, text, stop])
308 return ''.join([start, text, stop])
309
309
310 def extstyles():
310 def extstyles():
311 for name, ext in extensions.extensions():
311 for name, ext in extensions.extensions():
312 _styles.update(getattr(ext, 'colortable', {}))
312 _styles.update(getattr(ext, 'colortable', {}))
313
313
314 def configstyles(ui):
314 def configstyles(ui):
315 for status, cfgeffects in ui.configitems('color'):
315 for status, cfgeffects in ui.configitems('color'):
316 if '.' not in status or status.startswith('color.'):
316 if '.' not in status or status.startswith('color.'):
317 continue
317 continue
318 cfgeffects = ui.configlist('color', status)
318 cfgeffects = ui.configlist('color', status)
319 if cfgeffects:
319 if cfgeffects:
320 good = []
320 good = []
321 for e in cfgeffects:
321 for e in cfgeffects:
322 if not _terminfo_params and e in _effects:
322 if not _terminfo_params and e in _effects:
323 good.append(e)
323 good.append(e)
324 elif e in _terminfo_params or e[:-11] in _terminfo_params:
324 elif e in _terminfo_params or e[:-11] in _terminfo_params:
325 good.append(e)
325 good.append(e)
326 else:
326 else:
327 ui.warn(_("ignoring unknown color/effect %r "
327 ui.warn(_("ignoring unknown color/effect %r "
328 "(configured in color.%s)\n")
328 "(configured in color.%s)\n")
329 % (e, status))
329 % (e, status))
330 _styles[status] = ' '.join(good)
330 _styles[status] = ' '.join(good)
331
331
332 class colorui(uimod.ui):
332 class colorui(uimod.ui):
333 def popbuffer(self, labeled=False):
333 def popbuffer(self, labeled=False):
334 if self._colormode is None:
334 if self._colormode is None:
335 return super(colorui, self).popbuffer(labeled)
335 return super(colorui, self).popbuffer(labeled)
336
336
337 if labeled:
337 if labeled:
338 return ''.join(self.label(a, label) for a, label
338 return ''.join(self.label(a, label) for a, label
339 in self._buffers.pop())
339 in self._buffers.pop())
340 return ''.join(a for a, label in self._buffers.pop())
340 return ''.join(a for a, label in self._buffers.pop())
341
341
342 _colormode = 'ansi'
342 _colormode = 'ansi'
343 def write(self, *args, **opts):
343 def write(self, *args, **opts):
344 if self._colormode is None:
344 if self._colormode is None:
345 return super(colorui, self).write(*args, **opts)
345 return super(colorui, self).write(*args, **opts)
346
346
347 label = opts.get('label', '')
347 label = opts.get('label', '')
348 if self._buffers:
348 if self._buffers:
349 self._buffers[-1].extend([(str(a), label) for a in args])
349 self._buffers[-1].extend([(str(a), label) for a in args])
350 elif self._colormode == 'win32':
350 elif self._colormode == 'win32':
351 for a in args:
351 for a in args:
352 win32print(a, super(colorui, self).write, **opts)
352 win32print(a, super(colorui, self).write, **opts)
353 else:
353 else:
354 return super(colorui, self).write(
354 return super(colorui, self).write(
355 *[self.label(str(a), label) for a in args], **opts)
355 *[self.label(str(a), label) for a in args], **opts)
356
356
357 def write_err(self, *args, **opts):
357 def write_err(self, *args, **opts):
358 if self._colormode is None:
358 if self._colormode is None:
359 return super(colorui, self).write_err(*args, **opts)
359 return super(colorui, self).write_err(*args, **opts)
360
360
361 label = opts.get('label', '')
361 label = opts.get('label', '')
362 if self._colormode == 'win32':
362 if self._colormode == 'win32':
363 for a in args:
363 for a in args:
364 win32print(a, super(colorui, self).write_err, **opts)
364 win32print(a, super(colorui, self).write_err, **opts)
365 else:
365 else:
366 return super(colorui, self).write_err(
366 return super(colorui, self).write_err(
367 *[self.label(str(a), label) for a in args], **opts)
367 *[self.label(str(a), label) for a in args], **opts)
368
368
369 def label(self, msg, label):
369 def label(self, msg, label):
370 if self._colormode is None:
370 if self._colormode is None:
371 return super(colorui, self).label(msg, label)
371 return super(colorui, self).label(msg, label)
372
372
373 effects = []
373 effects = []
374 for l in label.split():
374 for l in label.split():
375 s = _styles.get(l, '')
375 s = _styles.get(l, '')
376 if s:
376 if s:
377 effects.append(s)
377 effects.append(s)
378 effects = ' '.join(effects)
378 effects = ' '.join(effects)
379 if effects:
379 if effects:
380 return '\n'.join([render_effects(s, effects)
380 return '\n'.join([render_effects(s, effects)
381 for s in msg.split('\n')])
381 for s in msg.split('\n')])
382 return msg
382 return msg
383
383
384 def templatelabel(context, mapping, args):
384 def templatelabel(context, mapping, args):
385 if len(args) != 2:
385 if len(args) != 2:
386 # i18n: "label" is a keyword
386 # i18n: "label" is a keyword
387 raise error.ParseError(_("label expects two arguments"))
387 raise error.ParseError(_("label expects two arguments"))
388
388
389 thing = templater._evalifliteral(args[1], context, mapping)
389 thing = templater._evalifliteral(args[1], context, mapping)
390
390
391 # apparently, repo could be a string that is the favicon?
391 # apparently, repo could be a string that is the favicon?
392 repo = mapping.get('repo', '')
392 repo = mapping.get('repo', '')
393 if isinstance(repo, str):
393 if isinstance(repo, str):
394 return thing
394 return thing
395
395
396 label = templater.stringify(args[0][0](context, mapping, args[0][1]))
396 label = templater._evalifliteral(args[0], context, mapping)
397 label = templater.runtemplate(context, mapping,
398 templater.compiletemplate(label, context))
399
397
400 thing = templater.stringify(thing)
398 thing = templater.stringify(thing)
401 label = templater.stringify(label)
399 label = templater.stringify(label)
402
400
403 return repo.ui.label(thing, label)
401 return repo.ui.label(thing, label)
404
402
405 def uisetup(ui):
403 def uisetup(ui):
406 if ui.plain():
404 if ui.plain():
407 return
405 return
408 if not isinstance(ui, colorui):
406 if not isinstance(ui, colorui):
409 colorui.__bases__ = (ui.__class__,)
407 colorui.__bases__ = (ui.__class__,)
410 ui.__class__ = colorui
408 ui.__class__ = colorui
411 def colorcmd(orig, ui_, opts, cmd, cmdfunc):
409 def colorcmd(orig, ui_, opts, cmd, cmdfunc):
412 mode = _modesetup(ui_, opts['color'])
410 mode = _modesetup(ui_, opts['color'])
413 colorui._colormode = mode
411 colorui._colormode = mode
414 if mode:
412 if mode:
415 extstyles()
413 extstyles()
416 configstyles(ui_)
414 configstyles(ui_)
417 return orig(ui_, opts, cmd, cmdfunc)
415 return orig(ui_, opts, cmd, cmdfunc)
418 extensions.wrapfunction(dispatch, '_runcommand', colorcmd)
416 extensions.wrapfunction(dispatch, '_runcommand', colorcmd)
419 templater.funcs['label'] = templatelabel
417 templater.funcs['label'] = templatelabel
420
418
421 def extsetup(ui):
419 def extsetup(ui):
422 commands.globalopts.append(
420 commands.globalopts.append(
423 ('', 'color', 'auto',
421 ('', 'color', 'auto',
424 # i18n: 'always', 'auto', and 'never' are keywords and should
422 # i18n: 'always', 'auto', and 'never' are keywords and should
425 # not be translated
423 # not be translated
426 _("when to colorize (boolean, always, auto, or never)"),
424 _("when to colorize (boolean, always, auto, or never)"),
427 _('TYPE')))
425 _('TYPE')))
428
426
429 if os.name != 'nt':
427 if os.name != 'nt':
430 w32effects = None
428 w32effects = None
431 else:
429 else:
432 import re, ctypes
430 import re, ctypes
433
431
434 _kernel32 = ctypes.windll.kernel32
432 _kernel32 = ctypes.windll.kernel32
435
433
436 _WORD = ctypes.c_ushort
434 _WORD = ctypes.c_ushort
437
435
438 _INVALID_HANDLE_VALUE = -1
436 _INVALID_HANDLE_VALUE = -1
439
437
440 class _COORD(ctypes.Structure):
438 class _COORD(ctypes.Structure):
441 _fields_ = [('X', ctypes.c_short),
439 _fields_ = [('X', ctypes.c_short),
442 ('Y', ctypes.c_short)]
440 ('Y', ctypes.c_short)]
443
441
444 class _SMALL_RECT(ctypes.Structure):
442 class _SMALL_RECT(ctypes.Structure):
445 _fields_ = [('Left', ctypes.c_short),
443 _fields_ = [('Left', ctypes.c_short),
446 ('Top', ctypes.c_short),
444 ('Top', ctypes.c_short),
447 ('Right', ctypes.c_short),
445 ('Right', ctypes.c_short),
448 ('Bottom', ctypes.c_short)]
446 ('Bottom', ctypes.c_short)]
449
447
450 class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
448 class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
451 _fields_ = [('dwSize', _COORD),
449 _fields_ = [('dwSize', _COORD),
452 ('dwCursorPosition', _COORD),
450 ('dwCursorPosition', _COORD),
453 ('wAttributes', _WORD),
451 ('wAttributes', _WORD),
454 ('srWindow', _SMALL_RECT),
452 ('srWindow', _SMALL_RECT),
455 ('dwMaximumWindowSize', _COORD)]
453 ('dwMaximumWindowSize', _COORD)]
456
454
457 _STD_OUTPUT_HANDLE = 0xfffffff5L # (DWORD)-11
455 _STD_OUTPUT_HANDLE = 0xfffffff5L # (DWORD)-11
458 _STD_ERROR_HANDLE = 0xfffffff4L # (DWORD)-12
456 _STD_ERROR_HANDLE = 0xfffffff4L # (DWORD)-12
459
457
460 _FOREGROUND_BLUE = 0x0001
458 _FOREGROUND_BLUE = 0x0001
461 _FOREGROUND_GREEN = 0x0002
459 _FOREGROUND_GREEN = 0x0002
462 _FOREGROUND_RED = 0x0004
460 _FOREGROUND_RED = 0x0004
463 _FOREGROUND_INTENSITY = 0x0008
461 _FOREGROUND_INTENSITY = 0x0008
464
462
465 _BACKGROUND_BLUE = 0x0010
463 _BACKGROUND_BLUE = 0x0010
466 _BACKGROUND_GREEN = 0x0020
464 _BACKGROUND_GREEN = 0x0020
467 _BACKGROUND_RED = 0x0040
465 _BACKGROUND_RED = 0x0040
468 _BACKGROUND_INTENSITY = 0x0080
466 _BACKGROUND_INTENSITY = 0x0080
469
467
470 _COMMON_LVB_REVERSE_VIDEO = 0x4000
468 _COMMON_LVB_REVERSE_VIDEO = 0x4000
471 _COMMON_LVB_UNDERSCORE = 0x8000
469 _COMMON_LVB_UNDERSCORE = 0x8000
472
470
473 # http://msdn.microsoft.com/en-us/library/ms682088%28VS.85%29.aspx
471 # http://msdn.microsoft.com/en-us/library/ms682088%28VS.85%29.aspx
474 w32effects = {
472 w32effects = {
475 'none': -1,
473 'none': -1,
476 'black': 0,
474 'black': 0,
477 'red': _FOREGROUND_RED,
475 'red': _FOREGROUND_RED,
478 'green': _FOREGROUND_GREEN,
476 'green': _FOREGROUND_GREEN,
479 'yellow': _FOREGROUND_RED | _FOREGROUND_GREEN,
477 'yellow': _FOREGROUND_RED | _FOREGROUND_GREEN,
480 'blue': _FOREGROUND_BLUE,
478 'blue': _FOREGROUND_BLUE,
481 'magenta': _FOREGROUND_BLUE | _FOREGROUND_RED,
479 'magenta': _FOREGROUND_BLUE | _FOREGROUND_RED,
482 'cyan': _FOREGROUND_BLUE | _FOREGROUND_GREEN,
480 'cyan': _FOREGROUND_BLUE | _FOREGROUND_GREEN,
483 'white': _FOREGROUND_RED | _FOREGROUND_GREEN | _FOREGROUND_BLUE,
481 'white': _FOREGROUND_RED | _FOREGROUND_GREEN | _FOREGROUND_BLUE,
484 'bold': _FOREGROUND_INTENSITY,
482 'bold': _FOREGROUND_INTENSITY,
485 'black_background': 0x100, # unused value > 0x0f
483 'black_background': 0x100, # unused value > 0x0f
486 'red_background': _BACKGROUND_RED,
484 'red_background': _BACKGROUND_RED,
487 'green_background': _BACKGROUND_GREEN,
485 'green_background': _BACKGROUND_GREEN,
488 'yellow_background': _BACKGROUND_RED | _BACKGROUND_GREEN,
486 'yellow_background': _BACKGROUND_RED | _BACKGROUND_GREEN,
489 'blue_background': _BACKGROUND_BLUE,
487 'blue_background': _BACKGROUND_BLUE,
490 'purple_background': _BACKGROUND_BLUE | _BACKGROUND_RED,
488 'purple_background': _BACKGROUND_BLUE | _BACKGROUND_RED,
491 'cyan_background': _BACKGROUND_BLUE | _BACKGROUND_GREEN,
489 'cyan_background': _BACKGROUND_BLUE | _BACKGROUND_GREEN,
492 'white_background': (_BACKGROUND_RED | _BACKGROUND_GREEN |
490 'white_background': (_BACKGROUND_RED | _BACKGROUND_GREEN |
493 _BACKGROUND_BLUE),
491 _BACKGROUND_BLUE),
494 'bold_background': _BACKGROUND_INTENSITY,
492 'bold_background': _BACKGROUND_INTENSITY,
495 'underline': _COMMON_LVB_UNDERSCORE, # double-byte charsets only
493 'underline': _COMMON_LVB_UNDERSCORE, # double-byte charsets only
496 'inverse': _COMMON_LVB_REVERSE_VIDEO, # double-byte charsets only
494 'inverse': _COMMON_LVB_REVERSE_VIDEO, # double-byte charsets only
497 }
495 }
498
496
499 passthrough = set([_FOREGROUND_INTENSITY,
497 passthrough = set([_FOREGROUND_INTENSITY,
500 _BACKGROUND_INTENSITY,
498 _BACKGROUND_INTENSITY,
501 _COMMON_LVB_UNDERSCORE,
499 _COMMON_LVB_UNDERSCORE,
502 _COMMON_LVB_REVERSE_VIDEO])
500 _COMMON_LVB_REVERSE_VIDEO])
503
501
504 stdout = _kernel32.GetStdHandle(
502 stdout = _kernel32.GetStdHandle(
505 _STD_OUTPUT_HANDLE) # don't close the handle returned
503 _STD_OUTPUT_HANDLE) # don't close the handle returned
506 if stdout is None or stdout == _INVALID_HANDLE_VALUE:
504 if stdout is None or stdout == _INVALID_HANDLE_VALUE:
507 w32effects = None
505 w32effects = None
508 else:
506 else:
509 csbi = _CONSOLE_SCREEN_BUFFER_INFO()
507 csbi = _CONSOLE_SCREEN_BUFFER_INFO()
510 if not _kernel32.GetConsoleScreenBufferInfo(
508 if not _kernel32.GetConsoleScreenBufferInfo(
511 stdout, ctypes.byref(csbi)):
509 stdout, ctypes.byref(csbi)):
512 # stdout may not support GetConsoleScreenBufferInfo()
510 # stdout may not support GetConsoleScreenBufferInfo()
513 # when called from subprocess or redirected
511 # when called from subprocess or redirected
514 w32effects = None
512 w32effects = None
515 else:
513 else:
516 origattr = csbi.wAttributes
514 origattr = csbi.wAttributes
517 ansire = re.compile('\033\[([^m]*)m([^\033]*)(.*)',
515 ansire = re.compile('\033\[([^m]*)m([^\033]*)(.*)',
518 re.MULTILINE | re.DOTALL)
516 re.MULTILINE | re.DOTALL)
519
517
520 def win32print(text, orig, **opts):
518 def win32print(text, orig, **opts):
521 label = opts.get('label', '')
519 label = opts.get('label', '')
522 attr = origattr
520 attr = origattr
523
521
524 def mapcolor(val, attr):
522 def mapcolor(val, attr):
525 if val == -1:
523 if val == -1:
526 return origattr
524 return origattr
527 elif val in passthrough:
525 elif val in passthrough:
528 return attr | val
526 return attr | val
529 elif val > 0x0f:
527 elif val > 0x0f:
530 return (val & 0x70) | (attr & 0x8f)
528 return (val & 0x70) | (attr & 0x8f)
531 else:
529 else:
532 return (val & 0x07) | (attr & 0xf8)
530 return (val & 0x07) | (attr & 0xf8)
533
531
534 # determine console attributes based on labels
532 # determine console attributes based on labels
535 for l in label.split():
533 for l in label.split():
536 style = _styles.get(l, '')
534 style = _styles.get(l, '')
537 for effect in style.split():
535 for effect in style.split():
538 attr = mapcolor(w32effects[effect], attr)
536 attr = mapcolor(w32effects[effect], attr)
539
537
540 # hack to ensure regexp finds data
538 # hack to ensure regexp finds data
541 if not text.startswith('\033['):
539 if not text.startswith('\033['):
542 text = '\033[m' + text
540 text = '\033[m' + text
543
541
544 # Look for ANSI-like codes embedded in text
542 # Look for ANSI-like codes embedded in text
545 m = re.match(ansire, text)
543 m = re.match(ansire, text)
546
544
547 try:
545 try:
548 while m:
546 while m:
549 for sattr in m.group(1).split(';'):
547 for sattr in m.group(1).split(';'):
550 if sattr:
548 if sattr:
551 attr = mapcolor(int(sattr), attr)
549 attr = mapcolor(int(sattr), attr)
552 _kernel32.SetConsoleTextAttribute(stdout, attr)
550 _kernel32.SetConsoleTextAttribute(stdout, attr)
553 orig(m.group(2), **opts)
551 orig(m.group(2), **opts)
554 m = re.match(ansire, m.group(3))
552 m = re.match(ansire, m.group(3))
555 finally:
553 finally:
556 # Explicitly reset original attributes
554 # Explicitly reset original attributes
557 _kernel32.SetConsoleTextAttribute(stdout, origattr)
555 _kernel32.SetConsoleTextAttribute(stdout, origattr)
@@ -1,589 +1,583 b''
1 # templater.py - template expansion for output
1 # templater.py - template expansion for output
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from i18n import _
8 from i18n import _
9 import sys, os, re
9 import sys, os, re
10 import util, config, templatefilters, parser, error
10 import util, config, templatefilters, parser, error
11 import types
11 import types
12 import minirst
12 import minirst
13
13
14 # template parsing
14 # template parsing
15
15
16 elements = {
16 elements = {
17 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
17 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
18 ",": (2, None, ("list", 2)),
18 ",": (2, None, ("list", 2)),
19 "|": (5, None, ("|", 5)),
19 "|": (5, None, ("|", 5)),
20 "%": (6, None, ("%", 6)),
20 "%": (6, None, ("%", 6)),
21 ")": (0, None, None),
21 ")": (0, None, None),
22 "symbol": (0, ("symbol",), None),
22 "symbol": (0, ("symbol",), None),
23 "string": (0, ("string",), None),
23 "string": (0, ("string",), None),
24 "end": (0, None, None),
24 "end": (0, None, None),
25 }
25 }
26
26
27 def tokenizer(data):
27 def tokenizer(data):
28 program, start, end = data
28 program, start, end = data
29 pos = start
29 pos = start
30 while pos < end:
30 while pos < end:
31 c = program[pos]
31 c = program[pos]
32 if c.isspace(): # skip inter-token whitespace
32 if c.isspace(): # skip inter-token whitespace
33 pass
33 pass
34 elif c in "(,)%|": # handle simple operators
34 elif c in "(,)%|": # handle simple operators
35 yield (c, None, pos)
35 yield (c, None, pos)
36 elif (c in '"\'' or c == 'r' and
36 elif (c in '"\'' or c == 'r' and
37 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
37 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
38 if c == 'r':
38 if c == 'r':
39 pos += 1
39 pos += 1
40 c = program[pos]
40 c = program[pos]
41 decode = False
41 decode = False
42 else:
42 else:
43 decode = True
43 decode = True
44 pos += 1
44 pos += 1
45 s = pos
45 s = pos
46 while pos < end: # find closing quote
46 while pos < end: # find closing quote
47 d = program[pos]
47 d = program[pos]
48 if decode and d == '\\': # skip over escaped characters
48 if decode and d == '\\': # skip over escaped characters
49 pos += 2
49 pos += 2
50 continue
50 continue
51 if d == c:
51 if d == c:
52 if not decode:
52 if not decode:
53 yield ('string', program[s:pos].replace('\\', r'\\'), s)
53 yield ('string', program[s:pos].replace('\\', r'\\'), s)
54 break
54 break
55 yield ('string', program[s:pos], s)
55 yield ('string', program[s:pos], s)
56 break
56 break
57 pos += 1
57 pos += 1
58 else:
58 else:
59 raise error.ParseError(_("unterminated string"), s)
59 raise error.ParseError(_("unterminated string"), s)
60 elif c.isalnum() or c in '_':
60 elif c.isalnum() or c in '_':
61 s = pos
61 s = pos
62 pos += 1
62 pos += 1
63 while pos < end: # find end of symbol
63 while pos < end: # find end of symbol
64 d = program[pos]
64 d = program[pos]
65 if not (d.isalnum() or d == "_"):
65 if not (d.isalnum() or d == "_"):
66 break
66 break
67 pos += 1
67 pos += 1
68 sym = program[s:pos]
68 sym = program[s:pos]
69 yield ('symbol', sym, s)
69 yield ('symbol', sym, s)
70 pos -= 1
70 pos -= 1
71 elif c == '}':
71 elif c == '}':
72 pos += 1
72 pos += 1
73 break
73 break
74 else:
74 else:
75 raise error.ParseError(_("syntax error"), pos)
75 raise error.ParseError(_("syntax error"), pos)
76 pos += 1
76 pos += 1
77 yield ('end', None, pos)
77 yield ('end', None, pos)
78
78
79 def compiletemplate(tmpl, context):
79 def compiletemplate(tmpl, context):
80 parsed = []
80 parsed = []
81 pos, stop = 0, len(tmpl)
81 pos, stop = 0, len(tmpl)
82 p = parser.parser(tokenizer, elements)
82 p = parser.parser(tokenizer, elements)
83 while pos < stop:
83 while pos < stop:
84 n = tmpl.find('{', pos)
84 n = tmpl.find('{', pos)
85 if n < 0:
85 if n < 0:
86 parsed.append(("string", tmpl[pos:].decode("string-escape")))
86 parsed.append(("string", tmpl[pos:].decode("string-escape")))
87 break
87 break
88 if n > 0 and tmpl[n - 1] == '\\':
88 if n > 0 and tmpl[n - 1] == '\\':
89 # escaped
89 # escaped
90 parsed.append(("string",
90 parsed.append(("string",
91 (tmpl[pos:n - 1] + "{").decode("string-escape")))
91 (tmpl[pos:n - 1] + "{").decode("string-escape")))
92 pos = n + 1
92 pos = n + 1
93 continue
93 continue
94 if n > pos:
94 if n > pos:
95 parsed.append(("string", tmpl[pos:n].decode("string-escape")))
95 parsed.append(("string", tmpl[pos:n].decode("string-escape")))
96
96
97 pd = [tmpl, n + 1, stop]
97 pd = [tmpl, n + 1, stop]
98 parseres, pos = p.parse(pd)
98 parseres, pos = p.parse(pd)
99 parsed.append(parseres)
99 parsed.append(parseres)
100
100
101 return [compileexp(e, context) for e in parsed]
101 return [compileexp(e, context) for e in parsed]
102
102
103 def compileexp(exp, context):
103 def compileexp(exp, context):
104 t = exp[0]
104 t = exp[0]
105 if t in methods:
105 if t in methods:
106 return methods[t](exp, context)
106 return methods[t](exp, context)
107 raise error.ParseError(_("unknown method '%s'") % t)
107 raise error.ParseError(_("unknown method '%s'") % t)
108
108
109 # template evaluation
109 # template evaluation
110
110
111 def getsymbol(exp):
111 def getsymbol(exp):
112 if exp[0] == 'symbol':
112 if exp[0] == 'symbol':
113 return exp[1]
113 return exp[1]
114 raise error.ParseError(_("expected a symbol"))
114 raise error.ParseError(_("expected a symbol"))
115
115
116 def getlist(x):
116 def getlist(x):
117 if not x:
117 if not x:
118 return []
118 return []
119 if x[0] == 'list':
119 if x[0] == 'list':
120 return getlist(x[1]) + [x[2]]
120 return getlist(x[1]) + [x[2]]
121 return [x]
121 return [x]
122
122
123 def getfilter(exp, context):
123 def getfilter(exp, context):
124 f = getsymbol(exp)
124 f = getsymbol(exp)
125 if f not in context._filters:
125 if f not in context._filters:
126 raise error.ParseError(_("unknown function '%s'") % f)
126 raise error.ParseError(_("unknown function '%s'") % f)
127 return context._filters[f]
127 return context._filters[f]
128
128
129 def gettemplate(exp, context):
129 def gettemplate(exp, context):
130 if exp[0] == 'string':
130 if exp[0] == 'string':
131 return compiletemplate(exp[1], context)
131 return compiletemplate(exp[1], context)
132 if exp[0] == 'symbol':
132 if exp[0] == 'symbol':
133 return context._load(exp[1])
133 return context._load(exp[1])
134 raise error.ParseError(_("expected template specifier"))
134 raise error.ParseError(_("expected template specifier"))
135
135
136 def runstring(context, mapping, data):
136 def runstring(context, mapping, data):
137 return data
137 return data
138
138
139 def runsymbol(context, mapping, key):
139 def runsymbol(context, mapping, key):
140 v = mapping.get(key)
140 v = mapping.get(key)
141 if v is None:
141 if v is None:
142 v = context._defaults.get(key)
142 v = context._defaults.get(key)
143 if v is None:
143 if v is None:
144 try:
144 try:
145 v = context.process(key, mapping)
145 v = context.process(key, mapping)
146 except TemplateNotFound:
146 except TemplateNotFound:
147 v = ''
147 v = ''
148 if util.safehasattr(v, '__call__'):
148 if util.safehasattr(v, '__call__'):
149 return v(**mapping)
149 return v(**mapping)
150 if isinstance(v, types.GeneratorType):
150 if isinstance(v, types.GeneratorType):
151 v = list(v)
151 v = list(v)
152 mapping[key] = v
152 mapping[key] = v
153 return v
153 return v
154 return v
154 return v
155
155
156 def buildfilter(exp, context):
156 def buildfilter(exp, context):
157 func, data = compileexp(exp[1], context)
157 func, data = compileexp(exp[1], context)
158 filt = getfilter(exp[2], context)
158 filt = getfilter(exp[2], context)
159 return (runfilter, (func, data, filt))
159 return (runfilter, (func, data, filt))
160
160
161 def runfilter(context, mapping, data):
161 def runfilter(context, mapping, data):
162 func, data, filt = data
162 func, data, filt = data
163 try:
163 try:
164 return filt(func(context, mapping, data))
164 return filt(func(context, mapping, data))
165 except (ValueError, AttributeError, TypeError):
165 except (ValueError, AttributeError, TypeError):
166 if isinstance(data, tuple):
166 if isinstance(data, tuple):
167 dt = data[1]
167 dt = data[1]
168 else:
168 else:
169 dt = data
169 dt = data
170 raise util.Abort(_("template filter '%s' is not compatible with "
170 raise util.Abort(_("template filter '%s' is not compatible with "
171 "keyword '%s'") % (filt.func_name, dt))
171 "keyword '%s'") % (filt.func_name, dt))
172
172
173 def buildmap(exp, context):
173 def buildmap(exp, context):
174 func, data = compileexp(exp[1], context)
174 func, data = compileexp(exp[1], context)
175 ctmpl = gettemplate(exp[2], context)
175 ctmpl = gettemplate(exp[2], context)
176 return (runmap, (func, data, ctmpl))
176 return (runmap, (func, data, ctmpl))
177
177
178 def runtemplate(context, mapping, template):
178 def runtemplate(context, mapping, template):
179 for func, data in template:
179 for func, data in template:
180 yield func(context, mapping, data)
180 yield func(context, mapping, data)
181
181
182 def runmap(context, mapping, data):
182 def runmap(context, mapping, data):
183 func, data, ctmpl = data
183 func, data, ctmpl = data
184 d = func(context, mapping, data)
184 d = func(context, mapping, data)
185 if util.safehasattr(d, '__call__'):
185 if util.safehasattr(d, '__call__'):
186 d = d()
186 d = d()
187
187
188 lm = mapping.copy()
188 lm = mapping.copy()
189
189
190 for i in d:
190 for i in d:
191 if isinstance(i, dict):
191 if isinstance(i, dict):
192 lm.update(i)
192 lm.update(i)
193 lm['originalnode'] = mapping.get('node')
193 lm['originalnode'] = mapping.get('node')
194 yield runtemplate(context, lm, ctmpl)
194 yield runtemplate(context, lm, ctmpl)
195 else:
195 else:
196 # v is not an iterable of dicts, this happen when 'key'
196 # v is not an iterable of dicts, this happen when 'key'
197 # has been fully expanded already and format is useless.
197 # has been fully expanded already and format is useless.
198 # If so, return the expanded value.
198 # If so, return the expanded value.
199 yield i
199 yield i
200
200
201 def buildfunc(exp, context):
201 def buildfunc(exp, context):
202 n = getsymbol(exp[1])
202 n = getsymbol(exp[1])
203 args = [compileexp(x, context) for x in getlist(exp[2])]
203 args = [compileexp(x, context) for x in getlist(exp[2])]
204 if n in funcs:
204 if n in funcs:
205 f = funcs[n]
205 f = funcs[n]
206 return (f, args)
206 return (f, args)
207 if n in context._filters:
207 if n in context._filters:
208 if len(args) != 1:
208 if len(args) != 1:
209 raise error.ParseError(_("filter %s expects one argument") % n)
209 raise error.ParseError(_("filter %s expects one argument") % n)
210 f = context._filters[n]
210 f = context._filters[n]
211 return (runfilter, (args[0][0], args[0][1], f))
211 return (runfilter, (args[0][0], args[0][1], f))
212
212
213 def date(context, mapping, args):
213 def date(context, mapping, args):
214 if not (1 <= len(args) <= 2):
214 if not (1 <= len(args) <= 2):
215 raise error.ParseError(_("date expects one or two arguments"))
215 raise error.ParseError(_("date expects one or two arguments"))
216
216
217 date = args[0][0](context, mapping, args[0][1])
217 date = args[0][0](context, mapping, args[0][1])
218 if len(args) == 2:
218 if len(args) == 2:
219 fmt = stringify(args[1][0](context, mapping, args[1][1]))
219 fmt = stringify(args[1][0](context, mapping, args[1][1]))
220 return util.datestr(date, fmt)
220 return util.datestr(date, fmt)
221 return util.datestr(date)
221 return util.datestr(date)
222
222
223 def fill(context, mapping, args):
223 def fill(context, mapping, args):
224 if not (1 <= len(args) <= 4):
224 if not (1 <= len(args) <= 4):
225 raise error.ParseError(_("fill expects one to four arguments"))
225 raise error.ParseError(_("fill expects one to four arguments"))
226
226
227 text = stringify(args[0][0](context, mapping, args[0][1]))
227 text = stringify(args[0][0](context, mapping, args[0][1]))
228 width = 76
228 width = 76
229 initindent = ''
229 initindent = ''
230 hangindent = ''
230 hangindent = ''
231 if 2 <= len(args) <= 4:
231 if 2 <= len(args) <= 4:
232 try:
232 try:
233 width = int(stringify(args[1][0](context, mapping, args[1][1])))
233 width = int(stringify(args[1][0](context, mapping, args[1][1])))
234 except ValueError:
234 except ValueError:
235 raise error.ParseError(_("fill expects an integer width"))
235 raise error.ParseError(_("fill expects an integer width"))
236 try:
236 try:
237 initindent = stringify(args[2][0](context, mapping, args[2][1]))
237 initindent = stringify(_evalifliteral(args[2], context, mapping))
238 initindent = stringify(runtemplate(context, mapping,
238 hangindent = stringify(_evalifliteral(args[3], context, mapping))
239 compiletemplate(initindent, context)))
240 hangindent = stringify(args[3][0](context, mapping, args[3][1]))
241 hangindent = stringify(runtemplate(context, mapping,
242 compiletemplate(hangindent, context)))
243 except IndexError:
239 except IndexError:
244 pass
240 pass
245
241
246 return templatefilters.fill(text, width, initindent, hangindent)
242 return templatefilters.fill(text, width, initindent, hangindent)
247
243
248 def get(context, mapping, args):
244 def get(context, mapping, args):
249 if len(args) != 2:
245 if len(args) != 2:
250 # i18n: "get" is a keyword
246 # i18n: "get" is a keyword
251 raise error.ParseError(_("get() expects two arguments"))
247 raise error.ParseError(_("get() expects two arguments"))
252
248
253 dictarg = args[0][0](context, mapping, args[0][1])
249 dictarg = args[0][0](context, mapping, args[0][1])
254 if not util.safehasattr(dictarg, 'get'):
250 if not util.safehasattr(dictarg, 'get'):
255 # i18n: "get" is a keyword
251 # i18n: "get" is a keyword
256 raise error.ParseError(_("get() expects a dict as first argument"))
252 raise error.ParseError(_("get() expects a dict as first argument"))
257
253
258 key = args[1][0](context, mapping, args[1][1])
254 key = args[1][0](context, mapping, args[1][1])
259 yield dictarg.get(key)
255 yield dictarg.get(key)
260
256
261 def _evalifliteral(arg, context, mapping):
257 def _evalifliteral(arg, context, mapping):
262 t = stringify(arg[0](context, mapping, arg[1]))
258 t = stringify(arg[0](context, mapping, arg[1]))
263 if arg[0] == runstring:
259 if arg[0] == runstring:
264 yield runtemplate(context, mapping, compiletemplate(t, context))
260 yield runtemplate(context, mapping, compiletemplate(t, context))
265 else:
261 else:
266 yield t
262 yield t
267
263
268 def if_(context, mapping, args):
264 def if_(context, mapping, args):
269 if not (2 <= len(args) <= 3):
265 if not (2 <= len(args) <= 3):
270 # i18n: "if" is a keyword
266 # i18n: "if" is a keyword
271 raise error.ParseError(_("if expects two or three arguments"))
267 raise error.ParseError(_("if expects two or three arguments"))
272
268
273 test = stringify(args[0][0](context, mapping, args[0][1]))
269 test = stringify(args[0][0](context, mapping, args[0][1]))
274 if test:
270 if test:
275 yield _evalifliteral(args[1], context, mapping)
271 yield _evalifliteral(args[1], context, mapping)
276 elif len(args) == 3:
272 elif len(args) == 3:
277 yield _evalifliteral(args[2], context, mapping)
273 yield _evalifliteral(args[2], context, mapping)
278
274
279 def ifeq(context, mapping, args):
275 def ifeq(context, mapping, args):
280 if not (3 <= len(args) <= 4):
276 if not (3 <= len(args) <= 4):
281 # i18n: "ifeq" is a keyword
277 # i18n: "ifeq" is a keyword
282 raise error.ParseError(_("ifeq expects three or four arguments"))
278 raise error.ParseError(_("ifeq expects three or four arguments"))
283
279
284 test = stringify(args[0][0](context, mapping, args[0][1]))
280 test = stringify(args[0][0](context, mapping, args[0][1]))
285 match = stringify(args[1][0](context, mapping, args[1][1]))
281 match = stringify(args[1][0](context, mapping, args[1][1]))
286 if test == match:
282 if test == match:
287 yield _evalifliteral(args[2], context, mapping)
283 yield _evalifliteral(args[2], context, mapping)
288 elif len(args) == 4:
284 elif len(args) == 4:
289 yield _evalifliteral(args[3], context, mapping)
285 yield _evalifliteral(args[3], context, mapping)
290
286
291 def join(context, mapping, args):
287 def join(context, mapping, args):
292 if not (1 <= len(args) <= 2):
288 if not (1 <= len(args) <= 2):
293 # i18n: "join" is a keyword
289 # i18n: "join" is a keyword
294 raise error.ParseError(_("join expects one or two arguments"))
290 raise error.ParseError(_("join expects one or two arguments"))
295
291
296 joinset = args[0][0](context, mapping, args[0][1])
292 joinset = args[0][0](context, mapping, args[0][1])
297 if util.safehasattr(joinset, '__call__'):
293 if util.safehasattr(joinset, '__call__'):
298 jf = joinset.joinfmt
294 jf = joinset.joinfmt
299 joinset = [jf(x) for x in joinset()]
295 joinset = [jf(x) for x in joinset()]
300
296
301 joiner = " "
297 joiner = " "
302 if len(args) > 1:
298 if len(args) > 1:
303 joiner = args[1][0](context, mapping, args[1][1])
299 joiner = args[1][0](context, mapping, args[1][1])
304
300
305 first = True
301 first = True
306 for x in joinset:
302 for x in joinset:
307 if first:
303 if first:
308 first = False
304 first = False
309 else:
305 else:
310 yield joiner
306 yield joiner
311 yield x
307 yield x
312
308
313 def label(context, mapping, args):
309 def label(context, mapping, args):
314 if len(args) != 2:
310 if len(args) != 2:
315 # i18n: "label" is a keyword
311 # i18n: "label" is a keyword
316 raise error.ParseError(_("label expects two arguments"))
312 raise error.ParseError(_("label expects two arguments"))
317
313
318 # ignore args[0] (the label string) since this is supposed to be a a no-op
314 # ignore args[0] (the label string) since this is supposed to be a a no-op
319 yield _evalifliteral(args[1], context, mapping)
315 yield _evalifliteral(args[1], context, mapping)
320
316
321 def rstdoc(context, mapping, args):
317 def rstdoc(context, mapping, args):
322 if len(args) != 2:
318 if len(args) != 2:
323 # i18n: "rstdoc" is a keyword
319 # i18n: "rstdoc" is a keyword
324 raise error.ParseError(_("rstdoc expects two arguments"))
320 raise error.ParseError(_("rstdoc expects two arguments"))
325
321
326 text = stringify(args[0][0](context, mapping, args[0][1]))
322 text = stringify(args[0][0](context, mapping, args[0][1]))
327 style = stringify(args[1][0](context, mapping, args[1][1]))
323 style = stringify(args[1][0](context, mapping, args[1][1]))
328
324
329 return minirst.format(text, style=style, keep=['verbose'])
325 return minirst.format(text, style=style, keep=['verbose'])
330
326
331 def strip(context, mapping, args):
327 def strip(context, mapping, args):
332 if not (1 <= len(args) <= 2):
328 if not (1 <= len(args) <= 2):
333 raise error.ParseError(_("strip expects one or two arguments"))
329 raise error.ParseError(_("strip expects one or two arguments"))
334
330
335 text = args[0][0](context, mapping, args[0][1])
331 text = args[0][0](context, mapping, args[0][1])
336 if len(args) == 2:
332 if len(args) == 2:
337 chars = args[1][0](context, mapping, args[1][1])
333 chars = args[1][0](context, mapping, args[1][1])
338 return text.strip(chars)
334 return text.strip(chars)
339 return text.strip()
335 return text.strip()
340
336
341 def sub(context, mapping, args):
337 def sub(context, mapping, args):
342 if len(args) != 3:
338 if len(args) != 3:
343 # i18n: "sub" is a keyword
339 # i18n: "sub" is a keyword
344 raise error.ParseError(_("sub expects three arguments"))
340 raise error.ParseError(_("sub expects three arguments"))
345
341
346 pat = stringify(args[0][0](context, mapping, args[0][1]))
342 pat = stringify(args[0][0](context, mapping, args[0][1]))
347 rpl = stringify(args[1][0](context, mapping, args[1][1]))
343 rpl = stringify(args[1][0](context, mapping, args[1][1]))
348 src = stringify(args[2][0](context, mapping, args[2][1]))
344 src = stringify(_evalifliteral(args[2], context, mapping))
349 src = stringify(runtemplate(context, mapping,
350 compiletemplate(src, context)))
351 yield re.sub(pat, rpl, src)
345 yield re.sub(pat, rpl, src)
352
346
353 methods = {
347 methods = {
354 "string": lambda e, c: (runstring, e[1]),
348 "string": lambda e, c: (runstring, e[1]),
355 "symbol": lambda e, c: (runsymbol, e[1]),
349 "symbol": lambda e, c: (runsymbol, e[1]),
356 "group": lambda e, c: compileexp(e[1], c),
350 "group": lambda e, c: compileexp(e[1], c),
357 # ".": buildmember,
351 # ".": buildmember,
358 "|": buildfilter,
352 "|": buildfilter,
359 "%": buildmap,
353 "%": buildmap,
360 "func": buildfunc,
354 "func": buildfunc,
361 }
355 }
362
356
363 funcs = {
357 funcs = {
364 "date": date,
358 "date": date,
365 "fill": fill,
359 "fill": fill,
366 "get": get,
360 "get": get,
367 "if": if_,
361 "if": if_,
368 "ifeq": ifeq,
362 "ifeq": ifeq,
369 "join": join,
363 "join": join,
370 "label": label,
364 "label": label,
371 "rstdoc": rstdoc,
365 "rstdoc": rstdoc,
372 "strip": strip,
366 "strip": strip,
373 "sub": sub,
367 "sub": sub,
374 }
368 }
375
369
376 # template engine
370 # template engine
377
371
378 path = ['templates', '../templates']
372 path = ['templates', '../templates']
379 stringify = templatefilters.stringify
373 stringify = templatefilters.stringify
380
374
381 def _flatten(thing):
375 def _flatten(thing):
382 '''yield a single stream from a possibly nested set of iterators'''
376 '''yield a single stream from a possibly nested set of iterators'''
383 if isinstance(thing, str):
377 if isinstance(thing, str):
384 yield thing
378 yield thing
385 elif not util.safehasattr(thing, '__iter__'):
379 elif not util.safehasattr(thing, '__iter__'):
386 if thing is not None:
380 if thing is not None:
387 yield str(thing)
381 yield str(thing)
388 else:
382 else:
389 for i in thing:
383 for i in thing:
390 if isinstance(i, str):
384 if isinstance(i, str):
391 yield i
385 yield i
392 elif not util.safehasattr(i, '__iter__'):
386 elif not util.safehasattr(i, '__iter__'):
393 if i is not None:
387 if i is not None:
394 yield str(i)
388 yield str(i)
395 elif i is not None:
389 elif i is not None:
396 for j in _flatten(i):
390 for j in _flatten(i):
397 yield j
391 yield j
398
392
399 def parsestring(s, quoted=True):
393 def parsestring(s, quoted=True):
400 '''parse a string using simple c-like syntax.
394 '''parse a string using simple c-like syntax.
401 string must be in quotes if quoted is True.'''
395 string must be in quotes if quoted is True.'''
402 if quoted:
396 if quoted:
403 if len(s) < 2 or s[0] != s[-1]:
397 if len(s) < 2 or s[0] != s[-1]:
404 raise SyntaxError(_('unmatched quotes'))
398 raise SyntaxError(_('unmatched quotes'))
405 return s[1:-1].decode('string_escape')
399 return s[1:-1].decode('string_escape')
406
400
407 return s.decode('string_escape')
401 return s.decode('string_escape')
408
402
409 class engine(object):
403 class engine(object):
410 '''template expansion engine.
404 '''template expansion engine.
411
405
412 template expansion works like this. a map file contains key=value
406 template expansion works like this. a map file contains key=value
413 pairs. if value is quoted, it is treated as string. otherwise, it
407 pairs. if value is quoted, it is treated as string. otherwise, it
414 is treated as name of template file.
408 is treated as name of template file.
415
409
416 templater is asked to expand a key in map. it looks up key, and
410 templater is asked to expand a key in map. it looks up key, and
417 looks for strings like this: {foo}. it expands {foo} by looking up
411 looks for strings like this: {foo}. it expands {foo} by looking up
418 foo in map, and substituting it. expansion is recursive: it stops
412 foo in map, and substituting it. expansion is recursive: it stops
419 when there is no more {foo} to replace.
413 when there is no more {foo} to replace.
420
414
421 expansion also allows formatting and filtering.
415 expansion also allows formatting and filtering.
422
416
423 format uses key to expand each item in list. syntax is
417 format uses key to expand each item in list. syntax is
424 {key%format}.
418 {key%format}.
425
419
426 filter uses function to transform value. syntax is
420 filter uses function to transform value. syntax is
427 {key|filter1|filter2|...}.'''
421 {key|filter1|filter2|...}.'''
428
422
429 def __init__(self, loader, filters={}, defaults={}):
423 def __init__(self, loader, filters={}, defaults={}):
430 self._loader = loader
424 self._loader = loader
431 self._filters = filters
425 self._filters = filters
432 self._defaults = defaults
426 self._defaults = defaults
433 self._cache = {}
427 self._cache = {}
434
428
435 def _load(self, t):
429 def _load(self, t):
436 '''load, parse, and cache a template'''
430 '''load, parse, and cache a template'''
437 if t not in self._cache:
431 if t not in self._cache:
438 self._cache[t] = compiletemplate(self._loader(t), self)
432 self._cache[t] = compiletemplate(self._loader(t), self)
439 return self._cache[t]
433 return self._cache[t]
440
434
441 def process(self, t, mapping):
435 def process(self, t, mapping):
442 '''Perform expansion. t is name of map element to expand.
436 '''Perform expansion. t is name of map element to expand.
443 mapping contains added elements for use during expansion. Is a
437 mapping contains added elements for use during expansion. Is a
444 generator.'''
438 generator.'''
445 return _flatten(runtemplate(self, mapping, self._load(t)))
439 return _flatten(runtemplate(self, mapping, self._load(t)))
446
440
447 engines = {'default': engine}
441 engines = {'default': engine}
448
442
449 def stylelist():
443 def stylelist():
450 paths = templatepath()
444 paths = templatepath()
451 if not paths:
445 if not paths:
452 return _('no templates found, try `hg debuginstall` for more info')
446 return _('no templates found, try `hg debuginstall` for more info')
453 dirlist = os.listdir(paths[0])
447 dirlist = os.listdir(paths[0])
454 stylelist = []
448 stylelist = []
455 for file in dirlist:
449 for file in dirlist:
456 split = file.split(".")
450 split = file.split(".")
457 if split[0] == "map-cmdline":
451 if split[0] == "map-cmdline":
458 stylelist.append(split[1])
452 stylelist.append(split[1])
459 return ", ".join(sorted(stylelist))
453 return ", ".join(sorted(stylelist))
460
454
461 class TemplateNotFound(util.Abort):
455 class TemplateNotFound(util.Abort):
462 pass
456 pass
463
457
464 class templater(object):
458 class templater(object):
465
459
466 def __init__(self, mapfile, filters={}, defaults={}, cache={},
460 def __init__(self, mapfile, filters={}, defaults={}, cache={},
467 minchunk=1024, maxchunk=65536):
461 minchunk=1024, maxchunk=65536):
468 '''set up template engine.
462 '''set up template engine.
469 mapfile is name of file to read map definitions from.
463 mapfile is name of file to read map definitions from.
470 filters is dict of functions. each transforms a value into another.
464 filters is dict of functions. each transforms a value into another.
471 defaults is dict of default map definitions.'''
465 defaults is dict of default map definitions.'''
472 self.mapfile = mapfile or 'template'
466 self.mapfile = mapfile or 'template'
473 self.cache = cache.copy()
467 self.cache = cache.copy()
474 self.map = {}
468 self.map = {}
475 self.base = (mapfile and os.path.dirname(mapfile)) or ''
469 self.base = (mapfile and os.path.dirname(mapfile)) or ''
476 self.filters = templatefilters.filters.copy()
470 self.filters = templatefilters.filters.copy()
477 self.filters.update(filters)
471 self.filters.update(filters)
478 self.defaults = defaults
472 self.defaults = defaults
479 self.minchunk, self.maxchunk = minchunk, maxchunk
473 self.minchunk, self.maxchunk = minchunk, maxchunk
480 self.ecache = {}
474 self.ecache = {}
481
475
482 if not mapfile:
476 if not mapfile:
483 return
477 return
484 if not os.path.exists(mapfile):
478 if not os.path.exists(mapfile):
485 raise util.Abort(_("style '%s' not found") % mapfile,
479 raise util.Abort(_("style '%s' not found") % mapfile,
486 hint=_("available styles: %s") % stylelist())
480 hint=_("available styles: %s") % stylelist())
487
481
488 conf = config.config()
482 conf = config.config()
489 conf.read(mapfile)
483 conf.read(mapfile)
490
484
491 for key, val in conf[''].items():
485 for key, val in conf[''].items():
492 if not val:
486 if not val:
493 raise SyntaxError(_('%s: missing value') % conf.source('', key))
487 raise SyntaxError(_('%s: missing value') % conf.source('', key))
494 if val[0] in "'\"":
488 if val[0] in "'\"":
495 try:
489 try:
496 self.cache[key] = parsestring(val)
490 self.cache[key] = parsestring(val)
497 except SyntaxError, inst:
491 except SyntaxError, inst:
498 raise SyntaxError('%s: %s' %
492 raise SyntaxError('%s: %s' %
499 (conf.source('', key), inst.args[0]))
493 (conf.source('', key), inst.args[0]))
500 else:
494 else:
501 val = 'default', val
495 val = 'default', val
502 if ':' in val[1]:
496 if ':' in val[1]:
503 val = val[1].split(':', 1)
497 val = val[1].split(':', 1)
504 self.map[key] = val[0], os.path.join(self.base, val[1])
498 self.map[key] = val[0], os.path.join(self.base, val[1])
505
499
506 def __contains__(self, key):
500 def __contains__(self, key):
507 return key in self.cache or key in self.map
501 return key in self.cache or key in self.map
508
502
509 def load(self, t):
503 def load(self, t):
510 '''Get the template for the given template name. Use a local cache.'''
504 '''Get the template for the given template name. Use a local cache.'''
511 if t not in self.cache:
505 if t not in self.cache:
512 try:
506 try:
513 self.cache[t] = util.readfile(self.map[t][1])
507 self.cache[t] = util.readfile(self.map[t][1])
514 except KeyError, inst:
508 except KeyError, inst:
515 raise TemplateNotFound(_('"%s" not in template map') %
509 raise TemplateNotFound(_('"%s" not in template map') %
516 inst.args[0])
510 inst.args[0])
517 except IOError, inst:
511 except IOError, inst:
518 raise IOError(inst.args[0], _('template file %s: %s') %
512 raise IOError(inst.args[0], _('template file %s: %s') %
519 (self.map[t][1], inst.args[1]))
513 (self.map[t][1], inst.args[1]))
520 return self.cache[t]
514 return self.cache[t]
521
515
522 def __call__(self, t, **mapping):
516 def __call__(self, t, **mapping):
523 ttype = t in self.map and self.map[t][0] or 'default'
517 ttype = t in self.map and self.map[t][0] or 'default'
524 if ttype not in self.ecache:
518 if ttype not in self.ecache:
525 self.ecache[ttype] = engines[ttype](self.load,
519 self.ecache[ttype] = engines[ttype](self.load,
526 self.filters, self.defaults)
520 self.filters, self.defaults)
527 proc = self.ecache[ttype]
521 proc = self.ecache[ttype]
528
522
529 stream = proc.process(t, mapping)
523 stream = proc.process(t, mapping)
530 if self.minchunk:
524 if self.minchunk:
531 stream = util.increasingchunks(stream, min=self.minchunk,
525 stream = util.increasingchunks(stream, min=self.minchunk,
532 max=self.maxchunk)
526 max=self.maxchunk)
533 return stream
527 return stream
534
528
535 def templatepath(name=None):
529 def templatepath(name=None):
536 '''return location of template file or directory (if no name).
530 '''return location of template file or directory (if no name).
537 returns None if not found.'''
531 returns None if not found.'''
538 normpaths = []
532 normpaths = []
539
533
540 # executable version (py2exe) doesn't support __file__
534 # executable version (py2exe) doesn't support __file__
541 if util.mainfrozen():
535 if util.mainfrozen():
542 module = sys.executable
536 module = sys.executable
543 else:
537 else:
544 module = __file__
538 module = __file__
545 for f in path:
539 for f in path:
546 if f.startswith('/'):
540 if f.startswith('/'):
547 p = f
541 p = f
548 else:
542 else:
549 fl = f.split('/')
543 fl = f.split('/')
550 p = os.path.join(os.path.dirname(module), *fl)
544 p = os.path.join(os.path.dirname(module), *fl)
551 if name:
545 if name:
552 p = os.path.join(p, name)
546 p = os.path.join(p, name)
553 if name and os.path.exists(p):
547 if name and os.path.exists(p):
554 return os.path.normpath(p)
548 return os.path.normpath(p)
555 elif os.path.isdir(p):
549 elif os.path.isdir(p):
556 normpaths.append(os.path.normpath(p))
550 normpaths.append(os.path.normpath(p))
557
551
558 return normpaths
552 return normpaths
559
553
560 def stylemap(styles, paths=None):
554 def stylemap(styles, paths=None):
561 """Return path to mapfile for a given style.
555 """Return path to mapfile for a given style.
562
556
563 Searches mapfile in the following locations:
557 Searches mapfile in the following locations:
564 1. templatepath/style/map
558 1. templatepath/style/map
565 2. templatepath/map-style
559 2. templatepath/map-style
566 3. templatepath/map
560 3. templatepath/map
567 """
561 """
568
562
569 if paths is None:
563 if paths is None:
570 paths = templatepath()
564 paths = templatepath()
571 elif isinstance(paths, str):
565 elif isinstance(paths, str):
572 paths = [paths]
566 paths = [paths]
573
567
574 if isinstance(styles, str):
568 if isinstance(styles, str):
575 styles = [styles]
569 styles = [styles]
576
570
577 for style in styles:
571 for style in styles:
578 if not style:
572 if not style:
579 continue
573 continue
580 locations = [os.path.join(style, 'map'), 'map-' + style]
574 locations = [os.path.join(style, 'map'), 'map-' + style]
581 locations.append('map')
575 locations.append('map')
582
576
583 for path in paths:
577 for path in paths:
584 for location in locations:
578 for location in locations:
585 mapfile = os.path.join(path, location)
579 mapfile = os.path.join(path, location)
586 if os.path.isfile(mapfile):
580 if os.path.isfile(mapfile):
587 return style, mapfile
581 return style, mapfile
588
582
589 raise RuntimeError("No hgweb templates found in %r" % paths)
583 raise RuntimeError("No hgweb templates found in %r" % paths)
@@ -1,1628 +1,1661 b''
1 $ hg init a
1 $ hg init a
2 $ cd a
2 $ cd a
3 $ echo a > a
3 $ echo a > a
4 $ hg add a
4 $ hg add a
5 $ echo line 1 > b
5 $ echo line 1 > b
6 $ echo line 2 >> b
6 $ echo line 2 >> b
7 $ hg commit -l b -d '1000000 0' -u 'User Name <user@hostname>'
7 $ hg commit -l b -d '1000000 0' -u 'User Name <user@hostname>'
8
8
9 $ hg add b
9 $ hg add b
10 $ echo other 1 > c
10 $ echo other 1 > c
11 $ echo other 2 >> c
11 $ echo other 2 >> c
12 $ echo >> c
12 $ echo >> c
13 $ echo other 3 >> c
13 $ echo other 3 >> c
14 $ hg commit -l c -d '1100000 0' -u 'A. N. Other <other@place>'
14 $ hg commit -l c -d '1100000 0' -u 'A. N. Other <other@place>'
15
15
16 $ hg add c
16 $ hg add c
17 $ hg commit -m 'no person' -d '1200000 0' -u 'other@place'
17 $ hg commit -m 'no person' -d '1200000 0' -u 'other@place'
18 $ echo c >> c
18 $ echo c >> c
19 $ hg commit -m 'no user, no domain' -d '1300000 0' -u 'person'
19 $ hg commit -m 'no user, no domain' -d '1300000 0' -u 'person'
20
20
21 $ echo foo > .hg/branch
21 $ echo foo > .hg/branch
22 $ hg commit -m 'new branch' -d '1400000 0' -u 'person'
22 $ hg commit -m 'new branch' -d '1400000 0' -u 'person'
23
23
24 $ hg co -q 3
24 $ hg co -q 3
25 $ echo other 4 >> d
25 $ echo other 4 >> d
26 $ hg add d
26 $ hg add d
27 $ hg commit -m 'new head' -d '1500000 0' -u 'person'
27 $ hg commit -m 'new head' -d '1500000 0' -u 'person'
28
28
29 $ hg merge -q foo
29 $ hg merge -q foo
30 $ hg commit -m 'merge' -d '1500001 0' -u 'person'
30 $ hg commit -m 'merge' -d '1500001 0' -u 'person'
31
31
32 Second branch starting at nullrev:
32 Second branch starting at nullrev:
33
33
34 $ hg update null
34 $ hg update null
35 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
35 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
36 $ echo second > second
36 $ echo second > second
37 $ hg add second
37 $ hg add second
38 $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
38 $ hg commit -m second -d '1000000 0' -u 'User Name <user@hostname>'
39 created new head
39 created new head
40
40
41 $ echo third > third
41 $ echo third > third
42 $ hg add third
42 $ hg add third
43 $ hg mv second fourth
43 $ hg mv second fourth
44 $ hg commit -m third -d "2020-01-01 10:01"
44 $ hg commit -m third -d "2020-01-01 10:01"
45
45
46 $ hg log --template '{join(file_copies, ",\n")}\n' -r .
46 $ hg log --template '{join(file_copies, ",\n")}\n' -r .
47 fourth (second)
47 fourth (second)
48 $ hg log --template '{file_copies % "{source} -> {name}\n"}' -r .
48 $ hg log --template '{file_copies % "{source} -> {name}\n"}' -r .
49 second -> fourth
49 second -> fourth
50
50
51 Quoting for ui.logtemplate
51 Quoting for ui.logtemplate
52
52
53 $ hg tip --config "ui.logtemplate={rev}\n"
53 $ hg tip --config "ui.logtemplate={rev}\n"
54 8
54 8
55 $ hg tip --config "ui.logtemplate='{rev}\n'"
55 $ hg tip --config "ui.logtemplate='{rev}\n'"
56 8
56 8
57 $ hg tip --config 'ui.logtemplate="{rev}\n"'
57 $ hg tip --config 'ui.logtemplate="{rev}\n"'
58 8
58 8
59
59
60 Make sure user/global hgrc does not affect tests
60 Make sure user/global hgrc does not affect tests
61
61
62 $ echo '[ui]' > .hg/hgrc
62 $ echo '[ui]' > .hg/hgrc
63 $ echo 'logtemplate =' >> .hg/hgrc
63 $ echo 'logtemplate =' >> .hg/hgrc
64 $ echo 'style =' >> .hg/hgrc
64 $ echo 'style =' >> .hg/hgrc
65
65
66 Default style is like normal output:
66 Default style is like normal output:
67
67
68 $ hg log > log.out
68 $ hg log > log.out
69 $ hg log --style default > style.out
69 $ hg log --style default > style.out
70 $ cmp log.out style.out || diff -u log.out style.out
70 $ cmp log.out style.out || diff -u log.out style.out
71
71
72 $ hg log -v > log.out
72 $ hg log -v > log.out
73 $ hg log -v --style default > style.out
73 $ hg log -v --style default > style.out
74 $ cmp log.out style.out || diff -u log.out style.out
74 $ cmp log.out style.out || diff -u log.out style.out
75
75
76 $ hg log --debug > log.out
76 $ hg log --debug > log.out
77 $ hg log --debug --style default > style.out
77 $ hg log --debug --style default > style.out
78 $ cmp log.out style.out || diff -u log.out style.out
78 $ cmp log.out style.out || diff -u log.out style.out
79
79
80 Revision with no copies (used to print a traceback):
80 Revision with no copies (used to print a traceback):
81
81
82 $ hg tip -v --template '\n'
82 $ hg tip -v --template '\n'
83
83
84
84
85 Compact style works:
85 Compact style works:
86
86
87 $ hg log --style compact
87 $ hg log --style compact
88 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
88 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
89 third
89 third
90
90
91 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
91 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
92 second
92 second
93
93
94 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
94 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
95 merge
95 merge
96
96
97 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
97 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
98 new head
98 new head
99
99
100 4 bbe44766e73d 1970-01-17 04:53 +0000 person
100 4 bbe44766e73d 1970-01-17 04:53 +0000 person
101 new branch
101 new branch
102
102
103 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
103 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
104 no user, no domain
104 no user, no domain
105
105
106 2 97054abb4ab8 1970-01-14 21:20 +0000 other
106 2 97054abb4ab8 1970-01-14 21:20 +0000 other
107 no person
107 no person
108
108
109 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
109 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
110 other 1
110 other 1
111
111
112 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
112 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
113 line 1
113 line 1
114
114
115
115
116 $ hg log -v --style compact
116 $ hg log -v --style compact
117 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
117 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
118 third
118 third
119
119
120 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
120 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
121 second
121 second
122
122
123 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
123 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
124 merge
124 merge
125
125
126 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
126 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
127 new head
127 new head
128
128
129 4 bbe44766e73d 1970-01-17 04:53 +0000 person
129 4 bbe44766e73d 1970-01-17 04:53 +0000 person
130 new branch
130 new branch
131
131
132 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
132 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
133 no user, no domain
133 no user, no domain
134
134
135 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
135 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
136 no person
136 no person
137
137
138 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
138 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
139 other 1
139 other 1
140 other 2
140 other 2
141
141
142 other 3
142 other 3
143
143
144 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
144 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
145 line 1
145 line 1
146 line 2
146 line 2
147
147
148
148
149 $ hg log --debug --style compact
149 $ hg log --debug --style compact
150 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
150 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
151 third
151 third
152
152
153 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
153 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
154 second
154 second
155
155
156 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
156 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
157 merge
157 merge
158
158
159 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
159 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
160 new head
160 new head
161
161
162 4:3,-1 bbe44766e73d 1970-01-17 04:53 +0000 person
162 4:3,-1 bbe44766e73d 1970-01-17 04:53 +0000 person
163 new branch
163 new branch
164
164
165 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
165 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
166 no user, no domain
166 no user, no domain
167
167
168 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
168 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
169 no person
169 no person
170
170
171 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
171 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
172 other 1
172 other 1
173 other 2
173 other 2
174
174
175 other 3
175 other 3
176
176
177 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
177 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
178 line 1
178 line 1
179 line 2
179 line 2
180
180
181
181
182 Test xml styles:
182 Test xml styles:
183
183
184 $ hg log --style xml
184 $ hg log --style xml
185 <?xml version="1.0"?>
185 <?xml version="1.0"?>
186 <log>
186 <log>
187 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
187 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
188 <tag>tip</tag>
188 <tag>tip</tag>
189 <author email="test">test</author>
189 <author email="test">test</author>
190 <date>2020-01-01T10:01:00+00:00</date>
190 <date>2020-01-01T10:01:00+00:00</date>
191 <msg xml:space="preserve">third</msg>
191 <msg xml:space="preserve">third</msg>
192 </logentry>
192 </logentry>
193 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
193 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
194 <parent revision="-1" node="0000000000000000000000000000000000000000" />
194 <parent revision="-1" node="0000000000000000000000000000000000000000" />
195 <author email="user@hostname">User Name</author>
195 <author email="user@hostname">User Name</author>
196 <date>1970-01-12T13:46:40+00:00</date>
196 <date>1970-01-12T13:46:40+00:00</date>
197 <msg xml:space="preserve">second</msg>
197 <msg xml:space="preserve">second</msg>
198 </logentry>
198 </logentry>
199 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
199 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
200 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
200 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
201 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
201 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
202 <author email="person">person</author>
202 <author email="person">person</author>
203 <date>1970-01-18T08:40:01+00:00</date>
203 <date>1970-01-18T08:40:01+00:00</date>
204 <msg xml:space="preserve">merge</msg>
204 <msg xml:space="preserve">merge</msg>
205 </logentry>
205 </logentry>
206 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
206 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
207 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
207 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
208 <author email="person">person</author>
208 <author email="person">person</author>
209 <date>1970-01-18T08:40:00+00:00</date>
209 <date>1970-01-18T08:40:00+00:00</date>
210 <msg xml:space="preserve">new head</msg>
210 <msg xml:space="preserve">new head</msg>
211 </logentry>
211 </logentry>
212 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
212 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
213 <branch>foo</branch>
213 <branch>foo</branch>
214 <author email="person">person</author>
214 <author email="person">person</author>
215 <date>1970-01-17T04:53:20+00:00</date>
215 <date>1970-01-17T04:53:20+00:00</date>
216 <msg xml:space="preserve">new branch</msg>
216 <msg xml:space="preserve">new branch</msg>
217 </logentry>
217 </logentry>
218 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
218 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
219 <author email="person">person</author>
219 <author email="person">person</author>
220 <date>1970-01-16T01:06:40+00:00</date>
220 <date>1970-01-16T01:06:40+00:00</date>
221 <msg xml:space="preserve">no user, no domain</msg>
221 <msg xml:space="preserve">no user, no domain</msg>
222 </logentry>
222 </logentry>
223 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
223 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
224 <author email="other@place">other</author>
224 <author email="other@place">other</author>
225 <date>1970-01-14T21:20:00+00:00</date>
225 <date>1970-01-14T21:20:00+00:00</date>
226 <msg xml:space="preserve">no person</msg>
226 <msg xml:space="preserve">no person</msg>
227 </logentry>
227 </logentry>
228 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
228 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
229 <author email="other@place">A. N. Other</author>
229 <author email="other@place">A. N. Other</author>
230 <date>1970-01-13T17:33:20+00:00</date>
230 <date>1970-01-13T17:33:20+00:00</date>
231 <msg xml:space="preserve">other 1
231 <msg xml:space="preserve">other 1
232 other 2
232 other 2
233
233
234 other 3</msg>
234 other 3</msg>
235 </logentry>
235 </logentry>
236 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
236 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
237 <author email="user@hostname">User Name</author>
237 <author email="user@hostname">User Name</author>
238 <date>1970-01-12T13:46:40+00:00</date>
238 <date>1970-01-12T13:46:40+00:00</date>
239 <msg xml:space="preserve">line 1
239 <msg xml:space="preserve">line 1
240 line 2</msg>
240 line 2</msg>
241 </logentry>
241 </logentry>
242 </log>
242 </log>
243
243
244 $ hg log -v --style xml
244 $ hg log -v --style xml
245 <?xml version="1.0"?>
245 <?xml version="1.0"?>
246 <log>
246 <log>
247 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
247 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
248 <tag>tip</tag>
248 <tag>tip</tag>
249 <author email="test">test</author>
249 <author email="test">test</author>
250 <date>2020-01-01T10:01:00+00:00</date>
250 <date>2020-01-01T10:01:00+00:00</date>
251 <msg xml:space="preserve">third</msg>
251 <msg xml:space="preserve">third</msg>
252 <paths>
252 <paths>
253 <path action="A">fourth</path>
253 <path action="A">fourth</path>
254 <path action="A">third</path>
254 <path action="A">third</path>
255 <path action="R">second</path>
255 <path action="R">second</path>
256 </paths>
256 </paths>
257 <copies>
257 <copies>
258 <copy source="second">fourth</copy>
258 <copy source="second">fourth</copy>
259 </copies>
259 </copies>
260 </logentry>
260 </logentry>
261 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
261 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
262 <parent revision="-1" node="0000000000000000000000000000000000000000" />
262 <parent revision="-1" node="0000000000000000000000000000000000000000" />
263 <author email="user@hostname">User Name</author>
263 <author email="user@hostname">User Name</author>
264 <date>1970-01-12T13:46:40+00:00</date>
264 <date>1970-01-12T13:46:40+00:00</date>
265 <msg xml:space="preserve">second</msg>
265 <msg xml:space="preserve">second</msg>
266 <paths>
266 <paths>
267 <path action="A">second</path>
267 <path action="A">second</path>
268 </paths>
268 </paths>
269 </logentry>
269 </logentry>
270 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
270 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
271 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
271 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
272 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
272 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
273 <author email="person">person</author>
273 <author email="person">person</author>
274 <date>1970-01-18T08:40:01+00:00</date>
274 <date>1970-01-18T08:40:01+00:00</date>
275 <msg xml:space="preserve">merge</msg>
275 <msg xml:space="preserve">merge</msg>
276 <paths>
276 <paths>
277 </paths>
277 </paths>
278 </logentry>
278 </logentry>
279 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
279 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
280 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
280 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
281 <author email="person">person</author>
281 <author email="person">person</author>
282 <date>1970-01-18T08:40:00+00:00</date>
282 <date>1970-01-18T08:40:00+00:00</date>
283 <msg xml:space="preserve">new head</msg>
283 <msg xml:space="preserve">new head</msg>
284 <paths>
284 <paths>
285 <path action="A">d</path>
285 <path action="A">d</path>
286 </paths>
286 </paths>
287 </logentry>
287 </logentry>
288 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
288 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
289 <branch>foo</branch>
289 <branch>foo</branch>
290 <author email="person">person</author>
290 <author email="person">person</author>
291 <date>1970-01-17T04:53:20+00:00</date>
291 <date>1970-01-17T04:53:20+00:00</date>
292 <msg xml:space="preserve">new branch</msg>
292 <msg xml:space="preserve">new branch</msg>
293 <paths>
293 <paths>
294 </paths>
294 </paths>
295 </logentry>
295 </logentry>
296 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
296 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
297 <author email="person">person</author>
297 <author email="person">person</author>
298 <date>1970-01-16T01:06:40+00:00</date>
298 <date>1970-01-16T01:06:40+00:00</date>
299 <msg xml:space="preserve">no user, no domain</msg>
299 <msg xml:space="preserve">no user, no domain</msg>
300 <paths>
300 <paths>
301 <path action="M">c</path>
301 <path action="M">c</path>
302 </paths>
302 </paths>
303 </logentry>
303 </logentry>
304 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
304 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
305 <author email="other@place">other</author>
305 <author email="other@place">other</author>
306 <date>1970-01-14T21:20:00+00:00</date>
306 <date>1970-01-14T21:20:00+00:00</date>
307 <msg xml:space="preserve">no person</msg>
307 <msg xml:space="preserve">no person</msg>
308 <paths>
308 <paths>
309 <path action="A">c</path>
309 <path action="A">c</path>
310 </paths>
310 </paths>
311 </logentry>
311 </logentry>
312 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
312 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
313 <author email="other@place">A. N. Other</author>
313 <author email="other@place">A. N. Other</author>
314 <date>1970-01-13T17:33:20+00:00</date>
314 <date>1970-01-13T17:33:20+00:00</date>
315 <msg xml:space="preserve">other 1
315 <msg xml:space="preserve">other 1
316 other 2
316 other 2
317
317
318 other 3</msg>
318 other 3</msg>
319 <paths>
319 <paths>
320 <path action="A">b</path>
320 <path action="A">b</path>
321 </paths>
321 </paths>
322 </logentry>
322 </logentry>
323 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
323 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
324 <author email="user@hostname">User Name</author>
324 <author email="user@hostname">User Name</author>
325 <date>1970-01-12T13:46:40+00:00</date>
325 <date>1970-01-12T13:46:40+00:00</date>
326 <msg xml:space="preserve">line 1
326 <msg xml:space="preserve">line 1
327 line 2</msg>
327 line 2</msg>
328 <paths>
328 <paths>
329 <path action="A">a</path>
329 <path action="A">a</path>
330 </paths>
330 </paths>
331 </logentry>
331 </logentry>
332 </log>
332 </log>
333
333
334 $ hg log --debug --style xml
334 $ hg log --debug --style xml
335 <?xml version="1.0"?>
335 <?xml version="1.0"?>
336 <log>
336 <log>
337 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
337 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
338 <tag>tip</tag>
338 <tag>tip</tag>
339 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
339 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
340 <parent revision="-1" node="0000000000000000000000000000000000000000" />
340 <parent revision="-1" node="0000000000000000000000000000000000000000" />
341 <author email="test">test</author>
341 <author email="test">test</author>
342 <date>2020-01-01T10:01:00+00:00</date>
342 <date>2020-01-01T10:01:00+00:00</date>
343 <msg xml:space="preserve">third</msg>
343 <msg xml:space="preserve">third</msg>
344 <paths>
344 <paths>
345 <path action="A">fourth</path>
345 <path action="A">fourth</path>
346 <path action="A">third</path>
346 <path action="A">third</path>
347 <path action="R">second</path>
347 <path action="R">second</path>
348 </paths>
348 </paths>
349 <copies>
349 <copies>
350 <copy source="second">fourth</copy>
350 <copy source="second">fourth</copy>
351 </copies>
351 </copies>
352 <extra key="branch">default</extra>
352 <extra key="branch">default</extra>
353 </logentry>
353 </logentry>
354 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
354 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
355 <parent revision="-1" node="0000000000000000000000000000000000000000" />
355 <parent revision="-1" node="0000000000000000000000000000000000000000" />
356 <parent revision="-1" node="0000000000000000000000000000000000000000" />
356 <parent revision="-1" node="0000000000000000000000000000000000000000" />
357 <author email="user@hostname">User Name</author>
357 <author email="user@hostname">User Name</author>
358 <date>1970-01-12T13:46:40+00:00</date>
358 <date>1970-01-12T13:46:40+00:00</date>
359 <msg xml:space="preserve">second</msg>
359 <msg xml:space="preserve">second</msg>
360 <paths>
360 <paths>
361 <path action="A">second</path>
361 <path action="A">second</path>
362 </paths>
362 </paths>
363 <extra key="branch">default</extra>
363 <extra key="branch">default</extra>
364 </logentry>
364 </logentry>
365 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
365 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
366 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
366 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
367 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
367 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
368 <author email="person">person</author>
368 <author email="person">person</author>
369 <date>1970-01-18T08:40:01+00:00</date>
369 <date>1970-01-18T08:40:01+00:00</date>
370 <msg xml:space="preserve">merge</msg>
370 <msg xml:space="preserve">merge</msg>
371 <paths>
371 <paths>
372 </paths>
372 </paths>
373 <extra key="branch">default</extra>
373 <extra key="branch">default</extra>
374 </logentry>
374 </logentry>
375 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
375 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
376 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
376 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
377 <parent revision="-1" node="0000000000000000000000000000000000000000" />
377 <parent revision="-1" node="0000000000000000000000000000000000000000" />
378 <author email="person">person</author>
378 <author email="person">person</author>
379 <date>1970-01-18T08:40:00+00:00</date>
379 <date>1970-01-18T08:40:00+00:00</date>
380 <msg xml:space="preserve">new head</msg>
380 <msg xml:space="preserve">new head</msg>
381 <paths>
381 <paths>
382 <path action="A">d</path>
382 <path action="A">d</path>
383 </paths>
383 </paths>
384 <extra key="branch">default</extra>
384 <extra key="branch">default</extra>
385 </logentry>
385 </logentry>
386 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
386 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
387 <branch>foo</branch>
387 <branch>foo</branch>
388 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
388 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
389 <parent revision="-1" node="0000000000000000000000000000000000000000" />
389 <parent revision="-1" node="0000000000000000000000000000000000000000" />
390 <author email="person">person</author>
390 <author email="person">person</author>
391 <date>1970-01-17T04:53:20+00:00</date>
391 <date>1970-01-17T04:53:20+00:00</date>
392 <msg xml:space="preserve">new branch</msg>
392 <msg xml:space="preserve">new branch</msg>
393 <paths>
393 <paths>
394 </paths>
394 </paths>
395 <extra key="branch">foo</extra>
395 <extra key="branch">foo</extra>
396 </logentry>
396 </logentry>
397 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
397 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
398 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
398 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
399 <parent revision="-1" node="0000000000000000000000000000000000000000" />
399 <parent revision="-1" node="0000000000000000000000000000000000000000" />
400 <author email="person">person</author>
400 <author email="person">person</author>
401 <date>1970-01-16T01:06:40+00:00</date>
401 <date>1970-01-16T01:06:40+00:00</date>
402 <msg xml:space="preserve">no user, no domain</msg>
402 <msg xml:space="preserve">no user, no domain</msg>
403 <paths>
403 <paths>
404 <path action="M">c</path>
404 <path action="M">c</path>
405 </paths>
405 </paths>
406 <extra key="branch">default</extra>
406 <extra key="branch">default</extra>
407 </logentry>
407 </logentry>
408 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
408 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
409 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
409 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
410 <parent revision="-1" node="0000000000000000000000000000000000000000" />
410 <parent revision="-1" node="0000000000000000000000000000000000000000" />
411 <author email="other@place">other</author>
411 <author email="other@place">other</author>
412 <date>1970-01-14T21:20:00+00:00</date>
412 <date>1970-01-14T21:20:00+00:00</date>
413 <msg xml:space="preserve">no person</msg>
413 <msg xml:space="preserve">no person</msg>
414 <paths>
414 <paths>
415 <path action="A">c</path>
415 <path action="A">c</path>
416 </paths>
416 </paths>
417 <extra key="branch">default</extra>
417 <extra key="branch">default</extra>
418 </logentry>
418 </logentry>
419 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
419 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
420 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
420 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
421 <parent revision="-1" node="0000000000000000000000000000000000000000" />
421 <parent revision="-1" node="0000000000000000000000000000000000000000" />
422 <author email="other@place">A. N. Other</author>
422 <author email="other@place">A. N. Other</author>
423 <date>1970-01-13T17:33:20+00:00</date>
423 <date>1970-01-13T17:33:20+00:00</date>
424 <msg xml:space="preserve">other 1
424 <msg xml:space="preserve">other 1
425 other 2
425 other 2
426
426
427 other 3</msg>
427 other 3</msg>
428 <paths>
428 <paths>
429 <path action="A">b</path>
429 <path action="A">b</path>
430 </paths>
430 </paths>
431 <extra key="branch">default</extra>
431 <extra key="branch">default</extra>
432 </logentry>
432 </logentry>
433 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
433 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
434 <parent revision="-1" node="0000000000000000000000000000000000000000" />
434 <parent revision="-1" node="0000000000000000000000000000000000000000" />
435 <parent revision="-1" node="0000000000000000000000000000000000000000" />
435 <parent revision="-1" node="0000000000000000000000000000000000000000" />
436 <author email="user@hostname">User Name</author>
436 <author email="user@hostname">User Name</author>
437 <date>1970-01-12T13:46:40+00:00</date>
437 <date>1970-01-12T13:46:40+00:00</date>
438 <msg xml:space="preserve">line 1
438 <msg xml:space="preserve">line 1
439 line 2</msg>
439 line 2</msg>
440 <paths>
440 <paths>
441 <path action="A">a</path>
441 <path action="A">a</path>
442 </paths>
442 </paths>
443 <extra key="branch">default</extra>
443 <extra key="branch">default</extra>
444 </logentry>
444 </logentry>
445 </log>
445 </log>
446
446
447
447
448 Error if style not readable:
448 Error if style not readable:
449
449
450 #if unix-permissions no-root
450 #if unix-permissions no-root
451 $ touch q
451 $ touch q
452 $ chmod 0 q
452 $ chmod 0 q
453 $ hg log --style ./q
453 $ hg log --style ./q
454 abort: Permission denied: ./q
454 abort: Permission denied: ./q
455 [255]
455 [255]
456 #endif
456 #endif
457
457
458 Error if no style:
458 Error if no style:
459
459
460 $ hg log --style notexist
460 $ hg log --style notexist
461 abort: style 'notexist' not found
461 abort: style 'notexist' not found
462 (available styles: bisect, changelog, compact, default, phases, xml)
462 (available styles: bisect, changelog, compact, default, phases, xml)
463 [255]
463 [255]
464
464
465 Error if style missing key:
465 Error if style missing key:
466
466
467 $ echo 'q = q' > t
467 $ echo 'q = q' > t
468 $ hg log --style ./t
468 $ hg log --style ./t
469 abort: "changeset" not in template map
469 abort: "changeset" not in template map
470 [255]
470 [255]
471
471
472 Error if style missing value:
472 Error if style missing value:
473
473
474 $ echo 'changeset =' > t
474 $ echo 'changeset =' > t
475 $ hg log --style t
475 $ hg log --style t
476 abort: t:1: missing value
476 abort: t:1: missing value
477 [255]
477 [255]
478
478
479 Error if include fails:
479 Error if include fails:
480
480
481 $ echo 'changeset = q' >> t
481 $ echo 'changeset = q' >> t
482 #if unix-permissions no-root
482 #if unix-permissions no-root
483 $ hg log --style ./t
483 $ hg log --style ./t
484 abort: template file ./q: Permission denied
484 abort: template file ./q: Permission denied
485 [255]
485 [255]
486 $ rm q
486 $ rm q
487 #endif
487 #endif
488
488
489 Include works:
489 Include works:
490
490
491 $ echo '{rev}' > q
491 $ echo '{rev}' > q
492 $ hg log --style ./t
492 $ hg log --style ./t
493 8
493 8
494 7
494 7
495 6
495 6
496 5
496 5
497 4
497 4
498 3
498 3
499 2
499 2
500 1
500 1
501 0
501 0
502
502
503 Missing non-standard names give no error (backward compatibility):
503 Missing non-standard names give no error (backward compatibility):
504
504
505 $ echo "changeset = '{c}'" > t
505 $ echo "changeset = '{c}'" > t
506 $ hg log --style ./t
506 $ hg log --style ./t
507
507
508 Defining non-standard name works:
508 Defining non-standard name works:
509
509
510 $ cat <<EOF > t
510 $ cat <<EOF > t
511 > changeset = '{c}'
511 > changeset = '{c}'
512 > c = q
512 > c = q
513 > EOF
513 > EOF
514 $ hg log --style ./t
514 $ hg log --style ./t
515 8
515 8
516 7
516 7
517 6
517 6
518 5
518 5
519 4
519 4
520 3
520 3
521 2
521 2
522 1
522 1
523 0
523 0
524
524
525 ui.style works:
525 ui.style works:
526
526
527 $ echo '[ui]' > .hg/hgrc
527 $ echo '[ui]' > .hg/hgrc
528 $ echo 'style = t' >> .hg/hgrc
528 $ echo 'style = t' >> .hg/hgrc
529 $ hg log
529 $ hg log
530 8
530 8
531 7
531 7
532 6
532 6
533 5
533 5
534 4
534 4
535 3
535 3
536 2
536 2
537 1
537 1
538 0
538 0
539
539
540
540
541 Issue338:
541 Issue338:
542
542
543 $ hg log --style=changelog > changelog
543 $ hg log --style=changelog > changelog
544
544
545 $ cat changelog
545 $ cat changelog
546 2020-01-01 test <test>
546 2020-01-01 test <test>
547
547
548 * fourth, second, third:
548 * fourth, second, third:
549 third
549 third
550 [95c24699272e] [tip]
550 [95c24699272e] [tip]
551
551
552 1970-01-12 User Name <user@hostname>
552 1970-01-12 User Name <user@hostname>
553
553
554 * second:
554 * second:
555 second
555 second
556 [29114dbae42b]
556 [29114dbae42b]
557
557
558 1970-01-18 person <person>
558 1970-01-18 person <person>
559
559
560 * merge
560 * merge
561 [d41e714fe50d]
561 [d41e714fe50d]
562
562
563 * d:
563 * d:
564 new head
564 new head
565 [13207e5a10d9]
565 [13207e5a10d9]
566
566
567 1970-01-17 person <person>
567 1970-01-17 person <person>
568
568
569 * new branch
569 * new branch
570 [bbe44766e73d] <foo>
570 [bbe44766e73d] <foo>
571
571
572 1970-01-16 person <person>
572 1970-01-16 person <person>
573
573
574 * c:
574 * c:
575 no user, no domain
575 no user, no domain
576 [10e46f2dcbf4]
576 [10e46f2dcbf4]
577
577
578 1970-01-14 other <other@place>
578 1970-01-14 other <other@place>
579
579
580 * c:
580 * c:
581 no person
581 no person
582 [97054abb4ab8]
582 [97054abb4ab8]
583
583
584 1970-01-13 A. N. Other <other@place>
584 1970-01-13 A. N. Other <other@place>
585
585
586 * b:
586 * b:
587 other 1 other 2
587 other 1 other 2
588
588
589 other 3
589 other 3
590 [b608e9d1a3f0]
590 [b608e9d1a3f0]
591
591
592 1970-01-12 User Name <user@hostname>
592 1970-01-12 User Name <user@hostname>
593
593
594 * a:
594 * a:
595 line 1 line 2
595 line 1 line 2
596 [1e4e1b8f71e0]
596 [1e4e1b8f71e0]
597
597
598
598
599 Issue2130: xml output for 'hg heads' is malformed
599 Issue2130: xml output for 'hg heads' is malformed
600
600
601 $ hg heads --style changelog
601 $ hg heads --style changelog
602 2020-01-01 test <test>
602 2020-01-01 test <test>
603
603
604 * fourth, second, third:
604 * fourth, second, third:
605 third
605 third
606 [95c24699272e] [tip]
606 [95c24699272e] [tip]
607
607
608 1970-01-18 person <person>
608 1970-01-18 person <person>
609
609
610 * merge
610 * merge
611 [d41e714fe50d]
611 [d41e714fe50d]
612
612
613 1970-01-17 person <person>
613 1970-01-17 person <person>
614
614
615 * new branch
615 * new branch
616 [bbe44766e73d] <foo>
616 [bbe44766e73d] <foo>
617
617
618
618
619 Keys work:
619 Keys work:
620
620
621 $ for key in author branch branches date desc file_adds file_dels file_mods \
621 $ for key in author branch branches date desc file_adds file_dels file_mods \
622 > file_copies file_copies_switch files \
622 > file_copies file_copies_switch files \
623 > manifest node parents rev tags diffstat extras \
623 > manifest node parents rev tags diffstat extras \
624 > p1rev p2rev p1node p2node; do
624 > p1rev p2rev p1node p2node; do
625 > for mode in '' --verbose --debug; do
625 > for mode in '' --verbose --debug; do
626 > hg log $mode --template "$key$mode: {$key}\n"
626 > hg log $mode --template "$key$mode: {$key}\n"
627 > done
627 > done
628 > done
628 > done
629 author: test
629 author: test
630 author: User Name <user@hostname>
630 author: User Name <user@hostname>
631 author: person
631 author: person
632 author: person
632 author: person
633 author: person
633 author: person
634 author: person
634 author: person
635 author: other@place
635 author: other@place
636 author: A. N. Other <other@place>
636 author: A. N. Other <other@place>
637 author: User Name <user@hostname>
637 author: User Name <user@hostname>
638 author--verbose: test
638 author--verbose: test
639 author--verbose: User Name <user@hostname>
639 author--verbose: User Name <user@hostname>
640 author--verbose: person
640 author--verbose: person
641 author--verbose: person
641 author--verbose: person
642 author--verbose: person
642 author--verbose: person
643 author--verbose: person
643 author--verbose: person
644 author--verbose: other@place
644 author--verbose: other@place
645 author--verbose: A. N. Other <other@place>
645 author--verbose: A. N. Other <other@place>
646 author--verbose: User Name <user@hostname>
646 author--verbose: User Name <user@hostname>
647 author--debug: test
647 author--debug: test
648 author--debug: User Name <user@hostname>
648 author--debug: User Name <user@hostname>
649 author--debug: person
649 author--debug: person
650 author--debug: person
650 author--debug: person
651 author--debug: person
651 author--debug: person
652 author--debug: person
652 author--debug: person
653 author--debug: other@place
653 author--debug: other@place
654 author--debug: A. N. Other <other@place>
654 author--debug: A. N. Other <other@place>
655 author--debug: User Name <user@hostname>
655 author--debug: User Name <user@hostname>
656 branch: default
656 branch: default
657 branch: default
657 branch: default
658 branch: default
658 branch: default
659 branch: default
659 branch: default
660 branch: foo
660 branch: foo
661 branch: default
661 branch: default
662 branch: default
662 branch: default
663 branch: default
663 branch: default
664 branch: default
664 branch: default
665 branch--verbose: default
665 branch--verbose: default
666 branch--verbose: default
666 branch--verbose: default
667 branch--verbose: default
667 branch--verbose: default
668 branch--verbose: default
668 branch--verbose: default
669 branch--verbose: foo
669 branch--verbose: foo
670 branch--verbose: default
670 branch--verbose: default
671 branch--verbose: default
671 branch--verbose: default
672 branch--verbose: default
672 branch--verbose: default
673 branch--verbose: default
673 branch--verbose: default
674 branch--debug: default
674 branch--debug: default
675 branch--debug: default
675 branch--debug: default
676 branch--debug: default
676 branch--debug: default
677 branch--debug: default
677 branch--debug: default
678 branch--debug: foo
678 branch--debug: foo
679 branch--debug: default
679 branch--debug: default
680 branch--debug: default
680 branch--debug: default
681 branch--debug: default
681 branch--debug: default
682 branch--debug: default
682 branch--debug: default
683 branches:
683 branches:
684 branches:
684 branches:
685 branches:
685 branches:
686 branches:
686 branches:
687 branches: foo
687 branches: foo
688 branches:
688 branches:
689 branches:
689 branches:
690 branches:
690 branches:
691 branches:
691 branches:
692 branches--verbose:
692 branches--verbose:
693 branches--verbose:
693 branches--verbose:
694 branches--verbose:
694 branches--verbose:
695 branches--verbose:
695 branches--verbose:
696 branches--verbose: foo
696 branches--verbose: foo
697 branches--verbose:
697 branches--verbose:
698 branches--verbose:
698 branches--verbose:
699 branches--verbose:
699 branches--verbose:
700 branches--verbose:
700 branches--verbose:
701 branches--debug:
701 branches--debug:
702 branches--debug:
702 branches--debug:
703 branches--debug:
703 branches--debug:
704 branches--debug:
704 branches--debug:
705 branches--debug: foo
705 branches--debug: foo
706 branches--debug:
706 branches--debug:
707 branches--debug:
707 branches--debug:
708 branches--debug:
708 branches--debug:
709 branches--debug:
709 branches--debug:
710 date: 1577872860.00
710 date: 1577872860.00
711 date: 1000000.00
711 date: 1000000.00
712 date: 1500001.00
712 date: 1500001.00
713 date: 1500000.00
713 date: 1500000.00
714 date: 1400000.00
714 date: 1400000.00
715 date: 1300000.00
715 date: 1300000.00
716 date: 1200000.00
716 date: 1200000.00
717 date: 1100000.00
717 date: 1100000.00
718 date: 1000000.00
718 date: 1000000.00
719 date--verbose: 1577872860.00
719 date--verbose: 1577872860.00
720 date--verbose: 1000000.00
720 date--verbose: 1000000.00
721 date--verbose: 1500001.00
721 date--verbose: 1500001.00
722 date--verbose: 1500000.00
722 date--verbose: 1500000.00
723 date--verbose: 1400000.00
723 date--verbose: 1400000.00
724 date--verbose: 1300000.00
724 date--verbose: 1300000.00
725 date--verbose: 1200000.00
725 date--verbose: 1200000.00
726 date--verbose: 1100000.00
726 date--verbose: 1100000.00
727 date--verbose: 1000000.00
727 date--verbose: 1000000.00
728 date--debug: 1577872860.00
728 date--debug: 1577872860.00
729 date--debug: 1000000.00
729 date--debug: 1000000.00
730 date--debug: 1500001.00
730 date--debug: 1500001.00
731 date--debug: 1500000.00
731 date--debug: 1500000.00
732 date--debug: 1400000.00
732 date--debug: 1400000.00
733 date--debug: 1300000.00
733 date--debug: 1300000.00
734 date--debug: 1200000.00
734 date--debug: 1200000.00
735 date--debug: 1100000.00
735 date--debug: 1100000.00
736 date--debug: 1000000.00
736 date--debug: 1000000.00
737 desc: third
737 desc: third
738 desc: second
738 desc: second
739 desc: merge
739 desc: merge
740 desc: new head
740 desc: new head
741 desc: new branch
741 desc: new branch
742 desc: no user, no domain
742 desc: no user, no domain
743 desc: no person
743 desc: no person
744 desc: other 1
744 desc: other 1
745 other 2
745 other 2
746
746
747 other 3
747 other 3
748 desc: line 1
748 desc: line 1
749 line 2
749 line 2
750 desc--verbose: third
750 desc--verbose: third
751 desc--verbose: second
751 desc--verbose: second
752 desc--verbose: merge
752 desc--verbose: merge
753 desc--verbose: new head
753 desc--verbose: new head
754 desc--verbose: new branch
754 desc--verbose: new branch
755 desc--verbose: no user, no domain
755 desc--verbose: no user, no domain
756 desc--verbose: no person
756 desc--verbose: no person
757 desc--verbose: other 1
757 desc--verbose: other 1
758 other 2
758 other 2
759
759
760 other 3
760 other 3
761 desc--verbose: line 1
761 desc--verbose: line 1
762 line 2
762 line 2
763 desc--debug: third
763 desc--debug: third
764 desc--debug: second
764 desc--debug: second
765 desc--debug: merge
765 desc--debug: merge
766 desc--debug: new head
766 desc--debug: new head
767 desc--debug: new branch
767 desc--debug: new branch
768 desc--debug: no user, no domain
768 desc--debug: no user, no domain
769 desc--debug: no person
769 desc--debug: no person
770 desc--debug: other 1
770 desc--debug: other 1
771 other 2
771 other 2
772
772
773 other 3
773 other 3
774 desc--debug: line 1
774 desc--debug: line 1
775 line 2
775 line 2
776 file_adds: fourth third
776 file_adds: fourth third
777 file_adds: second
777 file_adds: second
778 file_adds:
778 file_adds:
779 file_adds: d
779 file_adds: d
780 file_adds:
780 file_adds:
781 file_adds:
781 file_adds:
782 file_adds: c
782 file_adds: c
783 file_adds: b
783 file_adds: b
784 file_adds: a
784 file_adds: a
785 file_adds--verbose: fourth third
785 file_adds--verbose: fourth third
786 file_adds--verbose: second
786 file_adds--verbose: second
787 file_adds--verbose:
787 file_adds--verbose:
788 file_adds--verbose: d
788 file_adds--verbose: d
789 file_adds--verbose:
789 file_adds--verbose:
790 file_adds--verbose:
790 file_adds--verbose:
791 file_adds--verbose: c
791 file_adds--verbose: c
792 file_adds--verbose: b
792 file_adds--verbose: b
793 file_adds--verbose: a
793 file_adds--verbose: a
794 file_adds--debug: fourth third
794 file_adds--debug: fourth third
795 file_adds--debug: second
795 file_adds--debug: second
796 file_adds--debug:
796 file_adds--debug:
797 file_adds--debug: d
797 file_adds--debug: d
798 file_adds--debug:
798 file_adds--debug:
799 file_adds--debug:
799 file_adds--debug:
800 file_adds--debug: c
800 file_adds--debug: c
801 file_adds--debug: b
801 file_adds--debug: b
802 file_adds--debug: a
802 file_adds--debug: a
803 file_dels: second
803 file_dels: second
804 file_dels:
804 file_dels:
805 file_dels:
805 file_dels:
806 file_dels:
806 file_dels:
807 file_dels:
807 file_dels:
808 file_dels:
808 file_dels:
809 file_dels:
809 file_dels:
810 file_dels:
810 file_dels:
811 file_dels:
811 file_dels:
812 file_dels--verbose: second
812 file_dels--verbose: second
813 file_dels--verbose:
813 file_dels--verbose:
814 file_dels--verbose:
814 file_dels--verbose:
815 file_dels--verbose:
815 file_dels--verbose:
816 file_dels--verbose:
816 file_dels--verbose:
817 file_dels--verbose:
817 file_dels--verbose:
818 file_dels--verbose:
818 file_dels--verbose:
819 file_dels--verbose:
819 file_dels--verbose:
820 file_dels--verbose:
820 file_dels--verbose:
821 file_dels--debug: second
821 file_dels--debug: second
822 file_dels--debug:
822 file_dels--debug:
823 file_dels--debug:
823 file_dels--debug:
824 file_dels--debug:
824 file_dels--debug:
825 file_dels--debug:
825 file_dels--debug:
826 file_dels--debug:
826 file_dels--debug:
827 file_dels--debug:
827 file_dels--debug:
828 file_dels--debug:
828 file_dels--debug:
829 file_dels--debug:
829 file_dels--debug:
830 file_mods:
830 file_mods:
831 file_mods:
831 file_mods:
832 file_mods:
832 file_mods:
833 file_mods:
833 file_mods:
834 file_mods:
834 file_mods:
835 file_mods: c
835 file_mods: c
836 file_mods:
836 file_mods:
837 file_mods:
837 file_mods:
838 file_mods:
838 file_mods:
839 file_mods--verbose:
839 file_mods--verbose:
840 file_mods--verbose:
840 file_mods--verbose:
841 file_mods--verbose:
841 file_mods--verbose:
842 file_mods--verbose:
842 file_mods--verbose:
843 file_mods--verbose:
843 file_mods--verbose:
844 file_mods--verbose: c
844 file_mods--verbose: c
845 file_mods--verbose:
845 file_mods--verbose:
846 file_mods--verbose:
846 file_mods--verbose:
847 file_mods--verbose:
847 file_mods--verbose:
848 file_mods--debug:
848 file_mods--debug:
849 file_mods--debug:
849 file_mods--debug:
850 file_mods--debug:
850 file_mods--debug:
851 file_mods--debug:
851 file_mods--debug:
852 file_mods--debug:
852 file_mods--debug:
853 file_mods--debug: c
853 file_mods--debug: c
854 file_mods--debug:
854 file_mods--debug:
855 file_mods--debug:
855 file_mods--debug:
856 file_mods--debug:
856 file_mods--debug:
857 file_copies: fourth (second)
857 file_copies: fourth (second)
858 file_copies:
858 file_copies:
859 file_copies:
859 file_copies:
860 file_copies:
860 file_copies:
861 file_copies:
861 file_copies:
862 file_copies:
862 file_copies:
863 file_copies:
863 file_copies:
864 file_copies:
864 file_copies:
865 file_copies:
865 file_copies:
866 file_copies--verbose: fourth (second)
866 file_copies--verbose: fourth (second)
867 file_copies--verbose:
867 file_copies--verbose:
868 file_copies--verbose:
868 file_copies--verbose:
869 file_copies--verbose:
869 file_copies--verbose:
870 file_copies--verbose:
870 file_copies--verbose:
871 file_copies--verbose:
871 file_copies--verbose:
872 file_copies--verbose:
872 file_copies--verbose:
873 file_copies--verbose:
873 file_copies--verbose:
874 file_copies--verbose:
874 file_copies--verbose:
875 file_copies--debug: fourth (second)
875 file_copies--debug: fourth (second)
876 file_copies--debug:
876 file_copies--debug:
877 file_copies--debug:
877 file_copies--debug:
878 file_copies--debug:
878 file_copies--debug:
879 file_copies--debug:
879 file_copies--debug:
880 file_copies--debug:
880 file_copies--debug:
881 file_copies--debug:
881 file_copies--debug:
882 file_copies--debug:
882 file_copies--debug:
883 file_copies--debug:
883 file_copies--debug:
884 file_copies_switch:
884 file_copies_switch:
885 file_copies_switch:
885 file_copies_switch:
886 file_copies_switch:
886 file_copies_switch:
887 file_copies_switch:
887 file_copies_switch:
888 file_copies_switch:
888 file_copies_switch:
889 file_copies_switch:
889 file_copies_switch:
890 file_copies_switch:
890 file_copies_switch:
891 file_copies_switch:
891 file_copies_switch:
892 file_copies_switch:
892 file_copies_switch:
893 file_copies_switch--verbose:
893 file_copies_switch--verbose:
894 file_copies_switch--verbose:
894 file_copies_switch--verbose:
895 file_copies_switch--verbose:
895 file_copies_switch--verbose:
896 file_copies_switch--verbose:
896 file_copies_switch--verbose:
897 file_copies_switch--verbose:
897 file_copies_switch--verbose:
898 file_copies_switch--verbose:
898 file_copies_switch--verbose:
899 file_copies_switch--verbose:
899 file_copies_switch--verbose:
900 file_copies_switch--verbose:
900 file_copies_switch--verbose:
901 file_copies_switch--verbose:
901 file_copies_switch--verbose:
902 file_copies_switch--debug:
902 file_copies_switch--debug:
903 file_copies_switch--debug:
903 file_copies_switch--debug:
904 file_copies_switch--debug:
904 file_copies_switch--debug:
905 file_copies_switch--debug:
905 file_copies_switch--debug:
906 file_copies_switch--debug:
906 file_copies_switch--debug:
907 file_copies_switch--debug:
907 file_copies_switch--debug:
908 file_copies_switch--debug:
908 file_copies_switch--debug:
909 file_copies_switch--debug:
909 file_copies_switch--debug:
910 file_copies_switch--debug:
910 file_copies_switch--debug:
911 files: fourth second third
911 files: fourth second third
912 files: second
912 files: second
913 files:
913 files:
914 files: d
914 files: d
915 files:
915 files:
916 files: c
916 files: c
917 files: c
917 files: c
918 files: b
918 files: b
919 files: a
919 files: a
920 files--verbose: fourth second third
920 files--verbose: fourth second third
921 files--verbose: second
921 files--verbose: second
922 files--verbose:
922 files--verbose:
923 files--verbose: d
923 files--verbose: d
924 files--verbose:
924 files--verbose:
925 files--verbose: c
925 files--verbose: c
926 files--verbose: c
926 files--verbose: c
927 files--verbose: b
927 files--verbose: b
928 files--verbose: a
928 files--verbose: a
929 files--debug: fourth second third
929 files--debug: fourth second third
930 files--debug: second
930 files--debug: second
931 files--debug:
931 files--debug:
932 files--debug: d
932 files--debug: d
933 files--debug:
933 files--debug:
934 files--debug: c
934 files--debug: c
935 files--debug: c
935 files--debug: c
936 files--debug: b
936 files--debug: b
937 files--debug: a
937 files--debug: a
938 manifest: 6:94961b75a2da
938 manifest: 6:94961b75a2da
939 manifest: 5:f2dbc354b94e
939 manifest: 5:f2dbc354b94e
940 manifest: 4:4dc3def4f9b4
940 manifest: 4:4dc3def4f9b4
941 manifest: 4:4dc3def4f9b4
941 manifest: 4:4dc3def4f9b4
942 manifest: 3:cb5a1327723b
942 manifest: 3:cb5a1327723b
943 manifest: 3:cb5a1327723b
943 manifest: 3:cb5a1327723b
944 manifest: 2:6e0e82995c35
944 manifest: 2:6e0e82995c35
945 manifest: 1:4e8d705b1e53
945 manifest: 1:4e8d705b1e53
946 manifest: 0:a0c8bcbbb45c
946 manifest: 0:a0c8bcbbb45c
947 manifest--verbose: 6:94961b75a2da
947 manifest--verbose: 6:94961b75a2da
948 manifest--verbose: 5:f2dbc354b94e
948 manifest--verbose: 5:f2dbc354b94e
949 manifest--verbose: 4:4dc3def4f9b4
949 manifest--verbose: 4:4dc3def4f9b4
950 manifest--verbose: 4:4dc3def4f9b4
950 manifest--verbose: 4:4dc3def4f9b4
951 manifest--verbose: 3:cb5a1327723b
951 manifest--verbose: 3:cb5a1327723b
952 manifest--verbose: 3:cb5a1327723b
952 manifest--verbose: 3:cb5a1327723b
953 manifest--verbose: 2:6e0e82995c35
953 manifest--verbose: 2:6e0e82995c35
954 manifest--verbose: 1:4e8d705b1e53
954 manifest--verbose: 1:4e8d705b1e53
955 manifest--verbose: 0:a0c8bcbbb45c
955 manifest--verbose: 0:a0c8bcbbb45c
956 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
956 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
957 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
957 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
958 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
958 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
959 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
959 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
960 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
960 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
961 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
961 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
962 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
962 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
963 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
963 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
964 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
964 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
965 node: 95c24699272ef57d062b8bccc32c878bf841784a
965 node: 95c24699272ef57d062b8bccc32c878bf841784a
966 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
966 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
967 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
967 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
968 node: 13207e5a10d9fd28ec424934298e176197f2c67f
968 node: 13207e5a10d9fd28ec424934298e176197f2c67f
969 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
969 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
970 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
970 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
971 node: 97054abb4ab824450e9164180baf491ae0078465
971 node: 97054abb4ab824450e9164180baf491ae0078465
972 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
972 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
973 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
973 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
974 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
974 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
975 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
975 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
976 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
976 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
977 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
977 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
978 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
978 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
979 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
979 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
980 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
980 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
981 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
981 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
982 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
982 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
983 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
983 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
984 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
984 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
985 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
985 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
986 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
986 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
987 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
987 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
988 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
988 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
989 node--debug: 97054abb4ab824450e9164180baf491ae0078465
989 node--debug: 97054abb4ab824450e9164180baf491ae0078465
990 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
990 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
991 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
991 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
992 parents:
992 parents:
993 parents: -1:000000000000
993 parents: -1:000000000000
994 parents: 5:13207e5a10d9 4:bbe44766e73d
994 parents: 5:13207e5a10d9 4:bbe44766e73d
995 parents: 3:10e46f2dcbf4
995 parents: 3:10e46f2dcbf4
996 parents:
996 parents:
997 parents:
997 parents:
998 parents:
998 parents:
999 parents:
999 parents:
1000 parents:
1000 parents:
1001 parents--verbose:
1001 parents--verbose:
1002 parents--verbose: -1:000000000000
1002 parents--verbose: -1:000000000000
1003 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
1003 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
1004 parents--verbose: 3:10e46f2dcbf4
1004 parents--verbose: 3:10e46f2dcbf4
1005 parents--verbose:
1005 parents--verbose:
1006 parents--verbose:
1006 parents--verbose:
1007 parents--verbose:
1007 parents--verbose:
1008 parents--verbose:
1008 parents--verbose:
1009 parents--verbose:
1009 parents--verbose:
1010 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
1010 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
1011 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1011 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1012 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
1012 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
1013 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1013 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1014 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1014 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1015 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
1015 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
1016 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
1016 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
1017 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
1017 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
1018 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1018 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1019 rev: 8
1019 rev: 8
1020 rev: 7
1020 rev: 7
1021 rev: 6
1021 rev: 6
1022 rev: 5
1022 rev: 5
1023 rev: 4
1023 rev: 4
1024 rev: 3
1024 rev: 3
1025 rev: 2
1025 rev: 2
1026 rev: 1
1026 rev: 1
1027 rev: 0
1027 rev: 0
1028 rev--verbose: 8
1028 rev--verbose: 8
1029 rev--verbose: 7
1029 rev--verbose: 7
1030 rev--verbose: 6
1030 rev--verbose: 6
1031 rev--verbose: 5
1031 rev--verbose: 5
1032 rev--verbose: 4
1032 rev--verbose: 4
1033 rev--verbose: 3
1033 rev--verbose: 3
1034 rev--verbose: 2
1034 rev--verbose: 2
1035 rev--verbose: 1
1035 rev--verbose: 1
1036 rev--verbose: 0
1036 rev--verbose: 0
1037 rev--debug: 8
1037 rev--debug: 8
1038 rev--debug: 7
1038 rev--debug: 7
1039 rev--debug: 6
1039 rev--debug: 6
1040 rev--debug: 5
1040 rev--debug: 5
1041 rev--debug: 4
1041 rev--debug: 4
1042 rev--debug: 3
1042 rev--debug: 3
1043 rev--debug: 2
1043 rev--debug: 2
1044 rev--debug: 1
1044 rev--debug: 1
1045 rev--debug: 0
1045 rev--debug: 0
1046 tags: tip
1046 tags: tip
1047 tags:
1047 tags:
1048 tags:
1048 tags:
1049 tags:
1049 tags:
1050 tags:
1050 tags:
1051 tags:
1051 tags:
1052 tags:
1052 tags:
1053 tags:
1053 tags:
1054 tags:
1054 tags:
1055 tags--verbose: tip
1055 tags--verbose: tip
1056 tags--verbose:
1056 tags--verbose:
1057 tags--verbose:
1057 tags--verbose:
1058 tags--verbose:
1058 tags--verbose:
1059 tags--verbose:
1059 tags--verbose:
1060 tags--verbose:
1060 tags--verbose:
1061 tags--verbose:
1061 tags--verbose:
1062 tags--verbose:
1062 tags--verbose:
1063 tags--verbose:
1063 tags--verbose:
1064 tags--debug: tip
1064 tags--debug: tip
1065 tags--debug:
1065 tags--debug:
1066 tags--debug:
1066 tags--debug:
1067 tags--debug:
1067 tags--debug:
1068 tags--debug:
1068 tags--debug:
1069 tags--debug:
1069 tags--debug:
1070 tags--debug:
1070 tags--debug:
1071 tags--debug:
1071 tags--debug:
1072 tags--debug:
1072 tags--debug:
1073 diffstat: 3: +2/-1
1073 diffstat: 3: +2/-1
1074 diffstat: 1: +1/-0
1074 diffstat: 1: +1/-0
1075 diffstat: 0: +0/-0
1075 diffstat: 0: +0/-0
1076 diffstat: 1: +1/-0
1076 diffstat: 1: +1/-0
1077 diffstat: 0: +0/-0
1077 diffstat: 0: +0/-0
1078 diffstat: 1: +1/-0
1078 diffstat: 1: +1/-0
1079 diffstat: 1: +4/-0
1079 diffstat: 1: +4/-0
1080 diffstat: 1: +2/-0
1080 diffstat: 1: +2/-0
1081 diffstat: 1: +1/-0
1081 diffstat: 1: +1/-0
1082 diffstat--verbose: 3: +2/-1
1082 diffstat--verbose: 3: +2/-1
1083 diffstat--verbose: 1: +1/-0
1083 diffstat--verbose: 1: +1/-0
1084 diffstat--verbose: 0: +0/-0
1084 diffstat--verbose: 0: +0/-0
1085 diffstat--verbose: 1: +1/-0
1085 diffstat--verbose: 1: +1/-0
1086 diffstat--verbose: 0: +0/-0
1086 diffstat--verbose: 0: +0/-0
1087 diffstat--verbose: 1: +1/-0
1087 diffstat--verbose: 1: +1/-0
1088 diffstat--verbose: 1: +4/-0
1088 diffstat--verbose: 1: +4/-0
1089 diffstat--verbose: 1: +2/-0
1089 diffstat--verbose: 1: +2/-0
1090 diffstat--verbose: 1: +1/-0
1090 diffstat--verbose: 1: +1/-0
1091 diffstat--debug: 3: +2/-1
1091 diffstat--debug: 3: +2/-1
1092 diffstat--debug: 1: +1/-0
1092 diffstat--debug: 1: +1/-0
1093 diffstat--debug: 0: +0/-0
1093 diffstat--debug: 0: +0/-0
1094 diffstat--debug: 1: +1/-0
1094 diffstat--debug: 1: +1/-0
1095 diffstat--debug: 0: +0/-0
1095 diffstat--debug: 0: +0/-0
1096 diffstat--debug: 1: +1/-0
1096 diffstat--debug: 1: +1/-0
1097 diffstat--debug: 1: +4/-0
1097 diffstat--debug: 1: +4/-0
1098 diffstat--debug: 1: +2/-0
1098 diffstat--debug: 1: +2/-0
1099 diffstat--debug: 1: +1/-0
1099 diffstat--debug: 1: +1/-0
1100 extras: branch=default
1100 extras: branch=default
1101 extras: branch=default
1101 extras: branch=default
1102 extras: branch=default
1102 extras: branch=default
1103 extras: branch=default
1103 extras: branch=default
1104 extras: branch=foo
1104 extras: branch=foo
1105 extras: branch=default
1105 extras: branch=default
1106 extras: branch=default
1106 extras: branch=default
1107 extras: branch=default
1107 extras: branch=default
1108 extras: branch=default
1108 extras: branch=default
1109 extras--verbose: branch=default
1109 extras--verbose: branch=default
1110 extras--verbose: branch=default
1110 extras--verbose: branch=default
1111 extras--verbose: branch=default
1111 extras--verbose: branch=default
1112 extras--verbose: branch=default
1112 extras--verbose: branch=default
1113 extras--verbose: branch=foo
1113 extras--verbose: branch=foo
1114 extras--verbose: branch=default
1114 extras--verbose: branch=default
1115 extras--verbose: branch=default
1115 extras--verbose: branch=default
1116 extras--verbose: branch=default
1116 extras--verbose: branch=default
1117 extras--verbose: branch=default
1117 extras--verbose: branch=default
1118 extras--debug: branch=default
1118 extras--debug: branch=default
1119 extras--debug: branch=default
1119 extras--debug: branch=default
1120 extras--debug: branch=default
1120 extras--debug: branch=default
1121 extras--debug: branch=default
1121 extras--debug: branch=default
1122 extras--debug: branch=foo
1122 extras--debug: branch=foo
1123 extras--debug: branch=default
1123 extras--debug: branch=default
1124 extras--debug: branch=default
1124 extras--debug: branch=default
1125 extras--debug: branch=default
1125 extras--debug: branch=default
1126 extras--debug: branch=default
1126 extras--debug: branch=default
1127 p1rev: 7
1127 p1rev: 7
1128 p1rev: -1
1128 p1rev: -1
1129 p1rev: 5
1129 p1rev: 5
1130 p1rev: 3
1130 p1rev: 3
1131 p1rev: 3
1131 p1rev: 3
1132 p1rev: 2
1132 p1rev: 2
1133 p1rev: 1
1133 p1rev: 1
1134 p1rev: 0
1134 p1rev: 0
1135 p1rev: -1
1135 p1rev: -1
1136 p1rev--verbose: 7
1136 p1rev--verbose: 7
1137 p1rev--verbose: -1
1137 p1rev--verbose: -1
1138 p1rev--verbose: 5
1138 p1rev--verbose: 5
1139 p1rev--verbose: 3
1139 p1rev--verbose: 3
1140 p1rev--verbose: 3
1140 p1rev--verbose: 3
1141 p1rev--verbose: 2
1141 p1rev--verbose: 2
1142 p1rev--verbose: 1
1142 p1rev--verbose: 1
1143 p1rev--verbose: 0
1143 p1rev--verbose: 0
1144 p1rev--verbose: -1
1144 p1rev--verbose: -1
1145 p1rev--debug: 7
1145 p1rev--debug: 7
1146 p1rev--debug: -1
1146 p1rev--debug: -1
1147 p1rev--debug: 5
1147 p1rev--debug: 5
1148 p1rev--debug: 3
1148 p1rev--debug: 3
1149 p1rev--debug: 3
1149 p1rev--debug: 3
1150 p1rev--debug: 2
1150 p1rev--debug: 2
1151 p1rev--debug: 1
1151 p1rev--debug: 1
1152 p1rev--debug: 0
1152 p1rev--debug: 0
1153 p1rev--debug: -1
1153 p1rev--debug: -1
1154 p2rev: -1
1154 p2rev: -1
1155 p2rev: -1
1155 p2rev: -1
1156 p2rev: 4
1156 p2rev: 4
1157 p2rev: -1
1157 p2rev: -1
1158 p2rev: -1
1158 p2rev: -1
1159 p2rev: -1
1159 p2rev: -1
1160 p2rev: -1
1160 p2rev: -1
1161 p2rev: -1
1161 p2rev: -1
1162 p2rev: -1
1162 p2rev: -1
1163 p2rev--verbose: -1
1163 p2rev--verbose: -1
1164 p2rev--verbose: -1
1164 p2rev--verbose: -1
1165 p2rev--verbose: 4
1165 p2rev--verbose: 4
1166 p2rev--verbose: -1
1166 p2rev--verbose: -1
1167 p2rev--verbose: -1
1167 p2rev--verbose: -1
1168 p2rev--verbose: -1
1168 p2rev--verbose: -1
1169 p2rev--verbose: -1
1169 p2rev--verbose: -1
1170 p2rev--verbose: -1
1170 p2rev--verbose: -1
1171 p2rev--verbose: -1
1171 p2rev--verbose: -1
1172 p2rev--debug: -1
1172 p2rev--debug: -1
1173 p2rev--debug: -1
1173 p2rev--debug: -1
1174 p2rev--debug: 4
1174 p2rev--debug: 4
1175 p2rev--debug: -1
1175 p2rev--debug: -1
1176 p2rev--debug: -1
1176 p2rev--debug: -1
1177 p2rev--debug: -1
1177 p2rev--debug: -1
1178 p2rev--debug: -1
1178 p2rev--debug: -1
1179 p2rev--debug: -1
1179 p2rev--debug: -1
1180 p2rev--debug: -1
1180 p2rev--debug: -1
1181 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1181 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1182 p1node: 0000000000000000000000000000000000000000
1182 p1node: 0000000000000000000000000000000000000000
1183 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
1183 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
1184 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1184 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1185 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1185 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1186 p1node: 97054abb4ab824450e9164180baf491ae0078465
1186 p1node: 97054abb4ab824450e9164180baf491ae0078465
1187 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1187 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1188 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1188 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1189 p1node: 0000000000000000000000000000000000000000
1189 p1node: 0000000000000000000000000000000000000000
1190 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1190 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1191 p1node--verbose: 0000000000000000000000000000000000000000
1191 p1node--verbose: 0000000000000000000000000000000000000000
1192 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1192 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1193 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1193 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1194 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1194 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1195 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1195 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1196 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1196 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1197 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1197 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1198 p1node--verbose: 0000000000000000000000000000000000000000
1198 p1node--verbose: 0000000000000000000000000000000000000000
1199 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1199 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1200 p1node--debug: 0000000000000000000000000000000000000000
1200 p1node--debug: 0000000000000000000000000000000000000000
1201 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1201 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1202 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1202 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1203 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1203 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1204 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
1204 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
1205 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1205 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1206 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1206 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1207 p1node--debug: 0000000000000000000000000000000000000000
1207 p1node--debug: 0000000000000000000000000000000000000000
1208 p2node: 0000000000000000000000000000000000000000
1208 p2node: 0000000000000000000000000000000000000000
1209 p2node: 0000000000000000000000000000000000000000
1209 p2node: 0000000000000000000000000000000000000000
1210 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1210 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1211 p2node: 0000000000000000000000000000000000000000
1211 p2node: 0000000000000000000000000000000000000000
1212 p2node: 0000000000000000000000000000000000000000
1212 p2node: 0000000000000000000000000000000000000000
1213 p2node: 0000000000000000000000000000000000000000
1213 p2node: 0000000000000000000000000000000000000000
1214 p2node: 0000000000000000000000000000000000000000
1214 p2node: 0000000000000000000000000000000000000000
1215 p2node: 0000000000000000000000000000000000000000
1215 p2node: 0000000000000000000000000000000000000000
1216 p2node: 0000000000000000000000000000000000000000
1216 p2node: 0000000000000000000000000000000000000000
1217 p2node--verbose: 0000000000000000000000000000000000000000
1217 p2node--verbose: 0000000000000000000000000000000000000000
1218 p2node--verbose: 0000000000000000000000000000000000000000
1218 p2node--verbose: 0000000000000000000000000000000000000000
1219 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1219 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1220 p2node--verbose: 0000000000000000000000000000000000000000
1220 p2node--verbose: 0000000000000000000000000000000000000000
1221 p2node--verbose: 0000000000000000000000000000000000000000
1221 p2node--verbose: 0000000000000000000000000000000000000000
1222 p2node--verbose: 0000000000000000000000000000000000000000
1222 p2node--verbose: 0000000000000000000000000000000000000000
1223 p2node--verbose: 0000000000000000000000000000000000000000
1223 p2node--verbose: 0000000000000000000000000000000000000000
1224 p2node--verbose: 0000000000000000000000000000000000000000
1224 p2node--verbose: 0000000000000000000000000000000000000000
1225 p2node--verbose: 0000000000000000000000000000000000000000
1225 p2node--verbose: 0000000000000000000000000000000000000000
1226 p2node--debug: 0000000000000000000000000000000000000000
1226 p2node--debug: 0000000000000000000000000000000000000000
1227 p2node--debug: 0000000000000000000000000000000000000000
1227 p2node--debug: 0000000000000000000000000000000000000000
1228 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1228 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1229 p2node--debug: 0000000000000000000000000000000000000000
1229 p2node--debug: 0000000000000000000000000000000000000000
1230 p2node--debug: 0000000000000000000000000000000000000000
1230 p2node--debug: 0000000000000000000000000000000000000000
1231 p2node--debug: 0000000000000000000000000000000000000000
1231 p2node--debug: 0000000000000000000000000000000000000000
1232 p2node--debug: 0000000000000000000000000000000000000000
1232 p2node--debug: 0000000000000000000000000000000000000000
1233 p2node--debug: 0000000000000000000000000000000000000000
1233 p2node--debug: 0000000000000000000000000000000000000000
1234 p2node--debug: 0000000000000000000000000000000000000000
1234 p2node--debug: 0000000000000000000000000000000000000000
1235
1235
1236 Filters work:
1236 Filters work:
1237
1237
1238 $ hg log --template '{author|domain}\n'
1238 $ hg log --template '{author|domain}\n'
1239
1239
1240 hostname
1240 hostname
1241
1241
1242
1242
1243
1243
1244
1244
1245 place
1245 place
1246 place
1246 place
1247 hostname
1247 hostname
1248
1248
1249 $ hg log --template '{author|person}\n'
1249 $ hg log --template '{author|person}\n'
1250 test
1250 test
1251 User Name
1251 User Name
1252 person
1252 person
1253 person
1253 person
1254 person
1254 person
1255 person
1255 person
1256 other
1256 other
1257 A. N. Other
1257 A. N. Other
1258 User Name
1258 User Name
1259
1259
1260 $ hg log --template '{author|user}\n'
1260 $ hg log --template '{author|user}\n'
1261 test
1261 test
1262 user
1262 user
1263 person
1263 person
1264 person
1264 person
1265 person
1265 person
1266 person
1266 person
1267 other
1267 other
1268 other
1268 other
1269 user
1269 user
1270
1270
1271 $ hg log --template '{date|date}\n'
1271 $ hg log --template '{date|date}\n'
1272 Wed Jan 01 10:01:00 2020 +0000
1272 Wed Jan 01 10:01:00 2020 +0000
1273 Mon Jan 12 13:46:40 1970 +0000
1273 Mon Jan 12 13:46:40 1970 +0000
1274 Sun Jan 18 08:40:01 1970 +0000
1274 Sun Jan 18 08:40:01 1970 +0000
1275 Sun Jan 18 08:40:00 1970 +0000
1275 Sun Jan 18 08:40:00 1970 +0000
1276 Sat Jan 17 04:53:20 1970 +0000
1276 Sat Jan 17 04:53:20 1970 +0000
1277 Fri Jan 16 01:06:40 1970 +0000
1277 Fri Jan 16 01:06:40 1970 +0000
1278 Wed Jan 14 21:20:00 1970 +0000
1278 Wed Jan 14 21:20:00 1970 +0000
1279 Tue Jan 13 17:33:20 1970 +0000
1279 Tue Jan 13 17:33:20 1970 +0000
1280 Mon Jan 12 13:46:40 1970 +0000
1280 Mon Jan 12 13:46:40 1970 +0000
1281
1281
1282 $ hg log --template '{date|isodate}\n'
1282 $ hg log --template '{date|isodate}\n'
1283 2020-01-01 10:01 +0000
1283 2020-01-01 10:01 +0000
1284 1970-01-12 13:46 +0000
1284 1970-01-12 13:46 +0000
1285 1970-01-18 08:40 +0000
1285 1970-01-18 08:40 +0000
1286 1970-01-18 08:40 +0000
1286 1970-01-18 08:40 +0000
1287 1970-01-17 04:53 +0000
1287 1970-01-17 04:53 +0000
1288 1970-01-16 01:06 +0000
1288 1970-01-16 01:06 +0000
1289 1970-01-14 21:20 +0000
1289 1970-01-14 21:20 +0000
1290 1970-01-13 17:33 +0000
1290 1970-01-13 17:33 +0000
1291 1970-01-12 13:46 +0000
1291 1970-01-12 13:46 +0000
1292
1292
1293 $ hg log --template '{date|isodatesec}\n'
1293 $ hg log --template '{date|isodatesec}\n'
1294 2020-01-01 10:01:00 +0000
1294 2020-01-01 10:01:00 +0000
1295 1970-01-12 13:46:40 +0000
1295 1970-01-12 13:46:40 +0000
1296 1970-01-18 08:40:01 +0000
1296 1970-01-18 08:40:01 +0000
1297 1970-01-18 08:40:00 +0000
1297 1970-01-18 08:40:00 +0000
1298 1970-01-17 04:53:20 +0000
1298 1970-01-17 04:53:20 +0000
1299 1970-01-16 01:06:40 +0000
1299 1970-01-16 01:06:40 +0000
1300 1970-01-14 21:20:00 +0000
1300 1970-01-14 21:20:00 +0000
1301 1970-01-13 17:33:20 +0000
1301 1970-01-13 17:33:20 +0000
1302 1970-01-12 13:46:40 +0000
1302 1970-01-12 13:46:40 +0000
1303
1303
1304 $ hg log --template '{date|rfc822date}\n'
1304 $ hg log --template '{date|rfc822date}\n'
1305 Wed, 01 Jan 2020 10:01:00 +0000
1305 Wed, 01 Jan 2020 10:01:00 +0000
1306 Mon, 12 Jan 1970 13:46:40 +0000
1306 Mon, 12 Jan 1970 13:46:40 +0000
1307 Sun, 18 Jan 1970 08:40:01 +0000
1307 Sun, 18 Jan 1970 08:40:01 +0000
1308 Sun, 18 Jan 1970 08:40:00 +0000
1308 Sun, 18 Jan 1970 08:40:00 +0000
1309 Sat, 17 Jan 1970 04:53:20 +0000
1309 Sat, 17 Jan 1970 04:53:20 +0000
1310 Fri, 16 Jan 1970 01:06:40 +0000
1310 Fri, 16 Jan 1970 01:06:40 +0000
1311 Wed, 14 Jan 1970 21:20:00 +0000
1311 Wed, 14 Jan 1970 21:20:00 +0000
1312 Tue, 13 Jan 1970 17:33:20 +0000
1312 Tue, 13 Jan 1970 17:33:20 +0000
1313 Mon, 12 Jan 1970 13:46:40 +0000
1313 Mon, 12 Jan 1970 13:46:40 +0000
1314
1314
1315 $ hg log --template '{desc|firstline}\n'
1315 $ hg log --template '{desc|firstline}\n'
1316 third
1316 third
1317 second
1317 second
1318 merge
1318 merge
1319 new head
1319 new head
1320 new branch
1320 new branch
1321 no user, no domain
1321 no user, no domain
1322 no person
1322 no person
1323 other 1
1323 other 1
1324 line 1
1324 line 1
1325
1325
1326 $ hg log --template '{node|short}\n'
1326 $ hg log --template '{node|short}\n'
1327 95c24699272e
1327 95c24699272e
1328 29114dbae42b
1328 29114dbae42b
1329 d41e714fe50d
1329 d41e714fe50d
1330 13207e5a10d9
1330 13207e5a10d9
1331 bbe44766e73d
1331 bbe44766e73d
1332 10e46f2dcbf4
1332 10e46f2dcbf4
1333 97054abb4ab8
1333 97054abb4ab8
1334 b608e9d1a3f0
1334 b608e9d1a3f0
1335 1e4e1b8f71e0
1335 1e4e1b8f71e0
1336
1336
1337 $ hg log --template '<changeset author="{author|xmlescape}"/>\n'
1337 $ hg log --template '<changeset author="{author|xmlescape}"/>\n'
1338 <changeset author="test"/>
1338 <changeset author="test"/>
1339 <changeset author="User Name &lt;user@hostname&gt;"/>
1339 <changeset author="User Name &lt;user@hostname&gt;"/>
1340 <changeset author="person"/>
1340 <changeset author="person"/>
1341 <changeset author="person"/>
1341 <changeset author="person"/>
1342 <changeset author="person"/>
1342 <changeset author="person"/>
1343 <changeset author="person"/>
1343 <changeset author="person"/>
1344 <changeset author="other@place"/>
1344 <changeset author="other@place"/>
1345 <changeset author="A. N. Other &lt;other@place&gt;"/>
1345 <changeset author="A. N. Other &lt;other@place&gt;"/>
1346 <changeset author="User Name &lt;user@hostname&gt;"/>
1346 <changeset author="User Name &lt;user@hostname&gt;"/>
1347
1347
1348 $ hg log --template '{rev}: {children}\n'
1348 $ hg log --template '{rev}: {children}\n'
1349 8:
1349 8:
1350 7: 8:95c24699272e
1350 7: 8:95c24699272e
1351 6:
1351 6:
1352 5: 6:d41e714fe50d
1352 5: 6:d41e714fe50d
1353 4: 6:d41e714fe50d
1353 4: 6:d41e714fe50d
1354 3: 4:bbe44766e73d 5:13207e5a10d9
1354 3: 4:bbe44766e73d 5:13207e5a10d9
1355 2: 3:10e46f2dcbf4
1355 2: 3:10e46f2dcbf4
1356 1: 2:97054abb4ab8
1356 1: 2:97054abb4ab8
1357 0: 1:b608e9d1a3f0
1357 0: 1:b608e9d1a3f0
1358
1358
1359 Formatnode filter works:
1359 Formatnode filter works:
1360
1360
1361 $ hg -q log -r 0 --template '{node|formatnode}\n'
1361 $ hg -q log -r 0 --template '{node|formatnode}\n'
1362 1e4e1b8f71e0
1362 1e4e1b8f71e0
1363
1363
1364 $ hg log -r 0 --template '{node|formatnode}\n'
1364 $ hg log -r 0 --template '{node|formatnode}\n'
1365 1e4e1b8f71e0
1365 1e4e1b8f71e0
1366
1366
1367 $ hg -v log -r 0 --template '{node|formatnode}\n'
1367 $ hg -v log -r 0 --template '{node|formatnode}\n'
1368 1e4e1b8f71e0
1368 1e4e1b8f71e0
1369
1369
1370 $ hg --debug log -r 0 --template '{node|formatnode}\n'
1370 $ hg --debug log -r 0 --template '{node|formatnode}\n'
1371 1e4e1b8f71e05681d422154f5421e385fec3454f
1371 1e4e1b8f71e05681d422154f5421e385fec3454f
1372
1372
1373 Age filter:
1373 Age filter:
1374
1374
1375 $ hg log --template '{date|age}\n' > /dev/null || exit 1
1375 $ hg log --template '{date|age}\n' > /dev/null || exit 1
1376
1376
1377 >>> from datetime import datetime, timedelta
1377 >>> from datetime import datetime, timedelta
1378 >>> fp = open('a', 'w')
1378 >>> fp = open('a', 'w')
1379 >>> n = datetime.now() + timedelta(366 * 7)
1379 >>> n = datetime.now() + timedelta(366 * 7)
1380 >>> fp.write('%d-%d-%d 00:00' % (n.year, n.month, n.day))
1380 >>> fp.write('%d-%d-%d 00:00' % (n.year, n.month, n.day))
1381 >>> fp.close()
1381 >>> fp.close()
1382 $ hg add a
1382 $ hg add a
1383 $ hg commit -m future -d "`cat a`"
1383 $ hg commit -m future -d "`cat a`"
1384
1384
1385 $ hg log -l1 --template '{date|age}\n'
1385 $ hg log -l1 --template '{date|age}\n'
1386 7 years from now
1386 7 years from now
1387
1387
1388 Error on syntax:
1388 Error on syntax:
1389
1389
1390 $ echo 'x = "f' >> t
1390 $ echo 'x = "f' >> t
1391 $ hg log
1391 $ hg log
1392 abort: t:3: unmatched quotes
1392 abort: t:3: unmatched quotes
1393 [255]
1393 [255]
1394
1394
1395 Behind the scenes, this will throw TypeError
1395 Behind the scenes, this will throw TypeError
1396
1396
1397 $ hg log -l 3 --template '{date|obfuscate}\n'
1397 $ hg log -l 3 --template '{date|obfuscate}\n'
1398 abort: template filter 'obfuscate' is not compatible with keyword 'date'
1398 abort: template filter 'obfuscate' is not compatible with keyword 'date'
1399 [255]
1399 [255]
1400
1400
1401 Behind the scenes, this will throw a ValueError
1401 Behind the scenes, this will throw a ValueError
1402
1402
1403 $ hg log -l 3 --template 'line: {desc|shortdate}\n'
1403 $ hg log -l 3 --template 'line: {desc|shortdate}\n'
1404 abort: template filter 'shortdate' is not compatible with keyword 'desc'
1404 abort: template filter 'shortdate' is not compatible with keyword 'desc'
1405 [255]
1405 [255]
1406
1406
1407 Behind the scenes, this will throw AttributeError
1407 Behind the scenes, this will throw AttributeError
1408
1408
1409 $ hg log -l 3 --template 'line: {date|escape}\n'
1409 $ hg log -l 3 --template 'line: {date|escape}\n'
1410 abort: template filter 'escape' is not compatible with keyword 'date'
1410 abort: template filter 'escape' is not compatible with keyword 'date'
1411 [255]
1411 [255]
1412
1412
1413 Behind the scenes, this will throw ValueError
1413 Behind the scenes, this will throw ValueError
1414
1414
1415 $ hg tip --template '{author|email|date}\n'
1415 $ hg tip --template '{author|email|date}\n'
1416 abort: template filter 'datefilter' is not compatible with keyword 'author'
1416 abort: template filter 'datefilter' is not compatible with keyword 'author'
1417 [255]
1417 [255]
1418
1418
1419 $ cd ..
1419 $ cd ..
1420
1420
1421
1421
1422 latesttag:
1422 latesttag:
1423
1423
1424 $ hg init latesttag
1424 $ hg init latesttag
1425 $ cd latesttag
1425 $ cd latesttag
1426
1426
1427 $ echo a > file
1427 $ echo a > file
1428 $ hg ci -Am a -d '0 0'
1428 $ hg ci -Am a -d '0 0'
1429 adding file
1429 adding file
1430
1430
1431 $ echo b >> file
1431 $ echo b >> file
1432 $ hg ci -m b -d '1 0'
1432 $ hg ci -m b -d '1 0'
1433
1433
1434 $ echo c >> head1
1434 $ echo c >> head1
1435 $ hg ci -Am h1c -d '2 0'
1435 $ hg ci -Am h1c -d '2 0'
1436 adding head1
1436 adding head1
1437
1437
1438 $ hg update -q 1
1438 $ hg update -q 1
1439 $ echo d >> head2
1439 $ echo d >> head2
1440 $ hg ci -Am h2d -d '3 0'
1440 $ hg ci -Am h2d -d '3 0'
1441 adding head2
1441 adding head2
1442 created new head
1442 created new head
1443
1443
1444 $ echo e >> head2
1444 $ echo e >> head2
1445 $ hg ci -m h2e -d '4 0'
1445 $ hg ci -m h2e -d '4 0'
1446
1446
1447 $ hg merge -q
1447 $ hg merge -q
1448 $ hg ci -m merge -d '5 -3600'
1448 $ hg ci -m merge -d '5 -3600'
1449
1449
1450 No tag set:
1450 No tag set:
1451
1451
1452 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
1452 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
1453 5: null+5
1453 5: null+5
1454 4: null+4
1454 4: null+4
1455 3: null+3
1455 3: null+3
1456 2: null+3
1456 2: null+3
1457 1: null+2
1457 1: null+2
1458 0: null+1
1458 0: null+1
1459
1459
1460 One common tag: longuest path wins:
1460 One common tag: longuest path wins:
1461
1461
1462 $ hg tag -r 1 -m t1 -d '6 0' t1
1462 $ hg tag -r 1 -m t1 -d '6 0' t1
1463 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
1463 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
1464 6: t1+4
1464 6: t1+4
1465 5: t1+3
1465 5: t1+3
1466 4: t1+2
1466 4: t1+2
1467 3: t1+1
1467 3: t1+1
1468 2: t1+1
1468 2: t1+1
1469 1: t1+0
1469 1: t1+0
1470 0: null+1
1470 0: null+1
1471
1471
1472 One ancestor tag: more recent wins:
1472 One ancestor tag: more recent wins:
1473
1473
1474 $ hg tag -r 2 -m t2 -d '7 0' t2
1474 $ hg tag -r 2 -m t2 -d '7 0' t2
1475 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
1475 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
1476 7: t2+3
1476 7: t2+3
1477 6: t2+2
1477 6: t2+2
1478 5: t2+1
1478 5: t2+1
1479 4: t1+2
1479 4: t1+2
1480 3: t1+1
1480 3: t1+1
1481 2: t2+0
1481 2: t2+0
1482 1: t1+0
1482 1: t1+0
1483 0: null+1
1483 0: null+1
1484
1484
1485 Two branch tags: more recent wins:
1485 Two branch tags: more recent wins:
1486
1486
1487 $ hg tag -r 3 -m t3 -d '8 0' t3
1487 $ hg tag -r 3 -m t3 -d '8 0' t3
1488 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
1488 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
1489 8: t3+5
1489 8: t3+5
1490 7: t3+4
1490 7: t3+4
1491 6: t3+3
1491 6: t3+3
1492 5: t3+2
1492 5: t3+2
1493 4: t3+1
1493 4: t3+1
1494 3: t3+0
1494 3: t3+0
1495 2: t2+0
1495 2: t2+0
1496 1: t1+0
1496 1: t1+0
1497 0: null+1
1497 0: null+1
1498
1498
1499 Merged tag overrides:
1499 Merged tag overrides:
1500
1500
1501 $ hg tag -r 5 -m t5 -d '9 0' t5
1501 $ hg tag -r 5 -m t5 -d '9 0' t5
1502 $ hg tag -r 3 -m at3 -d '10 0' at3
1502 $ hg tag -r 3 -m at3 -d '10 0' at3
1503 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
1503 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
1504 10: t5+5
1504 10: t5+5
1505 9: t5+4
1505 9: t5+4
1506 8: t5+3
1506 8: t5+3
1507 7: t5+2
1507 7: t5+2
1508 6: t5+1
1508 6: t5+1
1509 5: t5+0
1509 5: t5+0
1510 4: at3:t3+1
1510 4: at3:t3+1
1511 3: at3:t3+0
1511 3: at3:t3+0
1512 2: t2+0
1512 2: t2+0
1513 1: t1+0
1513 1: t1+0
1514 0: null+1
1514 0: null+1
1515
1515
1516 $ cd ..
1516 $ cd ..
1517
1517
1518
1518
1519 Style path expansion: issue1948 - ui.style option doesn't work on OSX
1519 Style path expansion: issue1948 - ui.style option doesn't work on OSX
1520 if it is a relative path
1520 if it is a relative path
1521
1521
1522 $ mkdir -p home/styles
1522 $ mkdir -p home/styles
1523
1523
1524 $ cat > home/styles/teststyle <<EOF
1524 $ cat > home/styles/teststyle <<EOF
1525 > changeset = 'test {rev}:{node|short}\n'
1525 > changeset = 'test {rev}:{node|short}\n'
1526 > EOF
1526 > EOF
1527
1527
1528 $ HOME=`pwd`/home; export HOME
1528 $ HOME=`pwd`/home; export HOME
1529
1529
1530 $ cat > latesttag/.hg/hgrc <<EOF
1530 $ cat > latesttag/.hg/hgrc <<EOF
1531 > [ui]
1531 > [ui]
1532 > style = ~/styles/teststyle
1532 > style = ~/styles/teststyle
1533 > EOF
1533 > EOF
1534
1534
1535 $ hg -R latesttag tip
1535 $ hg -R latesttag tip
1536 test 10:9b4a630e5f5f
1536 test 10:9b4a630e5f5f
1537
1537
1538 Test recursive showlist template (issue1989):
1538 Test recursive showlist template (issue1989):
1539
1539
1540 $ cat > style1989 <<EOF
1540 $ cat > style1989 <<EOF
1541 > changeset = '{file_mods}{manifest}{extras}'
1541 > changeset = '{file_mods}{manifest}{extras}'
1542 > file_mod = 'M|{author|person}\n'
1542 > file_mod = 'M|{author|person}\n'
1543 > manifest = '{rev},{author}\n'
1543 > manifest = '{rev},{author}\n'
1544 > extra = '{key}: {author}\n'
1544 > extra = '{key}: {author}\n'
1545 > EOF
1545 > EOF
1546
1546
1547 $ hg -R latesttag log -r tip --style=style1989
1547 $ hg -R latesttag log -r tip --style=style1989
1548 M|test
1548 M|test
1549 10,test
1549 10,test
1550 branch: test
1550 branch: test
1551
1551
1552 Test new-style inline templating:
1552 Test new-style inline templating:
1553
1553
1554 $ hg log -R latesttag -r tip --template 'modified files: {file_mods % " {file}\n"}\n'
1554 $ hg log -R latesttag -r tip --template 'modified files: {file_mods % " {file}\n"}\n'
1555 modified files: .hgtags
1555 modified files: .hgtags
1556
1556
1557 Test the sub function of templating for expansion:
1557 Test the sub function of templating for expansion:
1558
1558
1559 $ hg log -R latesttag -r 10 --template '{sub("[0-9]", "x", "{rev}")}\n'
1559 $ hg log -R latesttag -r 10 --template '{sub("[0-9]", "x", "{rev}")}\n'
1560 xx
1560 xx
1561
1561
1562 Test the strip function with chars specified:
1562 Test the strip function with chars specified:
1563
1563
1564 $ hg log -R latesttag --template '{desc}\n'
1564 $ hg log -R latesttag --template '{desc}\n'
1565 at3
1565 at3
1566 t5
1566 t5
1567 t3
1567 t3
1568 t2
1568 t2
1569 t1
1569 t1
1570 merge
1570 merge
1571 h2e
1571 h2e
1572 h2d
1572 h2d
1573 h1c
1573 h1c
1574 b
1574 b
1575 a
1575 a
1576
1576
1577 $ hg log -R latesttag --template '{strip(desc, "te")}\n'
1577 $ hg log -R latesttag --template '{strip(desc, "te")}\n'
1578 at3
1578 at3
1579 5
1579 5
1580 3
1580 3
1581 2
1581 2
1582 1
1582 1
1583 merg
1583 merg
1584 h2
1584 h2
1585 h2d
1585 h2d
1586 h1c
1586 h1c
1587 b
1587 b
1588 a
1588 a
1589
1589
1590 Test date format:
1590 Test date format:
1591
1591
1592 $ hg log -R latesttag --template 'date: {date(date, "%y %m %d %S %z")}\n'
1592 $ hg log -R latesttag --template 'date: {date(date, "%y %m %d %S %z")}\n'
1593 date: 70 01 01 10 +0000
1593 date: 70 01 01 10 +0000
1594 date: 70 01 01 09 +0000
1594 date: 70 01 01 09 +0000
1595 date: 70 01 01 08 +0000
1595 date: 70 01 01 08 +0000
1596 date: 70 01 01 07 +0000
1596 date: 70 01 01 07 +0000
1597 date: 70 01 01 06 +0000
1597 date: 70 01 01 06 +0000
1598 date: 70 01 01 05 +0100
1598 date: 70 01 01 05 +0100
1599 date: 70 01 01 04 +0000
1599 date: 70 01 01 04 +0000
1600 date: 70 01 01 03 +0000
1600 date: 70 01 01 03 +0000
1601 date: 70 01 01 02 +0000
1601 date: 70 01 01 02 +0000
1602 date: 70 01 01 01 +0000
1602 date: 70 01 01 01 +0000
1603 date: 70 01 01 00 +0000
1603 date: 70 01 01 00 +0000
1604
1604
1605 Test string escaping:
1605 Test string escaping:
1606
1606
1607 $ hg log -R latesttag -r 0 --template '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
1607 $ hg log -R latesttag -r 0 --template '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
1608 >
1608 >
1609 <>\n<[>
1609 <>\n<[>
1610 <>\n<]>
1610 <>\n<]>
1611 <>\n<
1611 <>\n<
1612
1612
1613 Test recursive evaluation:
1613 Test recursive evaluation:
1614
1614
1615 $ hg init r
1615 $ hg init r
1616 $ cd r
1616 $ cd r
1617 $ echo a > a
1617 $ echo a > a
1618 $ hg ci -Am '{rev}'
1618 $ hg ci -Am '{rev}'
1619 adding a
1619 adding a
1620 $ hg log -r 0 --template '{if(rev, desc)}\n'
1620 $ hg log -r 0 --template '{if(rev, desc)}\n'
1621 {rev}
1621 {rev}
1622 $ hg log -r 0 --template '{if(rev, "{author} {rev}")}\n'
1622 $ hg log -r 0 --template '{if(rev, "{author} {rev}")}\n'
1623 test 0
1623 test 0
1624
1624
1625 $ hg branch -q 'text.{rev}'
1626 $ echo aa >> aa
1627 $ hg ci -u '{node|short}' -m 'desc to be wrapped desc to be wrapped'
1628
1629 $ hg log -r 1 --template '{fill(desc, "20", author, branch)}'
1630 {node|short}desc to
1631 text.{rev}be wrapped
1632 text.{rev}desc to be
1633 text.{rev}wrapped (no-eol)
1634 $ hg log -r 1 --template '{fill(desc, "20", "{node|short}:", "text.{rev}:")}'
1635 bcc7ff960b8e:desc to
1636 text.1:be wrapped
1637 text.1:desc to be
1638 text.1:wrapped (no-eol)
1639
1640 $ hg log -r 1 --template '{sub(r"[0-9]", "-", author)}'
1641 {node|short} (no-eol)
1642 $ hg log -r 1 --template '{sub(r"[0-9]", "-", "{node|short}")}'
1643 bcc-ff---b-e (no-eol)
1644
1645 $ cat >> .hg/hgrc <<EOF
1646 > [extensions]
1647 > color=
1648 > [color]
1649 > mode=ansi
1650 > text.{rev} = red
1651 > text.1 = green
1652 > EOF
1653 $ hg log --color=always -r 1 --template '{label(branch, "text\n")}'
1654 \x1b[0;31mtext\x1b[0m (esc)
1655 $ hg log --color=always -r 1 --template '{label("text.{rev}", "text\n")}'
1656 \x1b[0;32mtext\x1b[0m (esc)
1657
1625 Test branches inside if statement:
1658 Test branches inside if statement:
1626
1659
1627 $ hg log -r 0 --template '{if(branches, "yes", "no")}\n'
1660 $ hg log -r 0 --template '{if(branches, "yes", "no")}\n'
1628 no
1661 no
General Comments 0
You need to be logged in to leave comments. Login now