##// END OF EJS Templates
templater: make label() take unknown symbol as color literal...
Yuya Nishihara -
r28373:9a9dd71e default
parent child Browse files
Show More
@@ -1,678 +1,676
1 # color.py color output for Mercurial commands
1 # color.py color output for Mercurial 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 The color extension colorizes output from several Mercurial commands.
10 The color extension colorizes output from several Mercurial commands.
11 For example, the diff command shows additions in green and deletions
11 For example, the diff command shows additions in green and deletions
12 in red, while the status command shows modified files in magenta. Many
12 in red, while the status command shows modified files in magenta. Many
13 other commands have analogous colors. It is possible to customize
13 other commands have analogous colors. It is possible to customize
14 these colors.
14 these colors.
15
15
16 Effects
16 Effects
17 -------
17 -------
18
18
19 Other effects in addition to color, like bold and underlined text, are
19 Other effects in addition to color, like bold and underlined text, are
20 also available. By default, the terminfo database is used to find the
20 also available. By default, the terminfo database is used to find the
21 terminal codes used to change color and effect. If terminfo is not
21 terminal codes used to change color and effect. If terminfo is not
22 available, then effects are rendered with the ECMA-48 SGR control
22 available, then effects are rendered with the ECMA-48 SGR control
23 function (aka ANSI escape codes).
23 function (aka ANSI escape codes).
24
24
25 The available effects in terminfo mode are 'blink', 'bold', 'dim',
25 The available effects in terminfo mode are 'blink', 'bold', 'dim',
26 'inverse', 'invisible', 'italic', 'standout', and 'underline'; in
26 'inverse', 'invisible', 'italic', 'standout', and 'underline'; in
27 ECMA-48 mode, the options are 'bold', 'inverse', 'italic', and
27 ECMA-48 mode, the options are 'bold', 'inverse', 'italic', and
28 'underline'. How each is rendered depends on the terminal emulator.
28 'underline'. How each is rendered depends on the terminal emulator.
29 Some may not be available for a given terminal type, and will be
29 Some may not be available for a given terminal type, and will be
30 silently ignored.
30 silently ignored.
31
31
32 Labels
32 Labels
33 ------
33 ------
34
34
35 Text receives color effects depending on the labels that it has. Many
35 Text receives color effects depending on the labels that it has. Many
36 default Mercurial commands emit labelled text. You can also define
36 default Mercurial commands emit labelled text. You can also define
37 your own labels in templates using the label function, see :hg:`help
37 your own labels in templates using the label function, see :hg:`help
38 templates`. A single portion of text may have more than one label. In
38 templates`. A single portion of text may have more than one label. In
39 that case, effects given to the last label will override any other
39 that case, effects given to the last label will override any other
40 effects. This includes the special "none" effect, which nullifies
40 effects. This includes the special "none" effect, which nullifies
41 other effects.
41 other effects.
42
42
43 Labels are normally invisible. In order to see these labels and their
43 Labels are normally invisible. In order to see these labels and their
44 position in the text, use the global --color=debug option. The same
44 position in the text, use the global --color=debug option. The same
45 anchor text may be associated to multiple labels, e.g.
45 anchor text may be associated to multiple labels, e.g.
46
46
47 [log.changeset changeset.secret|changeset: 22611:6f0a53c8f587]
47 [log.changeset changeset.secret|changeset: 22611:6f0a53c8f587]
48
48
49 The following are the default effects for some default labels. Default
49 The following are the default effects for some default labels. Default
50 effects may be overridden from your configuration file::
50 effects may be overridden from your configuration file::
51
51
52 [color]
52 [color]
53 status.modified = blue bold underline red_background
53 status.modified = blue bold underline red_background
54 status.added = green bold
54 status.added = green bold
55 status.removed = red bold blue_background
55 status.removed = red bold blue_background
56 status.deleted = cyan bold underline
56 status.deleted = cyan bold underline
57 status.unknown = magenta bold underline
57 status.unknown = magenta bold underline
58 status.ignored = black bold
58 status.ignored = black bold
59
59
60 # 'none' turns off all effects
60 # 'none' turns off all effects
61 status.clean = none
61 status.clean = none
62 status.copied = none
62 status.copied = none
63
63
64 qseries.applied = blue bold underline
64 qseries.applied = blue bold underline
65 qseries.unapplied = black bold
65 qseries.unapplied = black bold
66 qseries.missing = red bold
66 qseries.missing = red bold
67
67
68 diff.diffline = bold
68 diff.diffline = bold
69 diff.extended = cyan bold
69 diff.extended = cyan bold
70 diff.file_a = red bold
70 diff.file_a = red bold
71 diff.file_b = green bold
71 diff.file_b = green bold
72 diff.hunk = magenta
72 diff.hunk = magenta
73 diff.deleted = red
73 diff.deleted = red
74 diff.inserted = green
74 diff.inserted = green
75 diff.changed = white
75 diff.changed = white
76 diff.tab =
76 diff.tab =
77 diff.trailingwhitespace = bold red_background
77 diff.trailingwhitespace = bold red_background
78
78
79 # Blank so it inherits the style of the surrounding label
79 # Blank so it inherits the style of the surrounding label
80 changeset.public =
80 changeset.public =
81 changeset.draft =
81 changeset.draft =
82 changeset.secret =
82 changeset.secret =
83
83
84 resolve.unresolved = red bold
84 resolve.unresolved = red bold
85 resolve.resolved = green bold
85 resolve.resolved = green bold
86
86
87 bookmarks.active = green
87 bookmarks.active = green
88
88
89 branches.active = none
89 branches.active = none
90 branches.closed = black bold
90 branches.closed = black bold
91 branches.current = green
91 branches.current = green
92 branches.inactive = none
92 branches.inactive = none
93
93
94 tags.normal = green
94 tags.normal = green
95 tags.local = black bold
95 tags.local = black bold
96
96
97 rebase.rebased = blue
97 rebase.rebased = blue
98 rebase.remaining = red bold
98 rebase.remaining = red bold
99
99
100 shelve.age = cyan
100 shelve.age = cyan
101 shelve.newest = green bold
101 shelve.newest = green bold
102 shelve.name = blue bold
102 shelve.name = blue bold
103
103
104 histedit.remaining = red bold
104 histedit.remaining = red bold
105
105
106 Custom colors
106 Custom colors
107 -------------
107 -------------
108
108
109 Because there are only eight standard colors, this module allows you
109 Because there are only eight standard colors, this module allows you
110 to define color names for other color slots which might be available
110 to define color names for other color slots which might be available
111 for your terminal type, assuming terminfo mode. For instance::
111 for your terminal type, assuming terminfo mode. For instance::
112
112
113 color.brightblue = 12
113 color.brightblue = 12
114 color.pink = 207
114 color.pink = 207
115 color.orange = 202
115 color.orange = 202
116
116
117 to set 'brightblue' to color slot 12 (useful for 16 color terminals
117 to set 'brightblue' to color slot 12 (useful for 16 color terminals
118 that have brighter colors defined in the upper eight) and, 'pink' and
118 that have brighter colors defined in the upper eight) and, 'pink' and
119 'orange' to colors in 256-color xterm's default color cube. These
119 'orange' to colors in 256-color xterm's default color cube. These
120 defined colors may then be used as any of the pre-defined eight,
120 defined colors may then be used as any of the pre-defined eight,
121 including appending '_background' to set the background to that color.
121 including appending '_background' to set the background to that color.
122
122
123 Modes
123 Modes
124 -----
124 -----
125
125
126 By default, the color extension will use ANSI mode (or win32 mode on
126 By default, the color extension will use ANSI mode (or win32 mode on
127 Windows) if it detects a terminal. To override auto mode (to enable
127 Windows) if it detects a terminal. To override auto mode (to enable
128 terminfo mode, for example), set the following configuration option::
128 terminfo mode, for example), set the following configuration option::
129
129
130 [color]
130 [color]
131 mode = terminfo
131 mode = terminfo
132
132
133 Any value other than 'ansi', 'win32', 'terminfo', or 'auto' will
133 Any value other than 'ansi', 'win32', 'terminfo', or 'auto' will
134 disable color.
134 disable color.
135
135
136 Note that on some systems, terminfo mode may cause problems when using
136 Note that on some systems, terminfo mode may cause problems when using
137 color with the pager extension and less -R. less with the -R option
137 color with the pager extension and less -R. less with the -R option
138 will only display ECMA-48 color codes, and terminfo mode may sometimes
138 will only display ECMA-48 color codes, and terminfo mode may sometimes
139 emit codes that less doesn't understand. You can work around this by
139 emit codes that less doesn't understand. You can work around this by
140 either using ansi mode (or auto mode), or by using less -r (which will
140 either using ansi mode (or auto mode), or by using less -r (which will
141 pass through all terminal control codes, not just color control
141 pass through all terminal control codes, not just color control
142 codes).
142 codes).
143
143
144 On some systems (such as MSYS in Windows), the terminal may support
144 On some systems (such as MSYS in Windows), the terminal may support
145 a different color mode than the pager (activated via the "pager"
145 a different color mode than the pager (activated via the "pager"
146 extension). It is possible to define separate modes depending on whether
146 extension). It is possible to define separate modes depending on whether
147 the pager is active::
147 the pager is active::
148
148
149 [color]
149 [color]
150 mode = auto
150 mode = auto
151 pagermode = ansi
151 pagermode = ansi
152
152
153 If ``pagermode`` is not defined, the ``mode`` will be used.
153 If ``pagermode`` is not defined, the ``mode`` will be used.
154 '''
154 '''
155
155
156 import os
156 import os
157
157
158 from mercurial import cmdutil, commands, dispatch, extensions, subrepo, util
158 from mercurial import cmdutil, commands, dispatch, extensions, subrepo, util
159 from mercurial import ui as uimod
159 from mercurial import ui as uimod
160 from mercurial import templater, error
160 from mercurial import templater, error
161 from mercurial.i18n import _
161 from mercurial.i18n import _
162
162
163 cmdtable = {}
163 cmdtable = {}
164 command = cmdutil.command(cmdtable)
164 command = cmdutil.command(cmdtable)
165 # Note for extension authors: ONLY specify testedwith = 'internal' for
165 # Note for extension authors: ONLY specify testedwith = 'internal' for
166 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
166 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
167 # be specifying the version(s) of Mercurial they are tested with, or
167 # be specifying the version(s) of Mercurial they are tested with, or
168 # leave the attribute unspecified.
168 # leave the attribute unspecified.
169 testedwith = 'internal'
169 testedwith = 'internal'
170
170
171 # start and stop parameters for effects
171 # start and stop parameters for effects
172 _effects = {'none': 0, 'black': 30, 'red': 31, 'green': 32, 'yellow': 33,
172 _effects = {'none': 0, 'black': 30, 'red': 31, 'green': 32, 'yellow': 33,
173 'blue': 34, 'magenta': 35, 'cyan': 36, 'white': 37, 'bold': 1,
173 'blue': 34, 'magenta': 35, 'cyan': 36, 'white': 37, 'bold': 1,
174 'italic': 3, 'underline': 4, 'inverse': 7, 'dim': 2,
174 'italic': 3, 'underline': 4, 'inverse': 7, 'dim': 2,
175 'black_background': 40, 'red_background': 41,
175 'black_background': 40, 'red_background': 41,
176 'green_background': 42, 'yellow_background': 43,
176 'green_background': 42, 'yellow_background': 43,
177 'blue_background': 44, 'purple_background': 45,
177 'blue_background': 44, 'purple_background': 45,
178 'cyan_background': 46, 'white_background': 47}
178 'cyan_background': 46, 'white_background': 47}
179
179
180 def _terminfosetup(ui, mode):
180 def _terminfosetup(ui, mode):
181 '''Initialize terminfo data and the terminal if we're in terminfo mode.'''
181 '''Initialize terminfo data and the terminal if we're in terminfo mode.'''
182
182
183 global _terminfo_params
183 global _terminfo_params
184 # If we failed to load curses, we go ahead and return.
184 # If we failed to load curses, we go ahead and return.
185 if not _terminfo_params:
185 if not _terminfo_params:
186 return
186 return
187 # Otherwise, see what the config file says.
187 # Otherwise, see what the config file says.
188 if mode not in ('auto', 'terminfo'):
188 if mode not in ('auto', 'terminfo'):
189 return
189 return
190
190
191 _terminfo_params.update((key[6:], (False, int(val)))
191 _terminfo_params.update((key[6:], (False, int(val)))
192 for key, val in ui.configitems('color')
192 for key, val in ui.configitems('color')
193 if key.startswith('color.'))
193 if key.startswith('color.'))
194
194
195 try:
195 try:
196 curses.setupterm()
196 curses.setupterm()
197 except curses.error as e:
197 except curses.error as e:
198 _terminfo_params = {}
198 _terminfo_params = {}
199 return
199 return
200
200
201 for key, (b, e) in _terminfo_params.items():
201 for key, (b, e) in _terminfo_params.items():
202 if not b:
202 if not b:
203 continue
203 continue
204 if not curses.tigetstr(e):
204 if not curses.tigetstr(e):
205 # Most terminals don't support dim, invis, etc, so don't be
205 # Most terminals don't support dim, invis, etc, so don't be
206 # noisy and use ui.debug().
206 # noisy and use ui.debug().
207 ui.debug("no terminfo entry for %s\n" % e)
207 ui.debug("no terminfo entry for %s\n" % e)
208 del _terminfo_params[key]
208 del _terminfo_params[key]
209 if not curses.tigetstr('setaf') or not curses.tigetstr('setab'):
209 if not curses.tigetstr('setaf') or not curses.tigetstr('setab'):
210 # Only warn about missing terminfo entries if we explicitly asked for
210 # Only warn about missing terminfo entries if we explicitly asked for
211 # terminfo mode.
211 # terminfo mode.
212 if mode == "terminfo":
212 if mode == "terminfo":
213 ui.warn(_("no terminfo entry for setab/setaf: reverting to "
213 ui.warn(_("no terminfo entry for setab/setaf: reverting to "
214 "ECMA-48 color\n"))
214 "ECMA-48 color\n"))
215 _terminfo_params = {}
215 _terminfo_params = {}
216
216
217 def _modesetup(ui, coloropt):
217 def _modesetup(ui, coloropt):
218 global _terminfo_params
218 global _terminfo_params
219
219
220 if coloropt == 'debug':
220 if coloropt == 'debug':
221 return 'debug'
221 return 'debug'
222
222
223 auto = (coloropt == 'auto')
223 auto = (coloropt == 'auto')
224 always = not auto and util.parsebool(coloropt)
224 always = not auto and util.parsebool(coloropt)
225 if not always and not auto:
225 if not always and not auto:
226 return None
226 return None
227
227
228 formatted = always or (os.environ.get('TERM') != 'dumb' and ui.formatted())
228 formatted = always or (os.environ.get('TERM') != 'dumb' and ui.formatted())
229
229
230 mode = ui.config('color', 'mode', 'auto')
230 mode = ui.config('color', 'mode', 'auto')
231
231
232 # If pager is active, color.pagermode overrides color.mode.
232 # If pager is active, color.pagermode overrides color.mode.
233 if getattr(ui, 'pageractive', False):
233 if getattr(ui, 'pageractive', False):
234 mode = ui.config('color', 'pagermode', mode)
234 mode = ui.config('color', 'pagermode', mode)
235
235
236 realmode = mode
236 realmode = mode
237 if mode == 'auto':
237 if mode == 'auto':
238 if os.name == 'nt':
238 if os.name == 'nt':
239 term = os.environ.get('TERM')
239 term = os.environ.get('TERM')
240 # TERM won't be defined in a vanilla cmd.exe environment.
240 # TERM won't be defined in a vanilla cmd.exe environment.
241
241
242 # UNIX-like environments on Windows such as Cygwin and MSYS will
242 # UNIX-like environments on Windows such as Cygwin and MSYS will
243 # set TERM. They appear to make a best effort attempt at setting it
243 # set TERM. They appear to make a best effort attempt at setting it
244 # to something appropriate. However, not all environments with TERM
244 # to something appropriate. However, not all environments with TERM
245 # defined support ANSI. Since "ansi" could result in terminal
245 # defined support ANSI. Since "ansi" could result in terminal
246 # gibberish, we error on the side of selecting "win32". However, if
246 # gibberish, we error on the side of selecting "win32". However, if
247 # w32effects is not defined, we almost certainly don't support
247 # w32effects is not defined, we almost certainly don't support
248 # "win32", so don't even try.
248 # "win32", so don't even try.
249 if (term and 'xterm' in term) or not w32effects:
249 if (term and 'xterm' in term) or not w32effects:
250 realmode = 'ansi'
250 realmode = 'ansi'
251 else:
251 else:
252 realmode = 'win32'
252 realmode = 'win32'
253 else:
253 else:
254 realmode = 'ansi'
254 realmode = 'ansi'
255
255
256 def modewarn():
256 def modewarn():
257 # only warn if color.mode was explicitly set and we're in
257 # only warn if color.mode was explicitly set and we're in
258 # an interactive terminal
258 # an interactive terminal
259 if mode == realmode and ui.interactive():
259 if mode == realmode and ui.interactive():
260 ui.warn(_('warning: failed to set color mode to %s\n') % mode)
260 ui.warn(_('warning: failed to set color mode to %s\n') % mode)
261
261
262 if realmode == 'win32':
262 if realmode == 'win32':
263 _terminfo_params = {}
263 _terminfo_params = {}
264 if not w32effects:
264 if not w32effects:
265 modewarn()
265 modewarn()
266 return None
266 return None
267 _effects.update(w32effects)
267 _effects.update(w32effects)
268 elif realmode == 'ansi':
268 elif realmode == 'ansi':
269 _terminfo_params = {}
269 _terminfo_params = {}
270 elif realmode == 'terminfo':
270 elif realmode == 'terminfo':
271 _terminfosetup(ui, mode)
271 _terminfosetup(ui, mode)
272 if not _terminfo_params:
272 if not _terminfo_params:
273 ## FIXME Shouldn't we return None in this case too?
273 ## FIXME Shouldn't we return None in this case too?
274 modewarn()
274 modewarn()
275 realmode = 'ansi'
275 realmode = 'ansi'
276 else:
276 else:
277 return None
277 return None
278
278
279 if always or (auto and formatted):
279 if always or (auto and formatted):
280 return realmode
280 return realmode
281 return None
281 return None
282
282
283 try:
283 try:
284 import curses
284 import curses
285 # Mapping from effect name to terminfo attribute name or color number.
285 # Mapping from effect name to terminfo attribute name or color number.
286 # This will also force-load the curses module.
286 # This will also force-load the curses module.
287 _terminfo_params = {'none': (True, 'sgr0'),
287 _terminfo_params = {'none': (True, 'sgr0'),
288 'standout': (True, 'smso'),
288 'standout': (True, 'smso'),
289 'underline': (True, 'smul'),
289 'underline': (True, 'smul'),
290 'reverse': (True, 'rev'),
290 'reverse': (True, 'rev'),
291 'inverse': (True, 'rev'),
291 'inverse': (True, 'rev'),
292 'blink': (True, 'blink'),
292 'blink': (True, 'blink'),
293 'dim': (True, 'dim'),
293 'dim': (True, 'dim'),
294 'bold': (True, 'bold'),
294 'bold': (True, 'bold'),
295 'invisible': (True, 'invis'),
295 'invisible': (True, 'invis'),
296 'italic': (True, 'sitm'),
296 'italic': (True, 'sitm'),
297 'black': (False, curses.COLOR_BLACK),
297 'black': (False, curses.COLOR_BLACK),
298 'red': (False, curses.COLOR_RED),
298 'red': (False, curses.COLOR_RED),
299 'green': (False, curses.COLOR_GREEN),
299 'green': (False, curses.COLOR_GREEN),
300 'yellow': (False, curses.COLOR_YELLOW),
300 'yellow': (False, curses.COLOR_YELLOW),
301 'blue': (False, curses.COLOR_BLUE),
301 'blue': (False, curses.COLOR_BLUE),
302 'magenta': (False, curses.COLOR_MAGENTA),
302 'magenta': (False, curses.COLOR_MAGENTA),
303 'cyan': (False, curses.COLOR_CYAN),
303 'cyan': (False, curses.COLOR_CYAN),
304 'white': (False, curses.COLOR_WHITE)}
304 'white': (False, curses.COLOR_WHITE)}
305 except ImportError:
305 except ImportError:
306 _terminfo_params = {}
306 _terminfo_params = {}
307
307
308 _styles = {'grep.match': 'red bold',
308 _styles = {'grep.match': 'red bold',
309 'grep.linenumber': 'green',
309 'grep.linenumber': 'green',
310 'grep.rev': 'green',
310 'grep.rev': 'green',
311 'grep.change': 'green',
311 'grep.change': 'green',
312 'grep.sep': 'cyan',
312 'grep.sep': 'cyan',
313 'grep.filename': 'magenta',
313 'grep.filename': 'magenta',
314 'grep.user': 'magenta',
314 'grep.user': 'magenta',
315 'grep.date': 'magenta',
315 'grep.date': 'magenta',
316 'bookmarks.active': 'green',
316 'bookmarks.active': 'green',
317 'branches.active': 'none',
317 'branches.active': 'none',
318 'branches.closed': 'black bold',
318 'branches.closed': 'black bold',
319 'branches.current': 'green',
319 'branches.current': 'green',
320 'branches.inactive': 'none',
320 'branches.inactive': 'none',
321 'diff.changed': 'white',
321 'diff.changed': 'white',
322 'diff.deleted': 'red',
322 'diff.deleted': 'red',
323 'diff.diffline': 'bold',
323 'diff.diffline': 'bold',
324 'diff.extended': 'cyan bold',
324 'diff.extended': 'cyan bold',
325 'diff.file_a': 'red bold',
325 'diff.file_a': 'red bold',
326 'diff.file_b': 'green bold',
326 'diff.file_b': 'green bold',
327 'diff.hunk': 'magenta',
327 'diff.hunk': 'magenta',
328 'diff.inserted': 'green',
328 'diff.inserted': 'green',
329 'diff.tab': '',
329 'diff.tab': '',
330 'diff.trailingwhitespace': 'bold red_background',
330 'diff.trailingwhitespace': 'bold red_background',
331 'changeset.public' : '',
331 'changeset.public' : '',
332 'changeset.draft' : '',
332 'changeset.draft' : '',
333 'changeset.secret' : '',
333 'changeset.secret' : '',
334 'diffstat.deleted': 'red',
334 'diffstat.deleted': 'red',
335 'diffstat.inserted': 'green',
335 'diffstat.inserted': 'green',
336 'histedit.remaining': 'red bold',
336 'histedit.remaining': 'red bold',
337 'ui.prompt': 'yellow',
337 'ui.prompt': 'yellow',
338 'log.changeset': 'yellow',
338 'log.changeset': 'yellow',
339 'patchbomb.finalsummary': '',
339 'patchbomb.finalsummary': '',
340 'patchbomb.from': 'magenta',
340 'patchbomb.from': 'magenta',
341 'patchbomb.to': 'cyan',
341 'patchbomb.to': 'cyan',
342 'patchbomb.subject': 'green',
342 'patchbomb.subject': 'green',
343 'patchbomb.diffstats': '',
343 'patchbomb.diffstats': '',
344 'rebase.rebased': 'blue',
344 'rebase.rebased': 'blue',
345 'rebase.remaining': 'red bold',
345 'rebase.remaining': 'red bold',
346 'resolve.resolved': 'green bold',
346 'resolve.resolved': 'green bold',
347 'resolve.unresolved': 'red bold',
347 'resolve.unresolved': 'red bold',
348 'shelve.age': 'cyan',
348 'shelve.age': 'cyan',
349 'shelve.newest': 'green bold',
349 'shelve.newest': 'green bold',
350 'shelve.name': 'blue bold',
350 'shelve.name': 'blue bold',
351 'status.added': 'green bold',
351 'status.added': 'green bold',
352 'status.clean': 'none',
352 'status.clean': 'none',
353 'status.copied': 'none',
353 'status.copied': 'none',
354 'status.deleted': 'cyan bold underline',
354 'status.deleted': 'cyan bold underline',
355 'status.ignored': 'black bold',
355 'status.ignored': 'black bold',
356 'status.modified': 'blue bold',
356 'status.modified': 'blue bold',
357 'status.removed': 'red bold',
357 'status.removed': 'red bold',
358 'status.unknown': 'magenta bold underline',
358 'status.unknown': 'magenta bold underline',
359 'tags.normal': 'green',
359 'tags.normal': 'green',
360 'tags.local': 'black bold'}
360 'tags.local': 'black bold'}
361
361
362
362
363 def _effect_str(effect):
363 def _effect_str(effect):
364 '''Helper function for render_effects().'''
364 '''Helper function for render_effects().'''
365
365
366 bg = False
366 bg = False
367 if effect.endswith('_background'):
367 if effect.endswith('_background'):
368 bg = True
368 bg = True
369 effect = effect[:-11]
369 effect = effect[:-11]
370 attr, val = _terminfo_params[effect]
370 attr, val = _terminfo_params[effect]
371 if attr:
371 if attr:
372 return curses.tigetstr(val)
372 return curses.tigetstr(val)
373 elif bg:
373 elif bg:
374 return curses.tparm(curses.tigetstr('setab'), val)
374 return curses.tparm(curses.tigetstr('setab'), val)
375 else:
375 else:
376 return curses.tparm(curses.tigetstr('setaf'), val)
376 return curses.tparm(curses.tigetstr('setaf'), val)
377
377
378 def render_effects(text, effects):
378 def render_effects(text, effects):
379 'Wrap text in commands to turn on each effect.'
379 'Wrap text in commands to turn on each effect.'
380 if not text:
380 if not text:
381 return text
381 return text
382 if not _terminfo_params:
382 if not _terminfo_params:
383 start = [str(_effects[e]) for e in ['none'] + effects.split()]
383 start = [str(_effects[e]) for e in ['none'] + effects.split()]
384 start = '\033[' + ';'.join(start) + 'm'
384 start = '\033[' + ';'.join(start) + 'm'
385 stop = '\033[' + str(_effects['none']) + 'm'
385 stop = '\033[' + str(_effects['none']) + 'm'
386 else:
386 else:
387 start = ''.join(_effect_str(effect)
387 start = ''.join(_effect_str(effect)
388 for effect in ['none'] + effects.split())
388 for effect in ['none'] + effects.split())
389 stop = _effect_str('none')
389 stop = _effect_str('none')
390 return ''.join([start, text, stop])
390 return ''.join([start, text, stop])
391
391
392 def extstyles():
392 def extstyles():
393 for name, ext in extensions.extensions():
393 for name, ext in extensions.extensions():
394 _styles.update(getattr(ext, 'colortable', {}))
394 _styles.update(getattr(ext, 'colortable', {}))
395
395
396 def valideffect(effect):
396 def valideffect(effect):
397 'Determine if the effect is valid or not.'
397 'Determine if the effect is valid or not.'
398 good = False
398 good = False
399 if not _terminfo_params and effect in _effects:
399 if not _terminfo_params and effect in _effects:
400 good = True
400 good = True
401 elif effect in _terminfo_params or effect[:-11] in _terminfo_params:
401 elif effect in _terminfo_params or effect[:-11] in _terminfo_params:
402 good = True
402 good = True
403 return good
403 return good
404
404
405 def configstyles(ui):
405 def configstyles(ui):
406 for status, cfgeffects in ui.configitems('color'):
406 for status, cfgeffects in ui.configitems('color'):
407 if '.' not in status or status.startswith('color.'):
407 if '.' not in status or status.startswith('color.'):
408 continue
408 continue
409 cfgeffects = ui.configlist('color', status)
409 cfgeffects = ui.configlist('color', status)
410 if cfgeffects:
410 if cfgeffects:
411 good = []
411 good = []
412 for e in cfgeffects:
412 for e in cfgeffects:
413 if valideffect(e):
413 if valideffect(e):
414 good.append(e)
414 good.append(e)
415 else:
415 else:
416 ui.warn(_("ignoring unknown color/effect %r "
416 ui.warn(_("ignoring unknown color/effect %r "
417 "(configured in color.%s)\n")
417 "(configured in color.%s)\n")
418 % (e, status))
418 % (e, status))
419 _styles[status] = ' '.join(good)
419 _styles[status] = ' '.join(good)
420
420
421 class colorui(uimod.ui):
421 class colorui(uimod.ui):
422 _colormode = 'ansi'
422 _colormode = 'ansi'
423 def write(self, *args, **opts):
423 def write(self, *args, **opts):
424 if self._colormode is None:
424 if self._colormode is None:
425 return super(colorui, self).write(*args, **opts)
425 return super(colorui, self).write(*args, **opts)
426
426
427 label = opts.get('label', '')
427 label = opts.get('label', '')
428 if self._buffers:
428 if self._buffers:
429 if self._bufferapplylabels:
429 if self._bufferapplylabels:
430 self._buffers[-1].extend(self.label(a, label) for a in args)
430 self._buffers[-1].extend(self.label(a, label) for a in args)
431 else:
431 else:
432 self._buffers[-1].extend(args)
432 self._buffers[-1].extend(args)
433 elif self._colormode == 'win32':
433 elif self._colormode == 'win32':
434 for a in args:
434 for a in args:
435 win32print(a, super(colorui, self).write, **opts)
435 win32print(a, super(colorui, self).write, **opts)
436 else:
436 else:
437 return super(colorui, self).write(
437 return super(colorui, self).write(
438 *[self.label(a, label) for a in args], **opts)
438 *[self.label(a, label) for a in args], **opts)
439
439
440 def write_err(self, *args, **opts):
440 def write_err(self, *args, **opts):
441 if self._colormode is None:
441 if self._colormode is None:
442 return super(colorui, self).write_err(*args, **opts)
442 return super(colorui, self).write_err(*args, **opts)
443
443
444 label = opts.get('label', '')
444 label = opts.get('label', '')
445 if self._bufferstates and self._bufferstates[-1][0]:
445 if self._bufferstates and self._bufferstates[-1][0]:
446 return self.write(*args, **opts)
446 return self.write(*args, **opts)
447 if self._colormode == 'win32':
447 if self._colormode == 'win32':
448 for a in args:
448 for a in args:
449 win32print(a, super(colorui, self).write_err, **opts)
449 win32print(a, super(colorui, self).write_err, **opts)
450 else:
450 else:
451 return super(colorui, self).write_err(
451 return super(colorui, self).write_err(
452 *[self.label(a, label) for a in args], **opts)
452 *[self.label(a, label) for a in args], **opts)
453
453
454 def showlabel(self, msg, label):
454 def showlabel(self, msg, label):
455 if label and msg:
455 if label and msg:
456 if msg[-1] == '\n':
456 if msg[-1] == '\n':
457 return "[%s|%s]\n" % (label, msg[:-1])
457 return "[%s|%s]\n" % (label, msg[:-1])
458 else:
458 else:
459 return "[%s|%s]" % (label, msg)
459 return "[%s|%s]" % (label, msg)
460 else:
460 else:
461 return msg
461 return msg
462
462
463 def label(self, msg, label):
463 def label(self, msg, label):
464 if self._colormode is None:
464 if self._colormode is None:
465 return super(colorui, self).label(msg, label)
465 return super(colorui, self).label(msg, label)
466
466
467 if self._colormode == 'debug':
467 if self._colormode == 'debug':
468 return self.showlabel(msg, label)
468 return self.showlabel(msg, label)
469
469
470 effects = []
470 effects = []
471 for l in label.split():
471 for l in label.split():
472 s = _styles.get(l, '')
472 s = _styles.get(l, '')
473 if s:
473 if s:
474 effects.append(s)
474 effects.append(s)
475 elif valideffect(l):
475 elif valideffect(l):
476 effects.append(l)
476 effects.append(l)
477 effects = ' '.join(effects)
477 effects = ' '.join(effects)
478 if effects:
478 if effects:
479 return '\n'.join([render_effects(s, effects)
479 return '\n'.join([render_effects(s, effects)
480 for s in msg.split('\n')])
480 for s in msg.split('\n')])
481 return msg
481 return msg
482
482
483 def templatelabel(context, mapping, args):
483 def templatelabel(context, mapping, args):
484 if len(args) != 2:
484 if len(args) != 2:
485 # i18n: "label" is a keyword
485 # i18n: "label" is a keyword
486 raise error.ParseError(_("label expects two arguments"))
486 raise error.ParseError(_("label expects two arguments"))
487
487
488 # add known effects to the mapping so symbols like 'red', 'bold',
489 # etc. don't need to be quoted
490 mapping.update(dict([(k, k) for k in _effects]))
491
492 thing = templater.evalstring(context, mapping, args[1])
488 thing = templater.evalstring(context, mapping, args[1])
493
489
494 # apparently, repo could be a string that is the favicon?
490 # apparently, repo could be a string that is the favicon?
495 repo = mapping.get('repo', '')
491 repo = mapping.get('repo', '')
496 if isinstance(repo, str):
492 if isinstance(repo, str):
497 return thing
493 return thing
498
494
499 label = templater.evalstring(context, mapping, args[0])
495 # preserve unknown symbol as literal so effects like 'red', 'bold',
496 # etc. don't need to be quoted
497 label = templater.evalstringliteral(context, mapping, args[0])
500
498
501 return repo.ui.label(thing, label)
499 return repo.ui.label(thing, label)
502
500
503 def uisetup(ui):
501 def uisetup(ui):
504 if ui.plain():
502 if ui.plain():
505 return
503 return
506 if not isinstance(ui, colorui):
504 if not isinstance(ui, colorui):
507 colorui.__bases__ = (ui.__class__,)
505 colorui.__bases__ = (ui.__class__,)
508 ui.__class__ = colorui
506 ui.__class__ = colorui
509 def colorcmd(orig, ui_, opts, cmd, cmdfunc):
507 def colorcmd(orig, ui_, opts, cmd, cmdfunc):
510 mode = _modesetup(ui_, opts['color'])
508 mode = _modesetup(ui_, opts['color'])
511 colorui._colormode = mode
509 colorui._colormode = mode
512 if mode and mode != 'debug':
510 if mode and mode != 'debug':
513 extstyles()
511 extstyles()
514 configstyles(ui_)
512 configstyles(ui_)
515 return orig(ui_, opts, cmd, cmdfunc)
513 return orig(ui_, opts, cmd, cmdfunc)
516 def colorgit(orig, gitsub, commands, env=None, stream=False, cwd=None):
514 def colorgit(orig, gitsub, commands, env=None, stream=False, cwd=None):
517 if gitsub.ui._colormode and len(commands) and commands[0] == "diff":
515 if gitsub.ui._colormode and len(commands) and commands[0] == "diff":
518 # insert the argument in the front,
516 # insert the argument in the front,
519 # the end of git diff arguments is used for paths
517 # the end of git diff arguments is used for paths
520 commands.insert(1, '--color')
518 commands.insert(1, '--color')
521 return orig(gitsub, commands, env, stream, cwd)
519 return orig(gitsub, commands, env, stream, cwd)
522 extensions.wrapfunction(dispatch, '_runcommand', colorcmd)
520 extensions.wrapfunction(dispatch, '_runcommand', colorcmd)
523 extensions.wrapfunction(subrepo.gitsubrepo, '_gitnodir', colorgit)
521 extensions.wrapfunction(subrepo.gitsubrepo, '_gitnodir', colorgit)
524 templatelabel.__doc__ = templater.funcs['label'].__doc__
522 templatelabel.__doc__ = templater.funcs['label'].__doc__
525 templater.funcs['label'] = templatelabel
523 templater.funcs['label'] = templatelabel
526
524
527 def extsetup(ui):
525 def extsetup(ui):
528 commands.globalopts.append(
526 commands.globalopts.append(
529 ('', 'color', 'auto',
527 ('', 'color', 'auto',
530 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
528 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
531 # and should not be translated
529 # and should not be translated
532 _("when to colorize (boolean, always, auto, never, or debug)"),
530 _("when to colorize (boolean, always, auto, never, or debug)"),
533 _('TYPE')))
531 _('TYPE')))
534
532
535 @command('debugcolor', [], 'hg debugcolor')
533 @command('debugcolor', [], 'hg debugcolor')
536 def debugcolor(ui, repo, **opts):
534 def debugcolor(ui, repo, **opts):
537 global _styles
535 global _styles
538 _styles = {}
536 _styles = {}
539 for effect in _effects.keys():
537 for effect in _effects.keys():
540 _styles[effect] = effect
538 _styles[effect] = effect
541 ui.write(('color mode: %s\n') % ui._colormode)
539 ui.write(('color mode: %s\n') % ui._colormode)
542 ui.write(_('available colors:\n'))
540 ui.write(_('available colors:\n'))
543 for label, colors in _styles.items():
541 for label, colors in _styles.items():
544 ui.write(('%s\n') % colors, label=label)
542 ui.write(('%s\n') % colors, label=label)
545
543
546 if os.name != 'nt':
544 if os.name != 'nt':
547 w32effects = None
545 w32effects = None
548 else:
546 else:
549 import re, ctypes
547 import re, ctypes
550
548
551 _kernel32 = ctypes.windll.kernel32
549 _kernel32 = ctypes.windll.kernel32
552
550
553 _WORD = ctypes.c_ushort
551 _WORD = ctypes.c_ushort
554
552
555 _INVALID_HANDLE_VALUE = -1
553 _INVALID_HANDLE_VALUE = -1
556
554
557 class _COORD(ctypes.Structure):
555 class _COORD(ctypes.Structure):
558 _fields_ = [('X', ctypes.c_short),
556 _fields_ = [('X', ctypes.c_short),
559 ('Y', ctypes.c_short)]
557 ('Y', ctypes.c_short)]
560
558
561 class _SMALL_RECT(ctypes.Structure):
559 class _SMALL_RECT(ctypes.Structure):
562 _fields_ = [('Left', ctypes.c_short),
560 _fields_ = [('Left', ctypes.c_short),
563 ('Top', ctypes.c_short),
561 ('Top', ctypes.c_short),
564 ('Right', ctypes.c_short),
562 ('Right', ctypes.c_short),
565 ('Bottom', ctypes.c_short)]
563 ('Bottom', ctypes.c_short)]
566
564
567 class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
565 class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
568 _fields_ = [('dwSize', _COORD),
566 _fields_ = [('dwSize', _COORD),
569 ('dwCursorPosition', _COORD),
567 ('dwCursorPosition', _COORD),
570 ('wAttributes', _WORD),
568 ('wAttributes', _WORD),
571 ('srWindow', _SMALL_RECT),
569 ('srWindow', _SMALL_RECT),
572 ('dwMaximumWindowSize', _COORD)]
570 ('dwMaximumWindowSize', _COORD)]
573
571
574 _STD_OUTPUT_HANDLE = 0xfffffff5L # (DWORD)-11
572 _STD_OUTPUT_HANDLE = 0xfffffff5L # (DWORD)-11
575 _STD_ERROR_HANDLE = 0xfffffff4L # (DWORD)-12
573 _STD_ERROR_HANDLE = 0xfffffff4L # (DWORD)-12
576
574
577 _FOREGROUND_BLUE = 0x0001
575 _FOREGROUND_BLUE = 0x0001
578 _FOREGROUND_GREEN = 0x0002
576 _FOREGROUND_GREEN = 0x0002
579 _FOREGROUND_RED = 0x0004
577 _FOREGROUND_RED = 0x0004
580 _FOREGROUND_INTENSITY = 0x0008
578 _FOREGROUND_INTENSITY = 0x0008
581
579
582 _BACKGROUND_BLUE = 0x0010
580 _BACKGROUND_BLUE = 0x0010
583 _BACKGROUND_GREEN = 0x0020
581 _BACKGROUND_GREEN = 0x0020
584 _BACKGROUND_RED = 0x0040
582 _BACKGROUND_RED = 0x0040
585 _BACKGROUND_INTENSITY = 0x0080
583 _BACKGROUND_INTENSITY = 0x0080
586
584
587 _COMMON_LVB_REVERSE_VIDEO = 0x4000
585 _COMMON_LVB_REVERSE_VIDEO = 0x4000
588 _COMMON_LVB_UNDERSCORE = 0x8000
586 _COMMON_LVB_UNDERSCORE = 0x8000
589
587
590 # http://msdn.microsoft.com/en-us/library/ms682088%28VS.85%29.aspx
588 # http://msdn.microsoft.com/en-us/library/ms682088%28VS.85%29.aspx
591 w32effects = {
589 w32effects = {
592 'none': -1,
590 'none': -1,
593 'black': 0,
591 'black': 0,
594 'red': _FOREGROUND_RED,
592 'red': _FOREGROUND_RED,
595 'green': _FOREGROUND_GREEN,
593 'green': _FOREGROUND_GREEN,
596 'yellow': _FOREGROUND_RED | _FOREGROUND_GREEN,
594 'yellow': _FOREGROUND_RED | _FOREGROUND_GREEN,
597 'blue': _FOREGROUND_BLUE,
595 'blue': _FOREGROUND_BLUE,
598 'magenta': _FOREGROUND_BLUE | _FOREGROUND_RED,
596 'magenta': _FOREGROUND_BLUE | _FOREGROUND_RED,
599 'cyan': _FOREGROUND_BLUE | _FOREGROUND_GREEN,
597 'cyan': _FOREGROUND_BLUE | _FOREGROUND_GREEN,
600 'white': _FOREGROUND_RED | _FOREGROUND_GREEN | _FOREGROUND_BLUE,
598 'white': _FOREGROUND_RED | _FOREGROUND_GREEN | _FOREGROUND_BLUE,
601 'bold': _FOREGROUND_INTENSITY,
599 'bold': _FOREGROUND_INTENSITY,
602 'black_background': 0x100, # unused value > 0x0f
600 'black_background': 0x100, # unused value > 0x0f
603 'red_background': _BACKGROUND_RED,
601 'red_background': _BACKGROUND_RED,
604 'green_background': _BACKGROUND_GREEN,
602 'green_background': _BACKGROUND_GREEN,
605 'yellow_background': _BACKGROUND_RED | _BACKGROUND_GREEN,
603 'yellow_background': _BACKGROUND_RED | _BACKGROUND_GREEN,
606 'blue_background': _BACKGROUND_BLUE,
604 'blue_background': _BACKGROUND_BLUE,
607 'purple_background': _BACKGROUND_BLUE | _BACKGROUND_RED,
605 'purple_background': _BACKGROUND_BLUE | _BACKGROUND_RED,
608 'cyan_background': _BACKGROUND_BLUE | _BACKGROUND_GREEN,
606 'cyan_background': _BACKGROUND_BLUE | _BACKGROUND_GREEN,
609 'white_background': (_BACKGROUND_RED | _BACKGROUND_GREEN |
607 'white_background': (_BACKGROUND_RED | _BACKGROUND_GREEN |
610 _BACKGROUND_BLUE),
608 _BACKGROUND_BLUE),
611 'bold_background': _BACKGROUND_INTENSITY,
609 'bold_background': _BACKGROUND_INTENSITY,
612 'underline': _COMMON_LVB_UNDERSCORE, # double-byte charsets only
610 'underline': _COMMON_LVB_UNDERSCORE, # double-byte charsets only
613 'inverse': _COMMON_LVB_REVERSE_VIDEO, # double-byte charsets only
611 'inverse': _COMMON_LVB_REVERSE_VIDEO, # double-byte charsets only
614 }
612 }
615
613
616 passthrough = set([_FOREGROUND_INTENSITY,
614 passthrough = set([_FOREGROUND_INTENSITY,
617 _BACKGROUND_INTENSITY,
615 _BACKGROUND_INTENSITY,
618 _COMMON_LVB_UNDERSCORE,
616 _COMMON_LVB_UNDERSCORE,
619 _COMMON_LVB_REVERSE_VIDEO])
617 _COMMON_LVB_REVERSE_VIDEO])
620
618
621 stdout = _kernel32.GetStdHandle(
619 stdout = _kernel32.GetStdHandle(
622 _STD_OUTPUT_HANDLE) # don't close the handle returned
620 _STD_OUTPUT_HANDLE) # don't close the handle returned
623 if stdout is None or stdout == _INVALID_HANDLE_VALUE:
621 if stdout is None or stdout == _INVALID_HANDLE_VALUE:
624 w32effects = None
622 w32effects = None
625 else:
623 else:
626 csbi = _CONSOLE_SCREEN_BUFFER_INFO()
624 csbi = _CONSOLE_SCREEN_BUFFER_INFO()
627 if not _kernel32.GetConsoleScreenBufferInfo(
625 if not _kernel32.GetConsoleScreenBufferInfo(
628 stdout, ctypes.byref(csbi)):
626 stdout, ctypes.byref(csbi)):
629 # stdout may not support GetConsoleScreenBufferInfo()
627 # stdout may not support GetConsoleScreenBufferInfo()
630 # when called from subprocess or redirected
628 # when called from subprocess or redirected
631 w32effects = None
629 w32effects = None
632 else:
630 else:
633 origattr = csbi.wAttributes
631 origattr = csbi.wAttributes
634 ansire = re.compile('\033\[([^m]*)m([^\033]*)(.*)',
632 ansire = re.compile('\033\[([^m]*)m([^\033]*)(.*)',
635 re.MULTILINE | re.DOTALL)
633 re.MULTILINE | re.DOTALL)
636
634
637 def win32print(text, orig, **opts):
635 def win32print(text, orig, **opts):
638 label = opts.get('label', '')
636 label = opts.get('label', '')
639 attr = origattr
637 attr = origattr
640
638
641 def mapcolor(val, attr):
639 def mapcolor(val, attr):
642 if val == -1:
640 if val == -1:
643 return origattr
641 return origattr
644 elif val in passthrough:
642 elif val in passthrough:
645 return attr | val
643 return attr | val
646 elif val > 0x0f:
644 elif val > 0x0f:
647 return (val & 0x70) | (attr & 0x8f)
645 return (val & 0x70) | (attr & 0x8f)
648 else:
646 else:
649 return (val & 0x07) | (attr & 0xf8)
647 return (val & 0x07) | (attr & 0xf8)
650
648
651 # determine console attributes based on labels
649 # determine console attributes based on labels
652 for l in label.split():
650 for l in label.split():
653 style = _styles.get(l, '')
651 style = _styles.get(l, '')
654 for effect in style.split():
652 for effect in style.split():
655 try:
653 try:
656 attr = mapcolor(w32effects[effect], attr)
654 attr = mapcolor(w32effects[effect], attr)
657 except KeyError:
655 except KeyError:
658 # w32effects could not have certain attributes so we skip
656 # w32effects could not have certain attributes so we skip
659 # them if not found
657 # them if not found
660 pass
658 pass
661 # hack to ensure regexp finds data
659 # hack to ensure regexp finds data
662 if not text.startswith('\033['):
660 if not text.startswith('\033['):
663 text = '\033[m' + text
661 text = '\033[m' + text
664
662
665 # Look for ANSI-like codes embedded in text
663 # Look for ANSI-like codes embedded in text
666 m = re.match(ansire, text)
664 m = re.match(ansire, text)
667
665
668 try:
666 try:
669 while m:
667 while m:
670 for sattr in m.group(1).split(';'):
668 for sattr in m.group(1).split(';'):
671 if sattr:
669 if sattr:
672 attr = mapcolor(int(sattr), attr)
670 attr = mapcolor(int(sattr), attr)
673 _kernel32.SetConsoleTextAttribute(stdout, attr)
671 _kernel32.SetConsoleTextAttribute(stdout, attr)
674 orig(m.group(2), **opts)
672 orig(m.group(2), **opts)
675 m = re.match(ansire, m.group(3))
673 m = re.match(ansire, m.group(3))
676 finally:
674 finally:
677 # Explicitly reset original attributes
675 # Explicitly reset original attributes
678 _kernel32.SetConsoleTextAttribute(stdout, origattr)
676 _kernel32.SetConsoleTextAttribute(stdout, origattr)
@@ -1,1013 +1,1023
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 __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import os
10 import os
11 import re
11 import re
12 import types
12 import types
13
13
14 from .i18n import _
14 from .i18n import _
15 from . import (
15 from . import (
16 config,
16 config,
17 error,
17 error,
18 minirst,
18 minirst,
19 parser,
19 parser,
20 revset as revsetmod,
20 revset as revsetmod,
21 templatefilters,
21 templatefilters,
22 templatekw,
22 templatekw,
23 util,
23 util,
24 )
24 )
25
25
26 # template parsing
26 # template parsing
27
27
28 elements = {
28 elements = {
29 # token-type: binding-strength, primary, prefix, infix, suffix
29 # token-type: binding-strength, primary, prefix, infix, suffix
30 "(": (20, None, ("group", 1, ")"), ("func", 1, ")"), None),
30 "(": (20, None, ("group", 1, ")"), ("func", 1, ")"), None),
31 ",": (2, None, None, ("list", 2), None),
31 ",": (2, None, None, ("list", 2), None),
32 "|": (5, None, None, ("|", 5), None),
32 "|": (5, None, None, ("|", 5), None),
33 "%": (6, None, None, ("%", 6), None),
33 "%": (6, None, None, ("%", 6), None),
34 ")": (0, None, None, None, None),
34 ")": (0, None, None, None, None),
35 "integer": (0, "integer", None, None, None),
35 "integer": (0, "integer", None, None, None),
36 "symbol": (0, "symbol", None, None, None),
36 "symbol": (0, "symbol", None, None, None),
37 "string": (0, "string", None, None, None),
37 "string": (0, "string", None, None, None),
38 "template": (0, "template", None, None, None),
38 "template": (0, "template", None, None, None),
39 "end": (0, None, None, None, None),
39 "end": (0, None, None, None, None),
40 }
40 }
41
41
42 def tokenize(program, start, end):
42 def tokenize(program, start, end):
43 pos = start
43 pos = start
44 while pos < end:
44 while pos < end:
45 c = program[pos]
45 c = program[pos]
46 if c.isspace(): # skip inter-token whitespace
46 if c.isspace(): # skip inter-token whitespace
47 pass
47 pass
48 elif c in "(,)%|": # handle simple operators
48 elif c in "(,)%|": # handle simple operators
49 yield (c, None, pos)
49 yield (c, None, pos)
50 elif c in '"\'': # handle quoted templates
50 elif c in '"\'': # handle quoted templates
51 s = pos + 1
51 s = pos + 1
52 data, pos = _parsetemplate(program, s, end, c)
52 data, pos = _parsetemplate(program, s, end, c)
53 yield ('template', data, s)
53 yield ('template', data, s)
54 pos -= 1
54 pos -= 1
55 elif c == 'r' and program[pos:pos + 2] in ("r'", 'r"'):
55 elif c == 'r' and program[pos:pos + 2] in ("r'", 'r"'):
56 # handle quoted strings
56 # handle quoted strings
57 c = program[pos + 1]
57 c = program[pos + 1]
58 s = pos = pos + 2
58 s = pos = pos + 2
59 while pos < end: # find closing quote
59 while pos < end: # find closing quote
60 d = program[pos]
60 d = program[pos]
61 if d == '\\': # skip over escaped characters
61 if d == '\\': # skip over escaped characters
62 pos += 2
62 pos += 2
63 continue
63 continue
64 if d == c:
64 if d == c:
65 yield ('string', program[s:pos], s)
65 yield ('string', program[s:pos], s)
66 break
66 break
67 pos += 1
67 pos += 1
68 else:
68 else:
69 raise error.ParseError(_("unterminated string"), s)
69 raise error.ParseError(_("unterminated string"), s)
70 elif c.isdigit() or c == '-':
70 elif c.isdigit() or c == '-':
71 s = pos
71 s = pos
72 if c == '-': # simply take negate operator as part of integer
72 if c == '-': # simply take negate operator as part of integer
73 pos += 1
73 pos += 1
74 if pos >= end or not program[pos].isdigit():
74 if pos >= end or not program[pos].isdigit():
75 raise error.ParseError(_("integer literal without digits"), s)
75 raise error.ParseError(_("integer literal without digits"), s)
76 pos += 1
76 pos += 1
77 while pos < end:
77 while pos < end:
78 d = program[pos]
78 d = program[pos]
79 if not d.isdigit():
79 if not d.isdigit():
80 break
80 break
81 pos += 1
81 pos += 1
82 yield ('integer', program[s:pos], s)
82 yield ('integer', program[s:pos], s)
83 pos -= 1
83 pos -= 1
84 elif (c == '\\' and program[pos:pos + 2] in (r"\'", r'\"')
84 elif (c == '\\' and program[pos:pos + 2] in (r"\'", r'\"')
85 or c == 'r' and program[pos:pos + 3] in (r"r\'", r'r\"')):
85 or c == 'r' and program[pos:pos + 3] in (r"r\'", r'r\"')):
86 # handle escaped quoted strings for compatibility with 2.9.2-3.4,
86 # handle escaped quoted strings for compatibility with 2.9.2-3.4,
87 # where some of nested templates were preprocessed as strings and
87 # where some of nested templates were preprocessed as strings and
88 # then compiled. therefore, \"...\" was allowed. (issue4733)
88 # then compiled. therefore, \"...\" was allowed. (issue4733)
89 #
89 #
90 # processing flow of _evalifliteral() at 5ab28a2e9962:
90 # processing flow of _evalifliteral() at 5ab28a2e9962:
91 # outer template string -> stringify() -> compiletemplate()
91 # outer template string -> stringify() -> compiletemplate()
92 # ------------------------ ------------ ------------------
92 # ------------------------ ------------ ------------------
93 # {f("\\\\ {g(\"\\\"\")}"} \\ {g("\"")} [r'\\', {g("\"")}]
93 # {f("\\\\ {g(\"\\\"\")}"} \\ {g("\"")} [r'\\', {g("\"")}]
94 # ~~~~~~~~
94 # ~~~~~~~~
95 # escaped quoted string
95 # escaped quoted string
96 if c == 'r':
96 if c == 'r':
97 pos += 1
97 pos += 1
98 token = 'string'
98 token = 'string'
99 else:
99 else:
100 token = 'template'
100 token = 'template'
101 quote = program[pos:pos + 2]
101 quote = program[pos:pos + 2]
102 s = pos = pos + 2
102 s = pos = pos + 2
103 while pos < end: # find closing escaped quote
103 while pos < end: # find closing escaped quote
104 if program.startswith('\\\\\\', pos, end):
104 if program.startswith('\\\\\\', pos, end):
105 pos += 4 # skip over double escaped characters
105 pos += 4 # skip over double escaped characters
106 continue
106 continue
107 if program.startswith(quote, pos, end):
107 if program.startswith(quote, pos, end):
108 # interpret as if it were a part of an outer string
108 # interpret as if it were a part of an outer string
109 data = parser.unescapestr(program[s:pos])
109 data = parser.unescapestr(program[s:pos])
110 if token == 'template':
110 if token == 'template':
111 data = _parsetemplate(data, 0, len(data))[0]
111 data = _parsetemplate(data, 0, len(data))[0]
112 yield (token, data, s)
112 yield (token, data, s)
113 pos += 1
113 pos += 1
114 break
114 break
115 pos += 1
115 pos += 1
116 else:
116 else:
117 raise error.ParseError(_("unterminated string"), s)
117 raise error.ParseError(_("unterminated string"), s)
118 elif c.isalnum() or c in '_':
118 elif c.isalnum() or c in '_':
119 s = pos
119 s = pos
120 pos += 1
120 pos += 1
121 while pos < end: # find end of symbol
121 while pos < end: # find end of symbol
122 d = program[pos]
122 d = program[pos]
123 if not (d.isalnum() or d == "_"):
123 if not (d.isalnum() or d == "_"):
124 break
124 break
125 pos += 1
125 pos += 1
126 sym = program[s:pos]
126 sym = program[s:pos]
127 yield ('symbol', sym, s)
127 yield ('symbol', sym, s)
128 pos -= 1
128 pos -= 1
129 elif c == '}':
129 elif c == '}':
130 yield ('end', None, pos + 1)
130 yield ('end', None, pos + 1)
131 return
131 return
132 else:
132 else:
133 raise error.ParseError(_("syntax error"), pos)
133 raise error.ParseError(_("syntax error"), pos)
134 pos += 1
134 pos += 1
135 raise error.ParseError(_("unterminated template expansion"), start)
135 raise error.ParseError(_("unterminated template expansion"), start)
136
136
137 def _parsetemplate(tmpl, start, stop, quote=''):
137 def _parsetemplate(tmpl, start, stop, quote=''):
138 r"""
138 r"""
139 >>> _parsetemplate('foo{bar}"baz', 0, 12)
139 >>> _parsetemplate('foo{bar}"baz', 0, 12)
140 ([('string', 'foo'), ('symbol', 'bar'), ('string', '"baz')], 12)
140 ([('string', 'foo'), ('symbol', 'bar'), ('string', '"baz')], 12)
141 >>> _parsetemplate('foo{bar}"baz', 0, 12, quote='"')
141 >>> _parsetemplate('foo{bar}"baz', 0, 12, quote='"')
142 ([('string', 'foo'), ('symbol', 'bar')], 9)
142 ([('string', 'foo'), ('symbol', 'bar')], 9)
143 >>> _parsetemplate('foo"{bar}', 0, 9, quote='"')
143 >>> _parsetemplate('foo"{bar}', 0, 9, quote='"')
144 ([('string', 'foo')], 4)
144 ([('string', 'foo')], 4)
145 >>> _parsetemplate(r'foo\"bar"baz', 0, 12, quote='"')
145 >>> _parsetemplate(r'foo\"bar"baz', 0, 12, quote='"')
146 ([('string', 'foo"'), ('string', 'bar')], 9)
146 ([('string', 'foo"'), ('string', 'bar')], 9)
147 >>> _parsetemplate(r'foo\\"bar', 0, 10, quote='"')
147 >>> _parsetemplate(r'foo\\"bar', 0, 10, quote='"')
148 ([('string', 'foo\\')], 6)
148 ([('string', 'foo\\')], 6)
149 """
149 """
150 parsed = []
150 parsed = []
151 sepchars = '{' + quote
151 sepchars = '{' + quote
152 pos = start
152 pos = start
153 p = parser.parser(elements)
153 p = parser.parser(elements)
154 while pos < stop:
154 while pos < stop:
155 n = min((tmpl.find(c, pos, stop) for c in sepchars),
155 n = min((tmpl.find(c, pos, stop) for c in sepchars),
156 key=lambda n: (n < 0, n))
156 key=lambda n: (n < 0, n))
157 if n < 0:
157 if n < 0:
158 parsed.append(('string', parser.unescapestr(tmpl[pos:stop])))
158 parsed.append(('string', parser.unescapestr(tmpl[pos:stop])))
159 pos = stop
159 pos = stop
160 break
160 break
161 c = tmpl[n]
161 c = tmpl[n]
162 bs = (n - pos) - len(tmpl[pos:n].rstrip('\\'))
162 bs = (n - pos) - len(tmpl[pos:n].rstrip('\\'))
163 if bs % 2 == 1:
163 if bs % 2 == 1:
164 # escaped (e.g. '\{', '\\\{', but not '\\{')
164 # escaped (e.g. '\{', '\\\{', but not '\\{')
165 parsed.append(('string', parser.unescapestr(tmpl[pos:n - 1]) + c))
165 parsed.append(('string', parser.unescapestr(tmpl[pos:n - 1]) + c))
166 pos = n + 1
166 pos = n + 1
167 continue
167 continue
168 if n > pos:
168 if n > pos:
169 parsed.append(('string', parser.unescapestr(tmpl[pos:n])))
169 parsed.append(('string', parser.unescapestr(tmpl[pos:n])))
170 if c == quote:
170 if c == quote:
171 return parsed, n + 1
171 return parsed, n + 1
172
172
173 parseres, pos = p.parse(tokenize(tmpl, n + 1, stop))
173 parseres, pos = p.parse(tokenize(tmpl, n + 1, stop))
174 parsed.append(parseres)
174 parsed.append(parseres)
175
175
176 if quote:
176 if quote:
177 raise error.ParseError(_("unterminated string"), start)
177 raise error.ParseError(_("unterminated string"), start)
178 return parsed, pos
178 return parsed, pos
179
179
180 def compiletemplate(tmpl, context):
180 def compiletemplate(tmpl, context):
181 parsed, pos = _parsetemplate(tmpl, 0, len(tmpl))
181 parsed, pos = _parsetemplate(tmpl, 0, len(tmpl))
182 return [compileexp(e, context, methods) for e in parsed]
182 return [compileexp(e, context, methods) for e in parsed]
183
183
184 def compileexp(exp, context, curmethods):
184 def compileexp(exp, context, curmethods):
185 t = exp[0]
185 t = exp[0]
186 if t in curmethods:
186 if t in curmethods:
187 return curmethods[t](exp, context)
187 return curmethods[t](exp, context)
188 raise error.ParseError(_("unknown method '%s'") % t)
188 raise error.ParseError(_("unknown method '%s'") % t)
189
189
190 # template evaluation
190 # template evaluation
191
191
192 def getsymbol(exp):
192 def getsymbol(exp):
193 if exp[0] == 'symbol':
193 if exp[0] == 'symbol':
194 return exp[1]
194 return exp[1]
195 raise error.ParseError(_("expected a symbol, got '%s'") % exp[0])
195 raise error.ParseError(_("expected a symbol, got '%s'") % exp[0])
196
196
197 def getlist(x):
197 def getlist(x):
198 if not x:
198 if not x:
199 return []
199 return []
200 if x[0] == 'list':
200 if x[0] == 'list':
201 return getlist(x[1]) + [x[2]]
201 return getlist(x[1]) + [x[2]]
202 return [x]
202 return [x]
203
203
204 def gettemplate(exp, context):
204 def gettemplate(exp, context):
205 if exp[0] == 'template':
205 if exp[0] == 'template':
206 return [compileexp(e, context, methods) for e in exp[1]]
206 return [compileexp(e, context, methods) for e in exp[1]]
207 if exp[0] == 'symbol':
207 if exp[0] == 'symbol':
208 # unlike runsymbol(), here 'symbol' is always taken as template name
208 # unlike runsymbol(), here 'symbol' is always taken as template name
209 # even if it exists in mapping. this allows us to override mapping
209 # even if it exists in mapping. this allows us to override mapping
210 # by web templates, e.g. 'changelogtag' is redefined in map file.
210 # by web templates, e.g. 'changelogtag' is redefined in map file.
211 return context._load(exp[1])
211 return context._load(exp[1])
212 raise error.ParseError(_("expected template specifier"))
212 raise error.ParseError(_("expected template specifier"))
213
213
214 def evalfuncarg(context, mapping, arg):
214 def evalfuncarg(context, mapping, arg):
215 func, data = arg
215 func, data = arg
216 # func() may return string, generator of strings or arbitrary object such
216 # func() may return string, generator of strings or arbitrary object such
217 # as date tuple, but filter does not want generator.
217 # as date tuple, but filter does not want generator.
218 thing = func(context, mapping, data)
218 thing = func(context, mapping, data)
219 if isinstance(thing, types.GeneratorType):
219 if isinstance(thing, types.GeneratorType):
220 thing = stringify(thing)
220 thing = stringify(thing)
221 return thing
221 return thing
222
222
223 def evalinteger(context, mapping, arg, err):
223 def evalinteger(context, mapping, arg, err):
224 v = evalfuncarg(context, mapping, arg)
224 v = evalfuncarg(context, mapping, arg)
225 try:
225 try:
226 return int(v)
226 return int(v)
227 except (TypeError, ValueError):
227 except (TypeError, ValueError):
228 raise error.ParseError(err)
228 raise error.ParseError(err)
229
229
230 def evalstring(context, mapping, arg):
230 def evalstring(context, mapping, arg):
231 func, data = arg
231 func, data = arg
232 return stringify(func(context, mapping, data))
232 return stringify(func(context, mapping, data))
233
233
234 def evalstringliteral(context, mapping, arg):
235 """Evaluate given argument as string template, but returns symbol name
236 if it is unknown"""
237 func, data = arg
238 if func is runsymbol:
239 thing = func(context, mapping, data, default=data)
240 else:
241 thing = func(context, mapping, data)
242 return stringify(thing)
243
234 def runinteger(context, mapping, data):
244 def runinteger(context, mapping, data):
235 return int(data)
245 return int(data)
236
246
237 def runstring(context, mapping, data):
247 def runstring(context, mapping, data):
238 return data
248 return data
239
249
240 def _recursivesymbolblocker(key):
250 def _recursivesymbolblocker(key):
241 def showrecursion(**args):
251 def showrecursion(**args):
242 raise error.Abort(_("recursive reference '%s' in template") % key)
252 raise error.Abort(_("recursive reference '%s' in template") % key)
243 return showrecursion
253 return showrecursion
244
254
245 def _runrecursivesymbol(context, mapping, key):
255 def _runrecursivesymbol(context, mapping, key):
246 raise error.Abort(_("recursive reference '%s' in template") % key)
256 raise error.Abort(_("recursive reference '%s' in template") % key)
247
257
248 def runsymbol(context, mapping, key):
258 def runsymbol(context, mapping, key, default=''):
249 v = mapping.get(key)
259 v = mapping.get(key)
250 if v is None:
260 if v is None:
251 v = context._defaults.get(key)
261 v = context._defaults.get(key)
252 if v is None:
262 if v is None:
253 # put poison to cut recursion. we can't move this to parsing phase
263 # put poison to cut recursion. we can't move this to parsing phase
254 # because "x = {x}" is allowed if "x" is a keyword. (issue4758)
264 # because "x = {x}" is allowed if "x" is a keyword. (issue4758)
255 safemapping = mapping.copy()
265 safemapping = mapping.copy()
256 safemapping[key] = _recursivesymbolblocker(key)
266 safemapping[key] = _recursivesymbolblocker(key)
257 try:
267 try:
258 v = context.process(key, safemapping)
268 v = context.process(key, safemapping)
259 except TemplateNotFound:
269 except TemplateNotFound:
260 v = ''
270 v = default
261 if callable(v):
271 if callable(v):
262 return v(**mapping)
272 return v(**mapping)
263 return v
273 return v
264
274
265 def buildtemplate(exp, context):
275 def buildtemplate(exp, context):
266 ctmpl = [compileexp(e, context, methods) for e in exp[1]]
276 ctmpl = [compileexp(e, context, methods) for e in exp[1]]
267 if len(ctmpl) == 1:
277 if len(ctmpl) == 1:
268 return ctmpl[0] # fast path for string with no template fragment
278 return ctmpl[0] # fast path for string with no template fragment
269 return (runtemplate, ctmpl)
279 return (runtemplate, ctmpl)
270
280
271 def runtemplate(context, mapping, template):
281 def runtemplate(context, mapping, template):
272 for func, data in template:
282 for func, data in template:
273 yield func(context, mapping, data)
283 yield func(context, mapping, data)
274
284
275 def buildfilter(exp, context):
285 def buildfilter(exp, context):
276 arg = compileexp(exp[1], context, methods)
286 arg = compileexp(exp[1], context, methods)
277 n = getsymbol(exp[2])
287 n = getsymbol(exp[2])
278 if n in context._filters:
288 if n in context._filters:
279 filt = context._filters[n]
289 filt = context._filters[n]
280 return (runfilter, (arg, filt))
290 return (runfilter, (arg, filt))
281 if n in funcs:
291 if n in funcs:
282 f = funcs[n]
292 f = funcs[n]
283 return (f, [arg])
293 return (f, [arg])
284 raise error.ParseError(_("unknown function '%s'") % n)
294 raise error.ParseError(_("unknown function '%s'") % n)
285
295
286 def runfilter(context, mapping, data):
296 def runfilter(context, mapping, data):
287 arg, filt = data
297 arg, filt = data
288 thing = evalfuncarg(context, mapping, arg)
298 thing = evalfuncarg(context, mapping, arg)
289 try:
299 try:
290 return filt(thing)
300 return filt(thing)
291 except (ValueError, AttributeError, TypeError):
301 except (ValueError, AttributeError, TypeError):
292 if isinstance(arg[1], tuple):
302 if isinstance(arg[1], tuple):
293 dt = arg[1][1]
303 dt = arg[1][1]
294 else:
304 else:
295 dt = arg[1]
305 dt = arg[1]
296 raise error.Abort(_("template filter '%s' is not compatible with "
306 raise error.Abort(_("template filter '%s' is not compatible with "
297 "keyword '%s'") % (filt.func_name, dt))
307 "keyword '%s'") % (filt.func_name, dt))
298
308
299 def buildmap(exp, context):
309 def buildmap(exp, context):
300 func, data = compileexp(exp[1], context, methods)
310 func, data = compileexp(exp[1], context, methods)
301 ctmpl = gettemplate(exp[2], context)
311 ctmpl = gettemplate(exp[2], context)
302 return (runmap, (func, data, ctmpl))
312 return (runmap, (func, data, ctmpl))
303
313
304 def runmap(context, mapping, data):
314 def runmap(context, mapping, data):
305 func, data, ctmpl = data
315 func, data, ctmpl = data
306 d = func(context, mapping, data)
316 d = func(context, mapping, data)
307 if util.safehasattr(d, 'itermaps'):
317 if util.safehasattr(d, 'itermaps'):
308 diter = d.itermaps()
318 diter = d.itermaps()
309 else:
319 else:
310 try:
320 try:
311 diter = iter(d)
321 diter = iter(d)
312 except TypeError:
322 except TypeError:
313 if func is runsymbol:
323 if func is runsymbol:
314 raise error.ParseError(_("keyword '%s' is not iterable") % data)
324 raise error.ParseError(_("keyword '%s' is not iterable") % data)
315 else:
325 else:
316 raise error.ParseError(_("%r is not iterable") % d)
326 raise error.ParseError(_("%r is not iterable") % d)
317
327
318 for i in diter:
328 for i in diter:
319 lm = mapping.copy()
329 lm = mapping.copy()
320 if isinstance(i, dict):
330 if isinstance(i, dict):
321 lm.update(i)
331 lm.update(i)
322 lm['originalnode'] = mapping.get('node')
332 lm['originalnode'] = mapping.get('node')
323 yield runtemplate(context, lm, ctmpl)
333 yield runtemplate(context, lm, ctmpl)
324 else:
334 else:
325 # v is not an iterable of dicts, this happen when 'key'
335 # v is not an iterable of dicts, this happen when 'key'
326 # has been fully expanded already and format is useless.
336 # has been fully expanded already and format is useless.
327 # If so, return the expanded value.
337 # If so, return the expanded value.
328 yield i
338 yield i
329
339
330 def buildfunc(exp, context):
340 def buildfunc(exp, context):
331 n = getsymbol(exp[1])
341 n = getsymbol(exp[1])
332 args = [compileexp(x, context, exprmethods) for x in getlist(exp[2])]
342 args = [compileexp(x, context, exprmethods) for x in getlist(exp[2])]
333 if n in funcs:
343 if n in funcs:
334 f = funcs[n]
344 f = funcs[n]
335 return (f, args)
345 return (f, args)
336 if n in context._filters:
346 if n in context._filters:
337 if len(args) != 1:
347 if len(args) != 1:
338 raise error.ParseError(_("filter %s expects one argument") % n)
348 raise error.ParseError(_("filter %s expects one argument") % n)
339 f = context._filters[n]
349 f = context._filters[n]
340 return (runfilter, (args[0], f))
350 return (runfilter, (args[0], f))
341 raise error.ParseError(_("unknown function '%s'") % n)
351 raise error.ParseError(_("unknown function '%s'") % n)
342
352
343 def date(context, mapping, args):
353 def date(context, mapping, args):
344 """:date(date[, fmt]): Format a date. See :hg:`help dates` for formatting
354 """:date(date[, fmt]): Format a date. See :hg:`help dates` for formatting
345 strings. The default is a Unix date format, including the timezone:
355 strings. The default is a Unix date format, including the timezone:
346 "Mon Sep 04 15:13:13 2006 0700"."""
356 "Mon Sep 04 15:13:13 2006 0700"."""
347 if not (1 <= len(args) <= 2):
357 if not (1 <= len(args) <= 2):
348 # i18n: "date" is a keyword
358 # i18n: "date" is a keyword
349 raise error.ParseError(_("date expects one or two arguments"))
359 raise error.ParseError(_("date expects one or two arguments"))
350
360
351 date = evalfuncarg(context, mapping, args[0])
361 date = evalfuncarg(context, mapping, args[0])
352 fmt = None
362 fmt = None
353 if len(args) == 2:
363 if len(args) == 2:
354 fmt = evalstring(context, mapping, args[1])
364 fmt = evalstring(context, mapping, args[1])
355 try:
365 try:
356 if fmt is None:
366 if fmt is None:
357 return util.datestr(date)
367 return util.datestr(date)
358 else:
368 else:
359 return util.datestr(date, fmt)
369 return util.datestr(date, fmt)
360 except (TypeError, ValueError):
370 except (TypeError, ValueError):
361 # i18n: "date" is a keyword
371 # i18n: "date" is a keyword
362 raise error.ParseError(_("date expects a date information"))
372 raise error.ParseError(_("date expects a date information"))
363
373
364 def diff(context, mapping, args):
374 def diff(context, mapping, args):
365 """:diff([includepattern [, excludepattern]]): Show a diff, optionally
375 """:diff([includepattern [, excludepattern]]): Show a diff, optionally
366 specifying files to include or exclude."""
376 specifying files to include or exclude."""
367 if len(args) > 2:
377 if len(args) > 2:
368 # i18n: "diff" is a keyword
378 # i18n: "diff" is a keyword
369 raise error.ParseError(_("diff expects zero, one, or two arguments"))
379 raise error.ParseError(_("diff expects zero, one, or two arguments"))
370
380
371 def getpatterns(i):
381 def getpatterns(i):
372 if i < len(args):
382 if i < len(args):
373 s = evalstring(context, mapping, args[i]).strip()
383 s = evalstring(context, mapping, args[i]).strip()
374 if s:
384 if s:
375 return [s]
385 return [s]
376 return []
386 return []
377
387
378 ctx = mapping['ctx']
388 ctx = mapping['ctx']
379 chunks = ctx.diff(match=ctx.match([], getpatterns(0), getpatterns(1)))
389 chunks = ctx.diff(match=ctx.match([], getpatterns(0), getpatterns(1)))
380
390
381 return ''.join(chunks)
391 return ''.join(chunks)
382
392
383 def fill(context, mapping, args):
393 def fill(context, mapping, args):
384 """:fill(text[, width[, initialident[, hangindent]]]): Fill many
394 """:fill(text[, width[, initialident[, hangindent]]]): Fill many
385 paragraphs with optional indentation. See the "fill" filter."""
395 paragraphs with optional indentation. See the "fill" filter."""
386 if not (1 <= len(args) <= 4):
396 if not (1 <= len(args) <= 4):
387 # i18n: "fill" is a keyword
397 # i18n: "fill" is a keyword
388 raise error.ParseError(_("fill expects one to four arguments"))
398 raise error.ParseError(_("fill expects one to four arguments"))
389
399
390 text = evalstring(context, mapping, args[0])
400 text = evalstring(context, mapping, args[0])
391 width = 76
401 width = 76
392 initindent = ''
402 initindent = ''
393 hangindent = ''
403 hangindent = ''
394 if 2 <= len(args) <= 4:
404 if 2 <= len(args) <= 4:
395 width = evalinteger(context, mapping, args[1],
405 width = evalinteger(context, mapping, args[1],
396 # i18n: "fill" is a keyword
406 # i18n: "fill" is a keyword
397 _("fill expects an integer width"))
407 _("fill expects an integer width"))
398 try:
408 try:
399 initindent = evalstring(context, mapping, args[2])
409 initindent = evalstring(context, mapping, args[2])
400 hangindent = evalstring(context, mapping, args[3])
410 hangindent = evalstring(context, mapping, args[3])
401 except IndexError:
411 except IndexError:
402 pass
412 pass
403
413
404 return templatefilters.fill(text, width, initindent, hangindent)
414 return templatefilters.fill(text, width, initindent, hangindent)
405
415
406 def pad(context, mapping, args):
416 def pad(context, mapping, args):
407 """:pad(text, width[, fillchar=' '[, right=False]]): Pad text with a
417 """:pad(text, width[, fillchar=' '[, right=False]]): Pad text with a
408 fill character."""
418 fill character."""
409 if not (2 <= len(args) <= 4):
419 if not (2 <= len(args) <= 4):
410 # i18n: "pad" is a keyword
420 # i18n: "pad" is a keyword
411 raise error.ParseError(_("pad() expects two to four arguments"))
421 raise error.ParseError(_("pad() expects two to four arguments"))
412
422
413 width = evalinteger(context, mapping, args[1],
423 width = evalinteger(context, mapping, args[1],
414 # i18n: "pad" is a keyword
424 # i18n: "pad" is a keyword
415 _("pad() expects an integer width"))
425 _("pad() expects an integer width"))
416
426
417 text = evalstring(context, mapping, args[0])
427 text = evalstring(context, mapping, args[0])
418
428
419 right = False
429 right = False
420 fillchar = ' '
430 fillchar = ' '
421 if len(args) > 2:
431 if len(args) > 2:
422 fillchar = evalstring(context, mapping, args[2])
432 fillchar = evalstring(context, mapping, args[2])
423 if len(args) > 3:
433 if len(args) > 3:
424 right = util.parsebool(args[3][1])
434 right = util.parsebool(args[3][1])
425
435
426 if right:
436 if right:
427 return text.rjust(width, fillchar)
437 return text.rjust(width, fillchar)
428 else:
438 else:
429 return text.ljust(width, fillchar)
439 return text.ljust(width, fillchar)
430
440
431 def indent(context, mapping, args):
441 def indent(context, mapping, args):
432 """:indent(text, indentchars[, firstline]): Indents all non-empty lines
442 """:indent(text, indentchars[, firstline]): Indents all non-empty lines
433 with the characters given in the indentchars string. An optional
443 with the characters given in the indentchars string. An optional
434 third parameter will override the indent for the first line only
444 third parameter will override the indent for the first line only
435 if present."""
445 if present."""
436 if not (2 <= len(args) <= 3):
446 if not (2 <= len(args) <= 3):
437 # i18n: "indent" is a keyword
447 # i18n: "indent" is a keyword
438 raise error.ParseError(_("indent() expects two or three arguments"))
448 raise error.ParseError(_("indent() expects two or three arguments"))
439
449
440 text = evalstring(context, mapping, args[0])
450 text = evalstring(context, mapping, args[0])
441 indent = evalstring(context, mapping, args[1])
451 indent = evalstring(context, mapping, args[1])
442
452
443 if len(args) == 3:
453 if len(args) == 3:
444 firstline = evalstring(context, mapping, args[2])
454 firstline = evalstring(context, mapping, args[2])
445 else:
455 else:
446 firstline = indent
456 firstline = indent
447
457
448 # the indent function doesn't indent the first line, so we do it here
458 # the indent function doesn't indent the first line, so we do it here
449 return templatefilters.indent(firstline + text, indent)
459 return templatefilters.indent(firstline + text, indent)
450
460
451 def get(context, mapping, args):
461 def get(context, mapping, args):
452 """:get(dict, key): Get an attribute/key from an object. Some keywords
462 """:get(dict, key): Get an attribute/key from an object. Some keywords
453 are complex types. This function allows you to obtain the value of an
463 are complex types. This function allows you to obtain the value of an
454 attribute on these types."""
464 attribute on these types."""
455 if len(args) != 2:
465 if len(args) != 2:
456 # i18n: "get" is a keyword
466 # i18n: "get" is a keyword
457 raise error.ParseError(_("get() expects two arguments"))
467 raise error.ParseError(_("get() expects two arguments"))
458
468
459 dictarg = evalfuncarg(context, mapping, args[0])
469 dictarg = evalfuncarg(context, mapping, args[0])
460 if not util.safehasattr(dictarg, 'get'):
470 if not util.safehasattr(dictarg, 'get'):
461 # i18n: "get" is a keyword
471 # i18n: "get" is a keyword
462 raise error.ParseError(_("get() expects a dict as first argument"))
472 raise error.ParseError(_("get() expects a dict as first argument"))
463
473
464 key = evalfuncarg(context, mapping, args[1])
474 key = evalfuncarg(context, mapping, args[1])
465 return dictarg.get(key)
475 return dictarg.get(key)
466
476
467 def if_(context, mapping, args):
477 def if_(context, mapping, args):
468 """:if(expr, then[, else]): Conditionally execute based on the result of
478 """:if(expr, then[, else]): Conditionally execute based on the result of
469 an expression."""
479 an expression."""
470 if not (2 <= len(args) <= 3):
480 if not (2 <= len(args) <= 3):
471 # i18n: "if" is a keyword
481 # i18n: "if" is a keyword
472 raise error.ParseError(_("if expects two or three arguments"))
482 raise error.ParseError(_("if expects two or three arguments"))
473
483
474 test = evalstring(context, mapping, args[0])
484 test = evalstring(context, mapping, args[0])
475 if test:
485 if test:
476 yield args[1][0](context, mapping, args[1][1])
486 yield args[1][0](context, mapping, args[1][1])
477 elif len(args) == 3:
487 elif len(args) == 3:
478 yield args[2][0](context, mapping, args[2][1])
488 yield args[2][0](context, mapping, args[2][1])
479
489
480 def ifcontains(context, mapping, args):
490 def ifcontains(context, mapping, args):
481 """:ifcontains(search, thing, then[, else]): Conditionally execute based
491 """:ifcontains(search, thing, then[, else]): Conditionally execute based
482 on whether the item "search" is in "thing"."""
492 on whether the item "search" is in "thing"."""
483 if not (3 <= len(args) <= 4):
493 if not (3 <= len(args) <= 4):
484 # i18n: "ifcontains" is a keyword
494 # i18n: "ifcontains" is a keyword
485 raise error.ParseError(_("ifcontains expects three or four arguments"))
495 raise error.ParseError(_("ifcontains expects three or four arguments"))
486
496
487 item = evalstring(context, mapping, args[0])
497 item = evalstring(context, mapping, args[0])
488 items = evalfuncarg(context, mapping, args[1])
498 items = evalfuncarg(context, mapping, args[1])
489
499
490 if item in items:
500 if item in items:
491 yield args[2][0](context, mapping, args[2][1])
501 yield args[2][0](context, mapping, args[2][1])
492 elif len(args) == 4:
502 elif len(args) == 4:
493 yield args[3][0](context, mapping, args[3][1])
503 yield args[3][0](context, mapping, args[3][1])
494
504
495 def ifeq(context, mapping, args):
505 def ifeq(context, mapping, args):
496 """:ifeq(expr1, expr2, then[, else]): Conditionally execute based on
506 """:ifeq(expr1, expr2, then[, else]): Conditionally execute based on
497 whether 2 items are equivalent."""
507 whether 2 items are equivalent."""
498 if not (3 <= len(args) <= 4):
508 if not (3 <= len(args) <= 4):
499 # i18n: "ifeq" is a keyword
509 # i18n: "ifeq" is a keyword
500 raise error.ParseError(_("ifeq expects three or four arguments"))
510 raise error.ParseError(_("ifeq expects three or four arguments"))
501
511
502 test = evalstring(context, mapping, args[0])
512 test = evalstring(context, mapping, args[0])
503 match = evalstring(context, mapping, args[1])
513 match = evalstring(context, mapping, args[1])
504 if test == match:
514 if test == match:
505 yield args[2][0](context, mapping, args[2][1])
515 yield args[2][0](context, mapping, args[2][1])
506 elif len(args) == 4:
516 elif len(args) == 4:
507 yield args[3][0](context, mapping, args[3][1])
517 yield args[3][0](context, mapping, args[3][1])
508
518
509 def join(context, mapping, args):
519 def join(context, mapping, args):
510 """:join(list, sep): Join items in a list with a delimiter."""
520 """:join(list, sep): Join items in a list with a delimiter."""
511 if not (1 <= len(args) <= 2):
521 if not (1 <= len(args) <= 2):
512 # i18n: "join" is a keyword
522 # i18n: "join" is a keyword
513 raise error.ParseError(_("join expects one or two arguments"))
523 raise error.ParseError(_("join expects one or two arguments"))
514
524
515 joinset = args[0][0](context, mapping, args[0][1])
525 joinset = args[0][0](context, mapping, args[0][1])
516 if util.safehasattr(joinset, 'itermaps'):
526 if util.safehasattr(joinset, 'itermaps'):
517 jf = joinset.joinfmt
527 jf = joinset.joinfmt
518 joinset = [jf(x) for x in joinset.itermaps()]
528 joinset = [jf(x) for x in joinset.itermaps()]
519
529
520 joiner = " "
530 joiner = " "
521 if len(args) > 1:
531 if len(args) > 1:
522 joiner = evalstring(context, mapping, args[1])
532 joiner = evalstring(context, mapping, args[1])
523
533
524 first = True
534 first = True
525 for x in joinset:
535 for x in joinset:
526 if first:
536 if first:
527 first = False
537 first = False
528 else:
538 else:
529 yield joiner
539 yield joiner
530 yield x
540 yield x
531
541
532 def label(context, mapping, args):
542 def label(context, mapping, args):
533 """:label(label, expr): Apply a label to generated content. Content with
543 """:label(label, expr): Apply a label to generated content. Content with
534 a label applied can result in additional post-processing, such as
544 a label applied can result in additional post-processing, such as
535 automatic colorization."""
545 automatic colorization."""
536 if len(args) != 2:
546 if len(args) != 2:
537 # i18n: "label" is a keyword
547 # i18n: "label" is a keyword
538 raise error.ParseError(_("label expects two arguments"))
548 raise error.ParseError(_("label expects two arguments"))
539
549
540 # ignore args[0] (the label string) since this is supposed to be a a no-op
550 # ignore args[0] (the label string) since this is supposed to be a a no-op
541 yield args[1][0](context, mapping, args[1][1])
551 yield args[1][0](context, mapping, args[1][1])
542
552
543 def latesttag(context, mapping, args):
553 def latesttag(context, mapping, args):
544 """:latesttag([pattern]): The global tags matching the given pattern on the
554 """:latesttag([pattern]): The global tags matching the given pattern on the
545 most recent globally tagged ancestor of this changeset."""
555 most recent globally tagged ancestor of this changeset."""
546 if len(args) > 1:
556 if len(args) > 1:
547 # i18n: "latesttag" is a keyword
557 # i18n: "latesttag" is a keyword
548 raise error.ParseError(_("latesttag expects at most one argument"))
558 raise error.ParseError(_("latesttag expects at most one argument"))
549
559
550 pattern = None
560 pattern = None
551 if len(args) == 1:
561 if len(args) == 1:
552 pattern = evalstring(context, mapping, args[0])
562 pattern = evalstring(context, mapping, args[0])
553
563
554 return templatekw.showlatesttags(pattern, **mapping)
564 return templatekw.showlatesttags(pattern, **mapping)
555
565
556 def localdate(context, mapping, args):
566 def localdate(context, mapping, args):
557 """:localdate(date[, tz]): Converts a date to the specified timezone.
567 """:localdate(date[, tz]): Converts a date to the specified timezone.
558 The default is local date."""
568 The default is local date."""
559 if not (1 <= len(args) <= 2):
569 if not (1 <= len(args) <= 2):
560 # i18n: "localdate" is a keyword
570 # i18n: "localdate" is a keyword
561 raise error.ParseError(_("localdate expects one or two arguments"))
571 raise error.ParseError(_("localdate expects one or two arguments"))
562
572
563 date = evalfuncarg(context, mapping, args[0])
573 date = evalfuncarg(context, mapping, args[0])
564 try:
574 try:
565 date = util.parsedate(date)
575 date = util.parsedate(date)
566 except AttributeError: # not str nor date tuple
576 except AttributeError: # not str nor date tuple
567 # i18n: "localdate" is a keyword
577 # i18n: "localdate" is a keyword
568 raise error.ParseError(_("localdate expects a date information"))
578 raise error.ParseError(_("localdate expects a date information"))
569 if len(args) >= 2:
579 if len(args) >= 2:
570 tzoffset = None
580 tzoffset = None
571 tz = evalfuncarg(context, mapping, args[1])
581 tz = evalfuncarg(context, mapping, args[1])
572 if isinstance(tz, str):
582 if isinstance(tz, str):
573 tzoffset = util.parsetimezone(tz)
583 tzoffset = util.parsetimezone(tz)
574 if tzoffset is None:
584 if tzoffset is None:
575 try:
585 try:
576 tzoffset = int(tz)
586 tzoffset = int(tz)
577 except (TypeError, ValueError):
587 except (TypeError, ValueError):
578 # i18n: "localdate" is a keyword
588 # i18n: "localdate" is a keyword
579 raise error.ParseError(_("localdate expects a timezone"))
589 raise error.ParseError(_("localdate expects a timezone"))
580 else:
590 else:
581 tzoffset = util.makedate()[1]
591 tzoffset = util.makedate()[1]
582 return (date[0], tzoffset)
592 return (date[0], tzoffset)
583
593
584 def revset(context, mapping, args):
594 def revset(context, mapping, args):
585 """:revset(query[, formatargs...]): Execute a revision set query. See
595 """:revset(query[, formatargs...]): Execute a revision set query. See
586 :hg:`help revset`."""
596 :hg:`help revset`."""
587 if not len(args) > 0:
597 if not len(args) > 0:
588 # i18n: "revset" is a keyword
598 # i18n: "revset" is a keyword
589 raise error.ParseError(_("revset expects one or more arguments"))
599 raise error.ParseError(_("revset expects one or more arguments"))
590
600
591 raw = evalstring(context, mapping, args[0])
601 raw = evalstring(context, mapping, args[0])
592 ctx = mapping['ctx']
602 ctx = mapping['ctx']
593 repo = ctx.repo()
603 repo = ctx.repo()
594
604
595 def query(expr):
605 def query(expr):
596 m = revsetmod.match(repo.ui, expr)
606 m = revsetmod.match(repo.ui, expr)
597 return m(repo)
607 return m(repo)
598
608
599 if len(args) > 1:
609 if len(args) > 1:
600 formatargs = [evalfuncarg(context, mapping, a) for a in args[1:]]
610 formatargs = [evalfuncarg(context, mapping, a) for a in args[1:]]
601 revs = query(revsetmod.formatspec(raw, *formatargs))
611 revs = query(revsetmod.formatspec(raw, *formatargs))
602 revs = list(revs)
612 revs = list(revs)
603 else:
613 else:
604 revsetcache = mapping['cache'].setdefault("revsetcache", {})
614 revsetcache = mapping['cache'].setdefault("revsetcache", {})
605 if raw in revsetcache:
615 if raw in revsetcache:
606 revs = revsetcache[raw]
616 revs = revsetcache[raw]
607 else:
617 else:
608 revs = query(raw)
618 revs = query(raw)
609 revs = list(revs)
619 revs = list(revs)
610 revsetcache[raw] = revs
620 revsetcache[raw] = revs
611
621
612 return templatekw.showrevslist("revision", revs, **mapping)
622 return templatekw.showrevslist("revision", revs, **mapping)
613
623
614 def rstdoc(context, mapping, args):
624 def rstdoc(context, mapping, args):
615 """:rstdoc(text, style): Format ReStructuredText."""
625 """:rstdoc(text, style): Format ReStructuredText."""
616 if len(args) != 2:
626 if len(args) != 2:
617 # i18n: "rstdoc" is a keyword
627 # i18n: "rstdoc" is a keyword
618 raise error.ParseError(_("rstdoc expects two arguments"))
628 raise error.ParseError(_("rstdoc expects two arguments"))
619
629
620 text = evalstring(context, mapping, args[0])
630 text = evalstring(context, mapping, args[0])
621 style = evalstring(context, mapping, args[1])
631 style = evalstring(context, mapping, args[1])
622
632
623 return minirst.format(text, style=style, keep=['verbose'])
633 return minirst.format(text, style=style, keep=['verbose'])
624
634
625 def shortest(context, mapping, args):
635 def shortest(context, mapping, args):
626 """:shortest(node, minlength=4): Obtain the shortest representation of
636 """:shortest(node, minlength=4): Obtain the shortest representation of
627 a node."""
637 a node."""
628 if not (1 <= len(args) <= 2):
638 if not (1 <= len(args) <= 2):
629 # i18n: "shortest" is a keyword
639 # i18n: "shortest" is a keyword
630 raise error.ParseError(_("shortest() expects one or two arguments"))
640 raise error.ParseError(_("shortest() expects one or two arguments"))
631
641
632 node = evalstring(context, mapping, args[0])
642 node = evalstring(context, mapping, args[0])
633
643
634 minlength = 4
644 minlength = 4
635 if len(args) > 1:
645 if len(args) > 1:
636 minlength = evalinteger(context, mapping, args[1],
646 minlength = evalinteger(context, mapping, args[1],
637 # i18n: "shortest" is a keyword
647 # i18n: "shortest" is a keyword
638 _("shortest() expects an integer minlength"))
648 _("shortest() expects an integer minlength"))
639
649
640 cl = mapping['ctx']._repo.changelog
650 cl = mapping['ctx']._repo.changelog
641 def isvalid(test):
651 def isvalid(test):
642 try:
652 try:
643 try:
653 try:
644 cl.index.partialmatch(test)
654 cl.index.partialmatch(test)
645 except AttributeError:
655 except AttributeError:
646 # Pure mercurial doesn't support partialmatch on the index.
656 # Pure mercurial doesn't support partialmatch on the index.
647 # Fallback to the slow way.
657 # Fallback to the slow way.
648 if cl._partialmatch(test) is None:
658 if cl._partialmatch(test) is None:
649 return False
659 return False
650
660
651 try:
661 try:
652 i = int(test)
662 i = int(test)
653 # if we are a pure int, then starting with zero will not be
663 # if we are a pure int, then starting with zero will not be
654 # confused as a rev; or, obviously, if the int is larger than
664 # confused as a rev; or, obviously, if the int is larger than
655 # the value of the tip rev
665 # the value of the tip rev
656 if test[0] == '0' or i > len(cl):
666 if test[0] == '0' or i > len(cl):
657 return True
667 return True
658 return False
668 return False
659 except ValueError:
669 except ValueError:
660 return True
670 return True
661 except error.RevlogError:
671 except error.RevlogError:
662 return False
672 return False
663
673
664 shortest = node
674 shortest = node
665 startlength = max(6, minlength)
675 startlength = max(6, minlength)
666 length = startlength
676 length = startlength
667 while True:
677 while True:
668 test = node[:length]
678 test = node[:length]
669 if isvalid(test):
679 if isvalid(test):
670 shortest = test
680 shortest = test
671 if length == minlength or length > startlength:
681 if length == minlength or length > startlength:
672 return shortest
682 return shortest
673 length -= 1
683 length -= 1
674 else:
684 else:
675 length += 1
685 length += 1
676 if len(shortest) <= length:
686 if len(shortest) <= length:
677 return shortest
687 return shortest
678
688
679 def strip(context, mapping, args):
689 def strip(context, mapping, args):
680 """:strip(text[, chars]): Strip characters from a string. By default,
690 """:strip(text[, chars]): Strip characters from a string. By default,
681 strips all leading and trailing whitespace."""
691 strips all leading and trailing whitespace."""
682 if not (1 <= len(args) <= 2):
692 if not (1 <= len(args) <= 2):
683 # i18n: "strip" is a keyword
693 # i18n: "strip" is a keyword
684 raise error.ParseError(_("strip expects one or two arguments"))
694 raise error.ParseError(_("strip expects one or two arguments"))
685
695
686 text = evalstring(context, mapping, args[0])
696 text = evalstring(context, mapping, args[0])
687 if len(args) == 2:
697 if len(args) == 2:
688 chars = evalstring(context, mapping, args[1])
698 chars = evalstring(context, mapping, args[1])
689 return text.strip(chars)
699 return text.strip(chars)
690 return text.strip()
700 return text.strip()
691
701
692 def sub(context, mapping, args):
702 def sub(context, mapping, args):
693 """:sub(pattern, replacement, expression): Perform text substitution
703 """:sub(pattern, replacement, expression): Perform text substitution
694 using regular expressions."""
704 using regular expressions."""
695 if len(args) != 3:
705 if len(args) != 3:
696 # i18n: "sub" is a keyword
706 # i18n: "sub" is a keyword
697 raise error.ParseError(_("sub expects three arguments"))
707 raise error.ParseError(_("sub expects three arguments"))
698
708
699 pat = evalstring(context, mapping, args[0])
709 pat = evalstring(context, mapping, args[0])
700 rpl = evalstring(context, mapping, args[1])
710 rpl = evalstring(context, mapping, args[1])
701 src = evalstring(context, mapping, args[2])
711 src = evalstring(context, mapping, args[2])
702 try:
712 try:
703 patre = re.compile(pat)
713 patre = re.compile(pat)
704 except re.error:
714 except re.error:
705 # i18n: "sub" is a keyword
715 # i18n: "sub" is a keyword
706 raise error.ParseError(_("sub got an invalid pattern: %s") % pat)
716 raise error.ParseError(_("sub got an invalid pattern: %s") % pat)
707 try:
717 try:
708 yield patre.sub(rpl, src)
718 yield patre.sub(rpl, src)
709 except re.error:
719 except re.error:
710 # i18n: "sub" is a keyword
720 # i18n: "sub" is a keyword
711 raise error.ParseError(_("sub got an invalid replacement: %s") % rpl)
721 raise error.ParseError(_("sub got an invalid replacement: %s") % rpl)
712
722
713 def startswith(context, mapping, args):
723 def startswith(context, mapping, args):
714 """:startswith(pattern, text): Returns the value from the "text" argument
724 """:startswith(pattern, text): Returns the value from the "text" argument
715 if it begins with the content from the "pattern" argument."""
725 if it begins with the content from the "pattern" argument."""
716 if len(args) != 2:
726 if len(args) != 2:
717 # i18n: "startswith" is a keyword
727 # i18n: "startswith" is a keyword
718 raise error.ParseError(_("startswith expects two arguments"))
728 raise error.ParseError(_("startswith expects two arguments"))
719
729
720 patn = evalstring(context, mapping, args[0])
730 patn = evalstring(context, mapping, args[0])
721 text = evalstring(context, mapping, args[1])
731 text = evalstring(context, mapping, args[1])
722 if text.startswith(patn):
732 if text.startswith(patn):
723 return text
733 return text
724 return ''
734 return ''
725
735
726
736
727 def word(context, mapping, args):
737 def word(context, mapping, args):
728 """:word(number, text[, separator]): Return the nth word from a string."""
738 """:word(number, text[, separator]): Return the nth word from a string."""
729 if not (2 <= len(args) <= 3):
739 if not (2 <= len(args) <= 3):
730 # i18n: "word" is a keyword
740 # i18n: "word" is a keyword
731 raise error.ParseError(_("word expects two or three arguments, got %d")
741 raise error.ParseError(_("word expects two or three arguments, got %d")
732 % len(args))
742 % len(args))
733
743
734 num = evalinteger(context, mapping, args[0],
744 num = evalinteger(context, mapping, args[0],
735 # i18n: "word" is a keyword
745 # i18n: "word" is a keyword
736 _("word expects an integer index"))
746 _("word expects an integer index"))
737 text = evalstring(context, mapping, args[1])
747 text = evalstring(context, mapping, args[1])
738 if len(args) == 3:
748 if len(args) == 3:
739 splitter = evalstring(context, mapping, args[2])
749 splitter = evalstring(context, mapping, args[2])
740 else:
750 else:
741 splitter = None
751 splitter = None
742
752
743 tokens = text.split(splitter)
753 tokens = text.split(splitter)
744 if num >= len(tokens) or num < -len(tokens):
754 if num >= len(tokens) or num < -len(tokens):
745 return ''
755 return ''
746 else:
756 else:
747 return tokens[num]
757 return tokens[num]
748
758
749 # methods to interpret function arguments or inner expressions (e.g. {_(x)})
759 # methods to interpret function arguments or inner expressions (e.g. {_(x)})
750 exprmethods = {
760 exprmethods = {
751 "integer": lambda e, c: (runinteger, e[1]),
761 "integer": lambda e, c: (runinteger, e[1]),
752 "string": lambda e, c: (runstring, e[1]),
762 "string": lambda e, c: (runstring, e[1]),
753 "symbol": lambda e, c: (runsymbol, e[1]),
763 "symbol": lambda e, c: (runsymbol, e[1]),
754 "template": buildtemplate,
764 "template": buildtemplate,
755 "group": lambda e, c: compileexp(e[1], c, exprmethods),
765 "group": lambda e, c: compileexp(e[1], c, exprmethods),
756 # ".": buildmember,
766 # ".": buildmember,
757 "|": buildfilter,
767 "|": buildfilter,
758 "%": buildmap,
768 "%": buildmap,
759 "func": buildfunc,
769 "func": buildfunc,
760 }
770 }
761
771
762 # methods to interpret top-level template (e.g. {x}, {x|_}, {x % "y"})
772 # methods to interpret top-level template (e.g. {x}, {x|_}, {x % "y"})
763 methods = exprmethods.copy()
773 methods = exprmethods.copy()
764 methods["integer"] = exprmethods["symbol"] # '{1}' as variable
774 methods["integer"] = exprmethods["symbol"] # '{1}' as variable
765
775
766 funcs = {
776 funcs = {
767 "date": date,
777 "date": date,
768 "diff": diff,
778 "diff": diff,
769 "fill": fill,
779 "fill": fill,
770 "get": get,
780 "get": get,
771 "if": if_,
781 "if": if_,
772 "ifcontains": ifcontains,
782 "ifcontains": ifcontains,
773 "ifeq": ifeq,
783 "ifeq": ifeq,
774 "indent": indent,
784 "indent": indent,
775 "join": join,
785 "join": join,
776 "label": label,
786 "label": label,
777 "latesttag": latesttag,
787 "latesttag": latesttag,
778 "localdate": localdate,
788 "localdate": localdate,
779 "pad": pad,
789 "pad": pad,
780 "revset": revset,
790 "revset": revset,
781 "rstdoc": rstdoc,
791 "rstdoc": rstdoc,
782 "shortest": shortest,
792 "shortest": shortest,
783 "startswith": startswith,
793 "startswith": startswith,
784 "strip": strip,
794 "strip": strip,
785 "sub": sub,
795 "sub": sub,
786 "word": word,
796 "word": word,
787 }
797 }
788
798
789 # template engine
799 # template engine
790
800
791 stringify = templatefilters.stringify
801 stringify = templatefilters.stringify
792
802
793 def _flatten(thing):
803 def _flatten(thing):
794 '''yield a single stream from a possibly nested set of iterators'''
804 '''yield a single stream from a possibly nested set of iterators'''
795 if isinstance(thing, str):
805 if isinstance(thing, str):
796 yield thing
806 yield thing
797 elif not util.safehasattr(thing, '__iter__'):
807 elif not util.safehasattr(thing, '__iter__'):
798 if thing is not None:
808 if thing is not None:
799 yield str(thing)
809 yield str(thing)
800 else:
810 else:
801 for i in thing:
811 for i in thing:
802 if isinstance(i, str):
812 if isinstance(i, str):
803 yield i
813 yield i
804 elif not util.safehasattr(i, '__iter__'):
814 elif not util.safehasattr(i, '__iter__'):
805 if i is not None:
815 if i is not None:
806 yield str(i)
816 yield str(i)
807 elif i is not None:
817 elif i is not None:
808 for j in _flatten(i):
818 for j in _flatten(i):
809 yield j
819 yield j
810
820
811 def unquotestring(s):
821 def unquotestring(s):
812 '''unwrap quotes'''
822 '''unwrap quotes'''
813 if len(s) < 2 or s[0] != s[-1]:
823 if len(s) < 2 or s[0] != s[-1]:
814 raise SyntaxError(_('unmatched quotes'))
824 raise SyntaxError(_('unmatched quotes'))
815 return s[1:-1]
825 return s[1:-1]
816
826
817 class engine(object):
827 class engine(object):
818 '''template expansion engine.
828 '''template expansion engine.
819
829
820 template expansion works like this. a map file contains key=value
830 template expansion works like this. a map file contains key=value
821 pairs. if value is quoted, it is treated as string. otherwise, it
831 pairs. if value is quoted, it is treated as string. otherwise, it
822 is treated as name of template file.
832 is treated as name of template file.
823
833
824 templater is asked to expand a key in map. it looks up key, and
834 templater is asked to expand a key in map. it looks up key, and
825 looks for strings like this: {foo}. it expands {foo} by looking up
835 looks for strings like this: {foo}. it expands {foo} by looking up
826 foo in map, and substituting it. expansion is recursive: it stops
836 foo in map, and substituting it. expansion is recursive: it stops
827 when there is no more {foo} to replace.
837 when there is no more {foo} to replace.
828
838
829 expansion also allows formatting and filtering.
839 expansion also allows formatting and filtering.
830
840
831 format uses key to expand each item in list. syntax is
841 format uses key to expand each item in list. syntax is
832 {key%format}.
842 {key%format}.
833
843
834 filter uses function to transform value. syntax is
844 filter uses function to transform value. syntax is
835 {key|filter1|filter2|...}.'''
845 {key|filter1|filter2|...}.'''
836
846
837 def __init__(self, loader, filters=None, defaults=None):
847 def __init__(self, loader, filters=None, defaults=None):
838 self._loader = loader
848 self._loader = loader
839 if filters is None:
849 if filters is None:
840 filters = {}
850 filters = {}
841 self._filters = filters
851 self._filters = filters
842 if defaults is None:
852 if defaults is None:
843 defaults = {}
853 defaults = {}
844 self._defaults = defaults
854 self._defaults = defaults
845 self._cache = {}
855 self._cache = {}
846
856
847 def _load(self, t):
857 def _load(self, t):
848 '''load, parse, and cache a template'''
858 '''load, parse, and cache a template'''
849 if t not in self._cache:
859 if t not in self._cache:
850 # put poison to cut recursion while compiling 't'
860 # put poison to cut recursion while compiling 't'
851 self._cache[t] = [(_runrecursivesymbol, t)]
861 self._cache[t] = [(_runrecursivesymbol, t)]
852 try:
862 try:
853 self._cache[t] = compiletemplate(self._loader(t), self)
863 self._cache[t] = compiletemplate(self._loader(t), self)
854 except: # re-raises
864 except: # re-raises
855 del self._cache[t]
865 del self._cache[t]
856 raise
866 raise
857 return self._cache[t]
867 return self._cache[t]
858
868
859 def process(self, t, mapping):
869 def process(self, t, mapping):
860 '''Perform expansion. t is name of map element to expand.
870 '''Perform expansion. t is name of map element to expand.
861 mapping contains added elements for use during expansion. Is a
871 mapping contains added elements for use during expansion. Is a
862 generator.'''
872 generator.'''
863 return _flatten(runtemplate(self, mapping, self._load(t)))
873 return _flatten(runtemplate(self, mapping, self._load(t)))
864
874
865 engines = {'default': engine}
875 engines = {'default': engine}
866
876
867 def stylelist():
877 def stylelist():
868 paths = templatepaths()
878 paths = templatepaths()
869 if not paths:
879 if not paths:
870 return _('no templates found, try `hg debuginstall` for more info')
880 return _('no templates found, try `hg debuginstall` for more info')
871 dirlist = os.listdir(paths[0])
881 dirlist = os.listdir(paths[0])
872 stylelist = []
882 stylelist = []
873 for file in dirlist:
883 for file in dirlist:
874 split = file.split(".")
884 split = file.split(".")
875 if split[0] == "map-cmdline":
885 if split[0] == "map-cmdline":
876 stylelist.append(split[1])
886 stylelist.append(split[1])
877 return ", ".join(sorted(stylelist))
887 return ", ".join(sorted(stylelist))
878
888
879 class TemplateNotFound(error.Abort):
889 class TemplateNotFound(error.Abort):
880 pass
890 pass
881
891
882 class templater(object):
892 class templater(object):
883
893
884 def __init__(self, mapfile, filters=None, defaults=None, cache=None,
894 def __init__(self, mapfile, filters=None, defaults=None, cache=None,
885 minchunk=1024, maxchunk=65536):
895 minchunk=1024, maxchunk=65536):
886 '''set up template engine.
896 '''set up template engine.
887 mapfile is name of file to read map definitions from.
897 mapfile is name of file to read map definitions from.
888 filters is dict of functions. each transforms a value into another.
898 filters is dict of functions. each transforms a value into another.
889 defaults is dict of default map definitions.'''
899 defaults is dict of default map definitions.'''
890 if filters is None:
900 if filters is None:
891 filters = {}
901 filters = {}
892 if defaults is None:
902 if defaults is None:
893 defaults = {}
903 defaults = {}
894 if cache is None:
904 if cache is None:
895 cache = {}
905 cache = {}
896 self.mapfile = mapfile or 'template'
906 self.mapfile = mapfile or 'template'
897 self.cache = cache.copy()
907 self.cache = cache.copy()
898 self.map = {}
908 self.map = {}
899 if mapfile:
909 if mapfile:
900 self.base = os.path.dirname(mapfile)
910 self.base = os.path.dirname(mapfile)
901 else:
911 else:
902 self.base = ''
912 self.base = ''
903 self.filters = templatefilters.filters.copy()
913 self.filters = templatefilters.filters.copy()
904 self.filters.update(filters)
914 self.filters.update(filters)
905 self.defaults = defaults
915 self.defaults = defaults
906 self.minchunk, self.maxchunk = minchunk, maxchunk
916 self.minchunk, self.maxchunk = minchunk, maxchunk
907 self.ecache = {}
917 self.ecache = {}
908
918
909 if not mapfile:
919 if not mapfile:
910 return
920 return
911 if not os.path.exists(mapfile):
921 if not os.path.exists(mapfile):
912 raise error.Abort(_("style '%s' not found") % mapfile,
922 raise error.Abort(_("style '%s' not found") % mapfile,
913 hint=_("available styles: %s") % stylelist())
923 hint=_("available styles: %s") % stylelist())
914
924
915 conf = config.config(includepaths=templatepaths())
925 conf = config.config(includepaths=templatepaths())
916 conf.read(mapfile)
926 conf.read(mapfile)
917
927
918 for key, val in conf[''].items():
928 for key, val in conf[''].items():
919 if not val:
929 if not val:
920 raise SyntaxError(_('%s: missing value') % conf.source('', key))
930 raise SyntaxError(_('%s: missing value') % conf.source('', key))
921 if val[0] in "'\"":
931 if val[0] in "'\"":
922 try:
932 try:
923 self.cache[key] = unquotestring(val)
933 self.cache[key] = unquotestring(val)
924 except SyntaxError as inst:
934 except SyntaxError as inst:
925 raise SyntaxError('%s: %s' %
935 raise SyntaxError('%s: %s' %
926 (conf.source('', key), inst.args[0]))
936 (conf.source('', key), inst.args[0]))
927 else:
937 else:
928 val = 'default', val
938 val = 'default', val
929 if ':' in val[1]:
939 if ':' in val[1]:
930 val = val[1].split(':', 1)
940 val = val[1].split(':', 1)
931 self.map[key] = val[0], os.path.join(self.base, val[1])
941 self.map[key] = val[0], os.path.join(self.base, val[1])
932
942
933 def __contains__(self, key):
943 def __contains__(self, key):
934 return key in self.cache or key in self.map
944 return key in self.cache or key in self.map
935
945
936 def load(self, t):
946 def load(self, t):
937 '''Get the template for the given template name. Use a local cache.'''
947 '''Get the template for the given template name. Use a local cache.'''
938 if t not in self.cache:
948 if t not in self.cache:
939 try:
949 try:
940 self.cache[t] = util.readfile(self.map[t][1])
950 self.cache[t] = util.readfile(self.map[t][1])
941 except KeyError as inst:
951 except KeyError as inst:
942 raise TemplateNotFound(_('"%s" not in template map') %
952 raise TemplateNotFound(_('"%s" not in template map') %
943 inst.args[0])
953 inst.args[0])
944 except IOError as inst:
954 except IOError as inst:
945 raise IOError(inst.args[0], _('template file %s: %s') %
955 raise IOError(inst.args[0], _('template file %s: %s') %
946 (self.map[t][1], inst.args[1]))
956 (self.map[t][1], inst.args[1]))
947 return self.cache[t]
957 return self.cache[t]
948
958
949 def __call__(self, t, **mapping):
959 def __call__(self, t, **mapping):
950 ttype = t in self.map and self.map[t][0] or 'default'
960 ttype = t in self.map and self.map[t][0] or 'default'
951 if ttype not in self.ecache:
961 if ttype not in self.ecache:
952 self.ecache[ttype] = engines[ttype](self.load,
962 self.ecache[ttype] = engines[ttype](self.load,
953 self.filters, self.defaults)
963 self.filters, self.defaults)
954 proc = self.ecache[ttype]
964 proc = self.ecache[ttype]
955
965
956 stream = proc.process(t, mapping)
966 stream = proc.process(t, mapping)
957 if self.minchunk:
967 if self.minchunk:
958 stream = util.increasingchunks(stream, min=self.minchunk,
968 stream = util.increasingchunks(stream, min=self.minchunk,
959 max=self.maxchunk)
969 max=self.maxchunk)
960 return stream
970 return stream
961
971
962 def templatepaths():
972 def templatepaths():
963 '''return locations used for template files.'''
973 '''return locations used for template files.'''
964 pathsrel = ['templates']
974 pathsrel = ['templates']
965 paths = [os.path.normpath(os.path.join(util.datapath, f))
975 paths = [os.path.normpath(os.path.join(util.datapath, f))
966 for f in pathsrel]
976 for f in pathsrel]
967 return [p for p in paths if os.path.isdir(p)]
977 return [p for p in paths if os.path.isdir(p)]
968
978
969 def templatepath(name):
979 def templatepath(name):
970 '''return location of template file. returns None if not found.'''
980 '''return location of template file. returns None if not found.'''
971 for p in templatepaths():
981 for p in templatepaths():
972 f = os.path.join(p, name)
982 f = os.path.join(p, name)
973 if os.path.exists(f):
983 if os.path.exists(f):
974 return f
984 return f
975 return None
985 return None
976
986
977 def stylemap(styles, paths=None):
987 def stylemap(styles, paths=None):
978 """Return path to mapfile for a given style.
988 """Return path to mapfile for a given style.
979
989
980 Searches mapfile in the following locations:
990 Searches mapfile in the following locations:
981 1. templatepath/style/map
991 1. templatepath/style/map
982 2. templatepath/map-style
992 2. templatepath/map-style
983 3. templatepath/map
993 3. templatepath/map
984 """
994 """
985
995
986 if paths is None:
996 if paths is None:
987 paths = templatepaths()
997 paths = templatepaths()
988 elif isinstance(paths, str):
998 elif isinstance(paths, str):
989 paths = [paths]
999 paths = [paths]
990
1000
991 if isinstance(styles, str):
1001 if isinstance(styles, str):
992 styles = [styles]
1002 styles = [styles]
993
1003
994 for style in styles:
1004 for style in styles:
995 # only plain name is allowed to honor template paths
1005 # only plain name is allowed to honor template paths
996 if (not style
1006 if (not style
997 or style in (os.curdir, os.pardir)
1007 or style in (os.curdir, os.pardir)
998 or os.sep in style
1008 or os.sep in style
999 or os.altsep and os.altsep in style):
1009 or os.altsep and os.altsep in style):
1000 continue
1010 continue
1001 locations = [os.path.join(style, 'map'), 'map-' + style]
1011 locations = [os.path.join(style, 'map'), 'map-' + style]
1002 locations.append('map')
1012 locations.append('map')
1003
1013
1004 for path in paths:
1014 for path in paths:
1005 for location in locations:
1015 for location in locations:
1006 mapfile = os.path.join(path, location)
1016 mapfile = os.path.join(path, location)
1007 if os.path.isfile(mapfile):
1017 if os.path.isfile(mapfile):
1008 return style, mapfile
1018 return style, mapfile
1009
1019
1010 raise RuntimeError("No hgweb templates found in %r" % paths)
1020 raise RuntimeError("No hgweb templates found in %r" % paths)
1011
1021
1012 # tell hggettext to extract docstrings from these functions:
1022 # tell hggettext to extract docstrings from these functions:
1013 i18nfunctions = funcs.values()
1023 i18nfunctions = funcs.values()
@@ -1,3641 +1,3646
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 -T '{file_copies % "{source} -> {name}\n"}' -r .
48 $ hg log -T '{file_copies % "{source} -> {name}\n"}' -r .
49 second -> fourth
49 second -> fourth
50 $ hg log -T '{rev} {ifcontains("fourth", file_copies, "t", "f")}\n' -r .:7
50 $ hg log -T '{rev} {ifcontains("fourth", file_copies, "t", "f")}\n' -r .:7
51 8 t
51 8 t
52 7 f
52 7 f
53
53
54 Working-directory revision has special identifiers, though they are still
54 Working-directory revision has special identifiers, though they are still
55 experimental:
55 experimental:
56
56
57 $ hg log -r 'wdir()' -T '{rev}:{node}\n'
57 $ hg log -r 'wdir()' -T '{rev}:{node}\n'
58 2147483647:ffffffffffffffffffffffffffffffffffffffff
58 2147483647:ffffffffffffffffffffffffffffffffffffffff
59
59
60 Some keywords are invalid for working-directory revision, but they should
60 Some keywords are invalid for working-directory revision, but they should
61 never cause crash:
61 never cause crash:
62
62
63 $ hg log -r 'wdir()' -T '{manifest}\n'
63 $ hg log -r 'wdir()' -T '{manifest}\n'
64
64
65
65
66 Quoting for ui.logtemplate
66 Quoting for ui.logtemplate
67
67
68 $ hg tip --config "ui.logtemplate={rev}\n"
68 $ hg tip --config "ui.logtemplate={rev}\n"
69 8
69 8
70 $ hg tip --config "ui.logtemplate='{rev}\n'"
70 $ hg tip --config "ui.logtemplate='{rev}\n'"
71 8
71 8
72 $ hg tip --config 'ui.logtemplate="{rev}\n"'
72 $ hg tip --config 'ui.logtemplate="{rev}\n"'
73 8
73 8
74
74
75 Make sure user/global hgrc does not affect tests
75 Make sure user/global hgrc does not affect tests
76
76
77 $ echo '[ui]' > .hg/hgrc
77 $ echo '[ui]' > .hg/hgrc
78 $ echo 'logtemplate =' >> .hg/hgrc
78 $ echo 'logtemplate =' >> .hg/hgrc
79 $ echo 'style =' >> .hg/hgrc
79 $ echo 'style =' >> .hg/hgrc
80
80
81 Add some simple styles to settings
81 Add some simple styles to settings
82
82
83 $ echo '[templates]' >> .hg/hgrc
83 $ echo '[templates]' >> .hg/hgrc
84 $ printf 'simple = "{rev}\\n"\n' >> .hg/hgrc
84 $ printf 'simple = "{rev}\\n"\n' >> .hg/hgrc
85 $ printf 'simple2 = {rev}\\n\n' >> .hg/hgrc
85 $ printf 'simple2 = {rev}\\n\n' >> .hg/hgrc
86
86
87 $ hg log -l1 -Tsimple
87 $ hg log -l1 -Tsimple
88 8
88 8
89 $ hg log -l1 -Tsimple2
89 $ hg log -l1 -Tsimple2
90 8
90 8
91
91
92 Test templates and style maps in files:
92 Test templates and style maps in files:
93
93
94 $ echo "{rev}" > tmpl
94 $ echo "{rev}" > tmpl
95 $ hg log -l1 -T./tmpl
95 $ hg log -l1 -T./tmpl
96 8
96 8
97 $ hg log -l1 -Tblah/blah
97 $ hg log -l1 -Tblah/blah
98 blah/blah (no-eol)
98 blah/blah (no-eol)
99
99
100 $ printf 'changeset = "{rev}\\n"\n' > map-simple
100 $ printf 'changeset = "{rev}\\n"\n' > map-simple
101 $ hg log -l1 -T./map-simple
101 $ hg log -l1 -T./map-simple
102 8
102 8
103
103
104 Template should precede style option
104 Template should precede style option
105
105
106 $ hg log -l1 --style default -T '{rev}\n'
106 $ hg log -l1 --style default -T '{rev}\n'
107 8
107 8
108
108
109 Add a commit with empty description, to ensure that the templates
109 Add a commit with empty description, to ensure that the templates
110 below will omit the description line.
110 below will omit the description line.
111
111
112 $ echo c >> c
112 $ echo c >> c
113 $ hg add c
113 $ hg add c
114 $ hg commit -qm ' '
114 $ hg commit -qm ' '
115
115
116 Default style is like normal output. Phases style should be the same
116 Default style is like normal output. Phases style should be the same
117 as default style, except for extra phase lines.
117 as default style, except for extra phase lines.
118
118
119 $ hg log > log.out
119 $ hg log > log.out
120 $ hg log --style default > style.out
120 $ hg log --style default > style.out
121 $ cmp log.out style.out || diff -u log.out style.out
121 $ cmp log.out style.out || diff -u log.out style.out
122 $ hg log -T phases > phases.out
122 $ hg log -T phases > phases.out
123 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
123 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
124 +phase: draft
124 +phase: draft
125 +phase: draft
125 +phase: draft
126 +phase: draft
126 +phase: draft
127 +phase: draft
127 +phase: draft
128 +phase: draft
128 +phase: draft
129 +phase: draft
129 +phase: draft
130 +phase: draft
130 +phase: draft
131 +phase: draft
131 +phase: draft
132 +phase: draft
132 +phase: draft
133 +phase: draft
133 +phase: draft
134
134
135 $ hg log -v > log.out
135 $ hg log -v > log.out
136 $ hg log -v --style default > style.out
136 $ hg log -v --style default > style.out
137 $ cmp log.out style.out || diff -u log.out style.out
137 $ cmp log.out style.out || diff -u log.out style.out
138 $ hg log -v -T phases > phases.out
138 $ hg log -v -T phases > phases.out
139 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
139 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
140 +phase: draft
140 +phase: draft
141 +phase: draft
141 +phase: draft
142 +phase: draft
142 +phase: draft
143 +phase: draft
143 +phase: draft
144 +phase: draft
144 +phase: draft
145 +phase: draft
145 +phase: draft
146 +phase: draft
146 +phase: draft
147 +phase: draft
147 +phase: draft
148 +phase: draft
148 +phase: draft
149 +phase: draft
149 +phase: draft
150
150
151 $ hg log -q > log.out
151 $ hg log -q > log.out
152 $ hg log -q --style default > style.out
152 $ hg log -q --style default > style.out
153 $ cmp log.out style.out || diff -u log.out style.out
153 $ cmp log.out style.out || diff -u log.out style.out
154 $ hg log -q -T phases > phases.out
154 $ hg log -q -T phases > phases.out
155 $ cmp log.out phases.out || diff -u log.out phases.out
155 $ cmp log.out phases.out || diff -u log.out phases.out
156
156
157 $ hg log --debug > log.out
157 $ hg log --debug > log.out
158 $ hg log --debug --style default > style.out
158 $ hg log --debug --style default > style.out
159 $ cmp log.out style.out || diff -u log.out style.out
159 $ cmp log.out style.out || diff -u log.out style.out
160 $ hg log --debug -T phases > phases.out
160 $ hg log --debug -T phases > phases.out
161 $ cmp log.out phases.out || diff -u log.out phases.out
161 $ cmp log.out phases.out || diff -u log.out phases.out
162
162
163 Default style of working-directory revision should also be the same (but
163 Default style of working-directory revision should also be the same (but
164 date may change while running tests):
164 date may change while running tests):
165
165
166 $ hg log -r 'wdir()' | sed 's|^date:.*|date:|' > log.out
166 $ hg log -r 'wdir()' | sed 's|^date:.*|date:|' > log.out
167 $ hg log -r 'wdir()' --style default | sed 's|^date:.*|date:|' > style.out
167 $ hg log -r 'wdir()' --style default | sed 's|^date:.*|date:|' > style.out
168 $ cmp log.out style.out || diff -u log.out style.out
168 $ cmp log.out style.out || diff -u log.out style.out
169
169
170 $ hg log -r 'wdir()' -v | sed 's|^date:.*|date:|' > log.out
170 $ hg log -r 'wdir()' -v | sed 's|^date:.*|date:|' > log.out
171 $ hg log -r 'wdir()' -v --style default | sed 's|^date:.*|date:|' > style.out
171 $ hg log -r 'wdir()' -v --style default | sed 's|^date:.*|date:|' > style.out
172 $ cmp log.out style.out || diff -u log.out style.out
172 $ cmp log.out style.out || diff -u log.out style.out
173
173
174 $ hg log -r 'wdir()' -q > log.out
174 $ hg log -r 'wdir()' -q > log.out
175 $ hg log -r 'wdir()' -q --style default > style.out
175 $ hg log -r 'wdir()' -q --style default > style.out
176 $ cmp log.out style.out || diff -u log.out style.out
176 $ cmp log.out style.out || diff -u log.out style.out
177
177
178 $ hg log -r 'wdir()' --debug | sed 's|^date:.*|date:|' > log.out
178 $ hg log -r 'wdir()' --debug | sed 's|^date:.*|date:|' > log.out
179 $ hg log -r 'wdir()' --debug --style default \
179 $ hg log -r 'wdir()' --debug --style default \
180 > | sed 's|^date:.*|date:|' > style.out
180 > | sed 's|^date:.*|date:|' > style.out
181 $ cmp log.out style.out || diff -u log.out style.out
181 $ cmp log.out style.out || diff -u log.out style.out
182
182
183 Default style should also preserve color information (issue2866):
183 Default style should also preserve color information (issue2866):
184
184
185 $ cp $HGRCPATH $HGRCPATH-bak
185 $ cp $HGRCPATH $HGRCPATH-bak
186 $ cat <<EOF >> $HGRCPATH
186 $ cat <<EOF >> $HGRCPATH
187 > [extensions]
187 > [extensions]
188 > color=
188 > color=
189 > EOF
189 > EOF
190
190
191 $ hg --color=debug log > log.out
191 $ hg --color=debug log > log.out
192 $ hg --color=debug log --style default > style.out
192 $ hg --color=debug log --style default > style.out
193 $ cmp log.out style.out || diff -u log.out style.out
193 $ cmp log.out style.out || diff -u log.out style.out
194 $ hg --color=debug log -T phases > phases.out
194 $ hg --color=debug log -T phases > phases.out
195 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
195 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
196 +[log.phase|phase: draft]
196 +[log.phase|phase: draft]
197 +[log.phase|phase: draft]
197 +[log.phase|phase: draft]
198 +[log.phase|phase: draft]
198 +[log.phase|phase: draft]
199 +[log.phase|phase: draft]
199 +[log.phase|phase: draft]
200 +[log.phase|phase: draft]
200 +[log.phase|phase: draft]
201 +[log.phase|phase: draft]
201 +[log.phase|phase: draft]
202 +[log.phase|phase: draft]
202 +[log.phase|phase: draft]
203 +[log.phase|phase: draft]
203 +[log.phase|phase: draft]
204 +[log.phase|phase: draft]
204 +[log.phase|phase: draft]
205 +[log.phase|phase: draft]
205 +[log.phase|phase: draft]
206
206
207 $ hg --color=debug -v log > log.out
207 $ hg --color=debug -v log > log.out
208 $ hg --color=debug -v log --style default > style.out
208 $ hg --color=debug -v log --style default > style.out
209 $ cmp log.out style.out || diff -u log.out style.out
209 $ cmp log.out style.out || diff -u log.out style.out
210 $ hg --color=debug -v log -T phases > phases.out
210 $ hg --color=debug -v log -T phases > phases.out
211 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
211 $ diff -U 0 log.out phases.out | egrep -v '^---|^\+\+\+|^@@'
212 +[log.phase|phase: draft]
212 +[log.phase|phase: draft]
213 +[log.phase|phase: draft]
213 +[log.phase|phase: draft]
214 +[log.phase|phase: draft]
214 +[log.phase|phase: draft]
215 +[log.phase|phase: draft]
215 +[log.phase|phase: draft]
216 +[log.phase|phase: draft]
216 +[log.phase|phase: draft]
217 +[log.phase|phase: draft]
217 +[log.phase|phase: draft]
218 +[log.phase|phase: draft]
218 +[log.phase|phase: draft]
219 +[log.phase|phase: draft]
219 +[log.phase|phase: draft]
220 +[log.phase|phase: draft]
220 +[log.phase|phase: draft]
221 +[log.phase|phase: draft]
221 +[log.phase|phase: draft]
222
222
223 $ hg --color=debug -q log > log.out
223 $ hg --color=debug -q log > log.out
224 $ hg --color=debug -q log --style default > style.out
224 $ hg --color=debug -q log --style default > style.out
225 $ cmp log.out style.out || diff -u log.out style.out
225 $ cmp log.out style.out || diff -u log.out style.out
226 $ hg --color=debug -q log -T phases > phases.out
226 $ hg --color=debug -q log -T phases > phases.out
227 $ cmp log.out phases.out || diff -u log.out phases.out
227 $ cmp log.out phases.out || diff -u log.out phases.out
228
228
229 $ hg --color=debug --debug log > log.out
229 $ hg --color=debug --debug log > log.out
230 $ hg --color=debug --debug log --style default > style.out
230 $ hg --color=debug --debug log --style default > style.out
231 $ cmp log.out style.out || diff -u log.out style.out
231 $ cmp log.out style.out || diff -u log.out style.out
232 $ hg --color=debug --debug log -T phases > phases.out
232 $ hg --color=debug --debug log -T phases > phases.out
233 $ cmp log.out phases.out || diff -u log.out phases.out
233 $ cmp log.out phases.out || diff -u log.out phases.out
234
234
235 $ mv $HGRCPATH-bak $HGRCPATH
235 $ mv $HGRCPATH-bak $HGRCPATH
236
236
237 Remove commit with empty commit message, so as to not pollute further
237 Remove commit with empty commit message, so as to not pollute further
238 tests.
238 tests.
239
239
240 $ hg --config extensions.strip= strip -q .
240 $ hg --config extensions.strip= strip -q .
241
241
242 Revision with no copies (used to print a traceback):
242 Revision with no copies (used to print a traceback):
243
243
244 $ hg tip -v --template '\n'
244 $ hg tip -v --template '\n'
245
245
246
246
247 Compact style works:
247 Compact style works:
248
248
249 $ hg log -Tcompact
249 $ hg log -Tcompact
250 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
250 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
251 third
251 third
252
252
253 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
253 7:-1 29114dbae42b 1970-01-12 13:46 +0000 user
254 second
254 second
255
255
256 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
256 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
257 merge
257 merge
258
258
259 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
259 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
260 new head
260 new head
261
261
262 4 bbe44766e73d 1970-01-17 04:53 +0000 person
262 4 bbe44766e73d 1970-01-17 04:53 +0000 person
263 new branch
263 new branch
264
264
265 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
265 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
266 no user, no domain
266 no user, no domain
267
267
268 2 97054abb4ab8 1970-01-14 21:20 +0000 other
268 2 97054abb4ab8 1970-01-14 21:20 +0000 other
269 no person
269 no person
270
270
271 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
271 1 b608e9d1a3f0 1970-01-13 17:33 +0000 other
272 other 1
272 other 1
273
273
274 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
274 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 user
275 line 1
275 line 1
276
276
277
277
278 $ hg log -v --style compact
278 $ hg log -v --style compact
279 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
279 8[tip] 95c24699272e 2020-01-01 10:01 +0000 test
280 third
280 third
281
281
282 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
282 7:-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
283 second
283 second
284
284
285 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
285 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
286 merge
286 merge
287
287
288 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
288 5:3 13207e5a10d9 1970-01-18 08:40 +0000 person
289 new head
289 new head
290
290
291 4 bbe44766e73d 1970-01-17 04:53 +0000 person
291 4 bbe44766e73d 1970-01-17 04:53 +0000 person
292 new branch
292 new branch
293
293
294 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
294 3 10e46f2dcbf4 1970-01-16 01:06 +0000 person
295 no user, no domain
295 no user, no domain
296
296
297 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
297 2 97054abb4ab8 1970-01-14 21:20 +0000 other@place
298 no person
298 no person
299
299
300 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
300 1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
301 other 1
301 other 1
302 other 2
302 other 2
303
303
304 other 3
304 other 3
305
305
306 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
306 0 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
307 line 1
307 line 1
308 line 2
308 line 2
309
309
310
310
311 $ hg log --debug --style compact
311 $ hg log --debug --style compact
312 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
312 8[tip]:7,-1 95c24699272e 2020-01-01 10:01 +0000 test
313 third
313 third
314
314
315 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
315 7:-1,-1 29114dbae42b 1970-01-12 13:46 +0000 User Name <user@hostname>
316 second
316 second
317
317
318 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
318 6:5,4 d41e714fe50d 1970-01-18 08:40 +0000 person
319 merge
319 merge
320
320
321 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
321 5:3,-1 13207e5a10d9 1970-01-18 08:40 +0000 person
322 new head
322 new head
323
323
324 4:3,-1 bbe44766e73d 1970-01-17 04:53 +0000 person
324 4:3,-1 bbe44766e73d 1970-01-17 04:53 +0000 person
325 new branch
325 new branch
326
326
327 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
327 3:2,-1 10e46f2dcbf4 1970-01-16 01:06 +0000 person
328 no user, no domain
328 no user, no domain
329
329
330 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
330 2:1,-1 97054abb4ab8 1970-01-14 21:20 +0000 other@place
331 no person
331 no person
332
332
333 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
333 1:0,-1 b608e9d1a3f0 1970-01-13 17:33 +0000 A. N. Other <other@place>
334 other 1
334 other 1
335 other 2
335 other 2
336
336
337 other 3
337 other 3
338
338
339 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
339 0:-1,-1 1e4e1b8f71e0 1970-01-12 13:46 +0000 User Name <user@hostname>
340 line 1
340 line 1
341 line 2
341 line 2
342
342
343
343
344 Test xml styles:
344 Test xml styles:
345
345
346 $ hg log --style xml -r 'not all()'
346 $ hg log --style xml -r 'not all()'
347 <?xml version="1.0"?>
347 <?xml version="1.0"?>
348 <log>
348 <log>
349 </log>
349 </log>
350
350
351 $ hg log --style xml
351 $ hg log --style xml
352 <?xml version="1.0"?>
352 <?xml version="1.0"?>
353 <log>
353 <log>
354 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
354 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
355 <tag>tip</tag>
355 <tag>tip</tag>
356 <author email="test">test</author>
356 <author email="test">test</author>
357 <date>2020-01-01T10:01:00+00:00</date>
357 <date>2020-01-01T10:01:00+00:00</date>
358 <msg xml:space="preserve">third</msg>
358 <msg xml:space="preserve">third</msg>
359 </logentry>
359 </logentry>
360 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
360 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
361 <parent revision="-1" node="0000000000000000000000000000000000000000" />
361 <parent revision="-1" node="0000000000000000000000000000000000000000" />
362 <author email="user@hostname">User Name</author>
362 <author email="user@hostname">User Name</author>
363 <date>1970-01-12T13:46:40+00:00</date>
363 <date>1970-01-12T13:46:40+00:00</date>
364 <msg xml:space="preserve">second</msg>
364 <msg xml:space="preserve">second</msg>
365 </logentry>
365 </logentry>
366 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
366 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
367 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
367 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
368 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
368 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
369 <author email="person">person</author>
369 <author email="person">person</author>
370 <date>1970-01-18T08:40:01+00:00</date>
370 <date>1970-01-18T08:40:01+00:00</date>
371 <msg xml:space="preserve">merge</msg>
371 <msg xml:space="preserve">merge</msg>
372 </logentry>
372 </logentry>
373 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
373 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
374 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
374 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
375 <author email="person">person</author>
375 <author email="person">person</author>
376 <date>1970-01-18T08:40:00+00:00</date>
376 <date>1970-01-18T08:40:00+00:00</date>
377 <msg xml:space="preserve">new head</msg>
377 <msg xml:space="preserve">new head</msg>
378 </logentry>
378 </logentry>
379 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
379 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
380 <branch>foo</branch>
380 <branch>foo</branch>
381 <author email="person">person</author>
381 <author email="person">person</author>
382 <date>1970-01-17T04:53:20+00:00</date>
382 <date>1970-01-17T04:53:20+00:00</date>
383 <msg xml:space="preserve">new branch</msg>
383 <msg xml:space="preserve">new branch</msg>
384 </logentry>
384 </logentry>
385 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
385 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
386 <author email="person">person</author>
386 <author email="person">person</author>
387 <date>1970-01-16T01:06:40+00:00</date>
387 <date>1970-01-16T01:06:40+00:00</date>
388 <msg xml:space="preserve">no user, no domain</msg>
388 <msg xml:space="preserve">no user, no domain</msg>
389 </logentry>
389 </logentry>
390 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
390 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
391 <author email="other@place">other</author>
391 <author email="other@place">other</author>
392 <date>1970-01-14T21:20:00+00:00</date>
392 <date>1970-01-14T21:20:00+00:00</date>
393 <msg xml:space="preserve">no person</msg>
393 <msg xml:space="preserve">no person</msg>
394 </logentry>
394 </logentry>
395 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
395 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
396 <author email="other@place">A. N. Other</author>
396 <author email="other@place">A. N. Other</author>
397 <date>1970-01-13T17:33:20+00:00</date>
397 <date>1970-01-13T17:33:20+00:00</date>
398 <msg xml:space="preserve">other 1
398 <msg xml:space="preserve">other 1
399 other 2
399 other 2
400
400
401 other 3</msg>
401 other 3</msg>
402 </logentry>
402 </logentry>
403 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
403 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
404 <author email="user@hostname">User Name</author>
404 <author email="user@hostname">User Name</author>
405 <date>1970-01-12T13:46:40+00:00</date>
405 <date>1970-01-12T13:46:40+00:00</date>
406 <msg xml:space="preserve">line 1
406 <msg xml:space="preserve">line 1
407 line 2</msg>
407 line 2</msg>
408 </logentry>
408 </logentry>
409 </log>
409 </log>
410
410
411 $ hg log -v --style xml
411 $ hg log -v --style xml
412 <?xml version="1.0"?>
412 <?xml version="1.0"?>
413 <log>
413 <log>
414 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
414 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
415 <tag>tip</tag>
415 <tag>tip</tag>
416 <author email="test">test</author>
416 <author email="test">test</author>
417 <date>2020-01-01T10:01:00+00:00</date>
417 <date>2020-01-01T10:01:00+00:00</date>
418 <msg xml:space="preserve">third</msg>
418 <msg xml:space="preserve">third</msg>
419 <paths>
419 <paths>
420 <path action="A">fourth</path>
420 <path action="A">fourth</path>
421 <path action="A">third</path>
421 <path action="A">third</path>
422 <path action="R">second</path>
422 <path action="R">second</path>
423 </paths>
423 </paths>
424 <copies>
424 <copies>
425 <copy source="second">fourth</copy>
425 <copy source="second">fourth</copy>
426 </copies>
426 </copies>
427 </logentry>
427 </logentry>
428 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
428 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
429 <parent revision="-1" node="0000000000000000000000000000000000000000" />
429 <parent revision="-1" node="0000000000000000000000000000000000000000" />
430 <author email="user@hostname">User Name</author>
430 <author email="user@hostname">User Name</author>
431 <date>1970-01-12T13:46:40+00:00</date>
431 <date>1970-01-12T13:46:40+00:00</date>
432 <msg xml:space="preserve">second</msg>
432 <msg xml:space="preserve">second</msg>
433 <paths>
433 <paths>
434 <path action="A">second</path>
434 <path action="A">second</path>
435 </paths>
435 </paths>
436 </logentry>
436 </logentry>
437 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
437 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
438 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
438 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
439 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
439 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
440 <author email="person">person</author>
440 <author email="person">person</author>
441 <date>1970-01-18T08:40:01+00:00</date>
441 <date>1970-01-18T08:40:01+00:00</date>
442 <msg xml:space="preserve">merge</msg>
442 <msg xml:space="preserve">merge</msg>
443 <paths>
443 <paths>
444 </paths>
444 </paths>
445 </logentry>
445 </logentry>
446 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
446 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
447 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
447 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
448 <author email="person">person</author>
448 <author email="person">person</author>
449 <date>1970-01-18T08:40:00+00:00</date>
449 <date>1970-01-18T08:40:00+00:00</date>
450 <msg xml:space="preserve">new head</msg>
450 <msg xml:space="preserve">new head</msg>
451 <paths>
451 <paths>
452 <path action="A">d</path>
452 <path action="A">d</path>
453 </paths>
453 </paths>
454 </logentry>
454 </logentry>
455 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
455 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
456 <branch>foo</branch>
456 <branch>foo</branch>
457 <author email="person">person</author>
457 <author email="person">person</author>
458 <date>1970-01-17T04:53:20+00:00</date>
458 <date>1970-01-17T04:53:20+00:00</date>
459 <msg xml:space="preserve">new branch</msg>
459 <msg xml:space="preserve">new branch</msg>
460 <paths>
460 <paths>
461 </paths>
461 </paths>
462 </logentry>
462 </logentry>
463 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
463 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
464 <author email="person">person</author>
464 <author email="person">person</author>
465 <date>1970-01-16T01:06:40+00:00</date>
465 <date>1970-01-16T01:06:40+00:00</date>
466 <msg xml:space="preserve">no user, no domain</msg>
466 <msg xml:space="preserve">no user, no domain</msg>
467 <paths>
467 <paths>
468 <path action="M">c</path>
468 <path action="M">c</path>
469 </paths>
469 </paths>
470 </logentry>
470 </logentry>
471 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
471 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
472 <author email="other@place">other</author>
472 <author email="other@place">other</author>
473 <date>1970-01-14T21:20:00+00:00</date>
473 <date>1970-01-14T21:20:00+00:00</date>
474 <msg xml:space="preserve">no person</msg>
474 <msg xml:space="preserve">no person</msg>
475 <paths>
475 <paths>
476 <path action="A">c</path>
476 <path action="A">c</path>
477 </paths>
477 </paths>
478 </logentry>
478 </logentry>
479 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
479 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
480 <author email="other@place">A. N. Other</author>
480 <author email="other@place">A. N. Other</author>
481 <date>1970-01-13T17:33:20+00:00</date>
481 <date>1970-01-13T17:33:20+00:00</date>
482 <msg xml:space="preserve">other 1
482 <msg xml:space="preserve">other 1
483 other 2
483 other 2
484
484
485 other 3</msg>
485 other 3</msg>
486 <paths>
486 <paths>
487 <path action="A">b</path>
487 <path action="A">b</path>
488 </paths>
488 </paths>
489 </logentry>
489 </logentry>
490 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
490 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
491 <author email="user@hostname">User Name</author>
491 <author email="user@hostname">User Name</author>
492 <date>1970-01-12T13:46:40+00:00</date>
492 <date>1970-01-12T13:46:40+00:00</date>
493 <msg xml:space="preserve">line 1
493 <msg xml:space="preserve">line 1
494 line 2</msg>
494 line 2</msg>
495 <paths>
495 <paths>
496 <path action="A">a</path>
496 <path action="A">a</path>
497 </paths>
497 </paths>
498 </logentry>
498 </logentry>
499 </log>
499 </log>
500
500
501 $ hg log --debug --style xml
501 $ hg log --debug --style xml
502 <?xml version="1.0"?>
502 <?xml version="1.0"?>
503 <log>
503 <log>
504 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
504 <logentry revision="8" node="95c24699272ef57d062b8bccc32c878bf841784a">
505 <tag>tip</tag>
505 <tag>tip</tag>
506 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
506 <parent revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453" />
507 <parent revision="-1" node="0000000000000000000000000000000000000000" />
507 <parent revision="-1" node="0000000000000000000000000000000000000000" />
508 <author email="test">test</author>
508 <author email="test">test</author>
509 <date>2020-01-01T10:01:00+00:00</date>
509 <date>2020-01-01T10:01:00+00:00</date>
510 <msg xml:space="preserve">third</msg>
510 <msg xml:space="preserve">third</msg>
511 <paths>
511 <paths>
512 <path action="A">fourth</path>
512 <path action="A">fourth</path>
513 <path action="A">third</path>
513 <path action="A">third</path>
514 <path action="R">second</path>
514 <path action="R">second</path>
515 </paths>
515 </paths>
516 <copies>
516 <copies>
517 <copy source="second">fourth</copy>
517 <copy source="second">fourth</copy>
518 </copies>
518 </copies>
519 <extra key="branch">default</extra>
519 <extra key="branch">default</extra>
520 </logentry>
520 </logentry>
521 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
521 <logentry revision="7" node="29114dbae42b9f078cf2714dbe3a86bba8ec7453">
522 <parent revision="-1" node="0000000000000000000000000000000000000000" />
522 <parent revision="-1" node="0000000000000000000000000000000000000000" />
523 <parent revision="-1" node="0000000000000000000000000000000000000000" />
523 <parent revision="-1" node="0000000000000000000000000000000000000000" />
524 <author email="user@hostname">User Name</author>
524 <author email="user@hostname">User Name</author>
525 <date>1970-01-12T13:46:40+00:00</date>
525 <date>1970-01-12T13:46:40+00:00</date>
526 <msg xml:space="preserve">second</msg>
526 <msg xml:space="preserve">second</msg>
527 <paths>
527 <paths>
528 <path action="A">second</path>
528 <path action="A">second</path>
529 </paths>
529 </paths>
530 <extra key="branch">default</extra>
530 <extra key="branch">default</extra>
531 </logentry>
531 </logentry>
532 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
532 <logentry revision="6" node="d41e714fe50d9e4a5f11b4d595d543481b5f980b">
533 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
533 <parent revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f" />
534 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
534 <parent revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74" />
535 <author email="person">person</author>
535 <author email="person">person</author>
536 <date>1970-01-18T08:40:01+00:00</date>
536 <date>1970-01-18T08:40:01+00:00</date>
537 <msg xml:space="preserve">merge</msg>
537 <msg xml:space="preserve">merge</msg>
538 <paths>
538 <paths>
539 </paths>
539 </paths>
540 <extra key="branch">default</extra>
540 <extra key="branch">default</extra>
541 </logentry>
541 </logentry>
542 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
542 <logentry revision="5" node="13207e5a10d9fd28ec424934298e176197f2c67f">
543 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
543 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
544 <parent revision="-1" node="0000000000000000000000000000000000000000" />
544 <parent revision="-1" node="0000000000000000000000000000000000000000" />
545 <author email="person">person</author>
545 <author email="person">person</author>
546 <date>1970-01-18T08:40:00+00:00</date>
546 <date>1970-01-18T08:40:00+00:00</date>
547 <msg xml:space="preserve">new head</msg>
547 <msg xml:space="preserve">new head</msg>
548 <paths>
548 <paths>
549 <path action="A">d</path>
549 <path action="A">d</path>
550 </paths>
550 </paths>
551 <extra key="branch">default</extra>
551 <extra key="branch">default</extra>
552 </logentry>
552 </logentry>
553 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
553 <logentry revision="4" node="bbe44766e73d5f11ed2177f1838de10c53ef3e74">
554 <branch>foo</branch>
554 <branch>foo</branch>
555 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
555 <parent revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47" />
556 <parent revision="-1" node="0000000000000000000000000000000000000000" />
556 <parent revision="-1" node="0000000000000000000000000000000000000000" />
557 <author email="person">person</author>
557 <author email="person">person</author>
558 <date>1970-01-17T04:53:20+00:00</date>
558 <date>1970-01-17T04:53:20+00:00</date>
559 <msg xml:space="preserve">new branch</msg>
559 <msg xml:space="preserve">new branch</msg>
560 <paths>
560 <paths>
561 </paths>
561 </paths>
562 <extra key="branch">foo</extra>
562 <extra key="branch">foo</extra>
563 </logentry>
563 </logentry>
564 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
564 <logentry revision="3" node="10e46f2dcbf4823578cf180f33ecf0b957964c47">
565 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
565 <parent revision="2" node="97054abb4ab824450e9164180baf491ae0078465" />
566 <parent revision="-1" node="0000000000000000000000000000000000000000" />
566 <parent revision="-1" node="0000000000000000000000000000000000000000" />
567 <author email="person">person</author>
567 <author email="person">person</author>
568 <date>1970-01-16T01:06:40+00:00</date>
568 <date>1970-01-16T01:06:40+00:00</date>
569 <msg xml:space="preserve">no user, no domain</msg>
569 <msg xml:space="preserve">no user, no domain</msg>
570 <paths>
570 <paths>
571 <path action="M">c</path>
571 <path action="M">c</path>
572 </paths>
572 </paths>
573 <extra key="branch">default</extra>
573 <extra key="branch">default</extra>
574 </logentry>
574 </logentry>
575 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
575 <logentry revision="2" node="97054abb4ab824450e9164180baf491ae0078465">
576 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
576 <parent revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965" />
577 <parent revision="-1" node="0000000000000000000000000000000000000000" />
577 <parent revision="-1" node="0000000000000000000000000000000000000000" />
578 <author email="other@place">other</author>
578 <author email="other@place">other</author>
579 <date>1970-01-14T21:20:00+00:00</date>
579 <date>1970-01-14T21:20:00+00:00</date>
580 <msg xml:space="preserve">no person</msg>
580 <msg xml:space="preserve">no person</msg>
581 <paths>
581 <paths>
582 <path action="A">c</path>
582 <path action="A">c</path>
583 </paths>
583 </paths>
584 <extra key="branch">default</extra>
584 <extra key="branch">default</extra>
585 </logentry>
585 </logentry>
586 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
586 <logentry revision="1" node="b608e9d1a3f0273ccf70fb85fd6866b3482bf965">
587 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
587 <parent revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f" />
588 <parent revision="-1" node="0000000000000000000000000000000000000000" />
588 <parent revision="-1" node="0000000000000000000000000000000000000000" />
589 <author email="other@place">A. N. Other</author>
589 <author email="other@place">A. N. Other</author>
590 <date>1970-01-13T17:33:20+00:00</date>
590 <date>1970-01-13T17:33:20+00:00</date>
591 <msg xml:space="preserve">other 1
591 <msg xml:space="preserve">other 1
592 other 2
592 other 2
593
593
594 other 3</msg>
594 other 3</msg>
595 <paths>
595 <paths>
596 <path action="A">b</path>
596 <path action="A">b</path>
597 </paths>
597 </paths>
598 <extra key="branch">default</extra>
598 <extra key="branch">default</extra>
599 </logentry>
599 </logentry>
600 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
600 <logentry revision="0" node="1e4e1b8f71e05681d422154f5421e385fec3454f">
601 <parent revision="-1" node="0000000000000000000000000000000000000000" />
601 <parent revision="-1" node="0000000000000000000000000000000000000000" />
602 <parent revision="-1" node="0000000000000000000000000000000000000000" />
602 <parent revision="-1" node="0000000000000000000000000000000000000000" />
603 <author email="user@hostname">User Name</author>
603 <author email="user@hostname">User Name</author>
604 <date>1970-01-12T13:46:40+00:00</date>
604 <date>1970-01-12T13:46:40+00:00</date>
605 <msg xml:space="preserve">line 1
605 <msg xml:space="preserve">line 1
606 line 2</msg>
606 line 2</msg>
607 <paths>
607 <paths>
608 <path action="A">a</path>
608 <path action="A">a</path>
609 </paths>
609 </paths>
610 <extra key="branch">default</extra>
610 <extra key="branch">default</extra>
611 </logentry>
611 </logentry>
612 </log>
612 </log>
613
613
614
614
615 Test JSON style:
615 Test JSON style:
616
616
617 $ hg log -k nosuch -Tjson
617 $ hg log -k nosuch -Tjson
618 []
618 []
619
619
620 $ hg log -qr . -Tjson
620 $ hg log -qr . -Tjson
621 [
621 [
622 {
622 {
623 "rev": 8,
623 "rev": 8,
624 "node": "95c24699272ef57d062b8bccc32c878bf841784a"
624 "node": "95c24699272ef57d062b8bccc32c878bf841784a"
625 }
625 }
626 ]
626 ]
627
627
628 $ hg log -vpr . -Tjson --stat
628 $ hg log -vpr . -Tjson --stat
629 [
629 [
630 {
630 {
631 "rev": 8,
631 "rev": 8,
632 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
632 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
633 "branch": "default",
633 "branch": "default",
634 "phase": "draft",
634 "phase": "draft",
635 "user": "test",
635 "user": "test",
636 "date": [1577872860, 0],
636 "date": [1577872860, 0],
637 "desc": "third",
637 "desc": "third",
638 "bookmarks": [],
638 "bookmarks": [],
639 "tags": ["tip"],
639 "tags": ["tip"],
640 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
640 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
641 "files": ["fourth", "second", "third"],
641 "files": ["fourth", "second", "third"],
642 "diffstat": " fourth | 1 +\n second | 1 -\n third | 1 +\n 3 files changed, 2 insertions(+), 1 deletions(-)\n",
642 "diffstat": " fourth | 1 +\n second | 1 -\n third | 1 +\n 3 files changed, 2 insertions(+), 1 deletions(-)\n",
643 "diff": "diff -r 29114dbae42b -r 95c24699272e fourth\n--- /dev/null\tThu Jan 01 00:00:00 1970 +0000\n+++ b/fourth\tWed Jan 01 10:01:00 2020 +0000\n@@ -0,0 +1,1 @@\n+second\ndiff -r 29114dbae42b -r 95c24699272e second\n--- a/second\tMon Jan 12 13:46:40 1970 +0000\n+++ /dev/null\tThu Jan 01 00:00:00 1970 +0000\n@@ -1,1 +0,0 @@\n-second\ndiff -r 29114dbae42b -r 95c24699272e third\n--- /dev/null\tThu Jan 01 00:00:00 1970 +0000\n+++ b/third\tWed Jan 01 10:01:00 2020 +0000\n@@ -0,0 +1,1 @@\n+third\n"
643 "diff": "diff -r 29114dbae42b -r 95c24699272e fourth\n--- /dev/null\tThu Jan 01 00:00:00 1970 +0000\n+++ b/fourth\tWed Jan 01 10:01:00 2020 +0000\n@@ -0,0 +1,1 @@\n+second\ndiff -r 29114dbae42b -r 95c24699272e second\n--- a/second\tMon Jan 12 13:46:40 1970 +0000\n+++ /dev/null\tThu Jan 01 00:00:00 1970 +0000\n@@ -1,1 +0,0 @@\n-second\ndiff -r 29114dbae42b -r 95c24699272e third\n--- /dev/null\tThu Jan 01 00:00:00 1970 +0000\n+++ b/third\tWed Jan 01 10:01:00 2020 +0000\n@@ -0,0 +1,1 @@\n+third\n"
644 }
644 }
645 ]
645 ]
646
646
647 honor --git but not format-breaking diffopts
647 honor --git but not format-breaking diffopts
648 $ hg --config diff.noprefix=True log --git -vpr . -Tjson
648 $ hg --config diff.noprefix=True log --git -vpr . -Tjson
649 [
649 [
650 {
650 {
651 "rev": 8,
651 "rev": 8,
652 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
652 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
653 "branch": "default",
653 "branch": "default",
654 "phase": "draft",
654 "phase": "draft",
655 "user": "test",
655 "user": "test",
656 "date": [1577872860, 0],
656 "date": [1577872860, 0],
657 "desc": "third",
657 "desc": "third",
658 "bookmarks": [],
658 "bookmarks": [],
659 "tags": ["tip"],
659 "tags": ["tip"],
660 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
660 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
661 "files": ["fourth", "second", "third"],
661 "files": ["fourth", "second", "third"],
662 "diff": "diff --git a/second b/fourth\nrename from second\nrename to fourth\ndiff --git a/third b/third\nnew file mode 100644\n--- /dev/null\n+++ b/third\n@@ -0,0 +1,1 @@\n+third\n"
662 "diff": "diff --git a/second b/fourth\nrename from second\nrename to fourth\ndiff --git a/third b/third\nnew file mode 100644\n--- /dev/null\n+++ b/third\n@@ -0,0 +1,1 @@\n+third\n"
663 }
663 }
664 ]
664 ]
665
665
666 $ hg log -T json
666 $ hg log -T json
667 [
667 [
668 {
668 {
669 "rev": 8,
669 "rev": 8,
670 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
670 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
671 "branch": "default",
671 "branch": "default",
672 "phase": "draft",
672 "phase": "draft",
673 "user": "test",
673 "user": "test",
674 "date": [1577872860, 0],
674 "date": [1577872860, 0],
675 "desc": "third",
675 "desc": "third",
676 "bookmarks": [],
676 "bookmarks": [],
677 "tags": ["tip"],
677 "tags": ["tip"],
678 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"]
678 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"]
679 },
679 },
680 {
680 {
681 "rev": 7,
681 "rev": 7,
682 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
682 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
683 "branch": "default",
683 "branch": "default",
684 "phase": "draft",
684 "phase": "draft",
685 "user": "User Name <user@hostname>",
685 "user": "User Name <user@hostname>",
686 "date": [1000000, 0],
686 "date": [1000000, 0],
687 "desc": "second",
687 "desc": "second",
688 "bookmarks": [],
688 "bookmarks": [],
689 "tags": [],
689 "tags": [],
690 "parents": ["0000000000000000000000000000000000000000"]
690 "parents": ["0000000000000000000000000000000000000000"]
691 },
691 },
692 {
692 {
693 "rev": 6,
693 "rev": 6,
694 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
694 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
695 "branch": "default",
695 "branch": "default",
696 "phase": "draft",
696 "phase": "draft",
697 "user": "person",
697 "user": "person",
698 "date": [1500001, 0],
698 "date": [1500001, 0],
699 "desc": "merge",
699 "desc": "merge",
700 "bookmarks": [],
700 "bookmarks": [],
701 "tags": [],
701 "tags": [],
702 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"]
702 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"]
703 },
703 },
704 {
704 {
705 "rev": 5,
705 "rev": 5,
706 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
706 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
707 "branch": "default",
707 "branch": "default",
708 "phase": "draft",
708 "phase": "draft",
709 "user": "person",
709 "user": "person",
710 "date": [1500000, 0],
710 "date": [1500000, 0],
711 "desc": "new head",
711 "desc": "new head",
712 "bookmarks": [],
712 "bookmarks": [],
713 "tags": [],
713 "tags": [],
714 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
714 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
715 },
715 },
716 {
716 {
717 "rev": 4,
717 "rev": 4,
718 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
718 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
719 "branch": "foo",
719 "branch": "foo",
720 "phase": "draft",
720 "phase": "draft",
721 "user": "person",
721 "user": "person",
722 "date": [1400000, 0],
722 "date": [1400000, 0],
723 "desc": "new branch",
723 "desc": "new branch",
724 "bookmarks": [],
724 "bookmarks": [],
725 "tags": [],
725 "tags": [],
726 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
726 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"]
727 },
727 },
728 {
728 {
729 "rev": 3,
729 "rev": 3,
730 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
730 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
731 "branch": "default",
731 "branch": "default",
732 "phase": "draft",
732 "phase": "draft",
733 "user": "person",
733 "user": "person",
734 "date": [1300000, 0],
734 "date": [1300000, 0],
735 "desc": "no user, no domain",
735 "desc": "no user, no domain",
736 "bookmarks": [],
736 "bookmarks": [],
737 "tags": [],
737 "tags": [],
738 "parents": ["97054abb4ab824450e9164180baf491ae0078465"]
738 "parents": ["97054abb4ab824450e9164180baf491ae0078465"]
739 },
739 },
740 {
740 {
741 "rev": 2,
741 "rev": 2,
742 "node": "97054abb4ab824450e9164180baf491ae0078465",
742 "node": "97054abb4ab824450e9164180baf491ae0078465",
743 "branch": "default",
743 "branch": "default",
744 "phase": "draft",
744 "phase": "draft",
745 "user": "other@place",
745 "user": "other@place",
746 "date": [1200000, 0],
746 "date": [1200000, 0],
747 "desc": "no person",
747 "desc": "no person",
748 "bookmarks": [],
748 "bookmarks": [],
749 "tags": [],
749 "tags": [],
750 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"]
750 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"]
751 },
751 },
752 {
752 {
753 "rev": 1,
753 "rev": 1,
754 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
754 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
755 "branch": "default",
755 "branch": "default",
756 "phase": "draft",
756 "phase": "draft",
757 "user": "A. N. Other <other@place>",
757 "user": "A. N. Other <other@place>",
758 "date": [1100000, 0],
758 "date": [1100000, 0],
759 "desc": "other 1\nother 2\n\nother 3",
759 "desc": "other 1\nother 2\n\nother 3",
760 "bookmarks": [],
760 "bookmarks": [],
761 "tags": [],
761 "tags": [],
762 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"]
762 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"]
763 },
763 },
764 {
764 {
765 "rev": 0,
765 "rev": 0,
766 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
766 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
767 "branch": "default",
767 "branch": "default",
768 "phase": "draft",
768 "phase": "draft",
769 "user": "User Name <user@hostname>",
769 "user": "User Name <user@hostname>",
770 "date": [1000000, 0],
770 "date": [1000000, 0],
771 "desc": "line 1\nline 2",
771 "desc": "line 1\nline 2",
772 "bookmarks": [],
772 "bookmarks": [],
773 "tags": [],
773 "tags": [],
774 "parents": ["0000000000000000000000000000000000000000"]
774 "parents": ["0000000000000000000000000000000000000000"]
775 }
775 }
776 ]
776 ]
777
777
778 $ hg heads -v -Tjson
778 $ hg heads -v -Tjson
779 [
779 [
780 {
780 {
781 "rev": 8,
781 "rev": 8,
782 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
782 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
783 "branch": "default",
783 "branch": "default",
784 "phase": "draft",
784 "phase": "draft",
785 "user": "test",
785 "user": "test",
786 "date": [1577872860, 0],
786 "date": [1577872860, 0],
787 "desc": "third",
787 "desc": "third",
788 "bookmarks": [],
788 "bookmarks": [],
789 "tags": ["tip"],
789 "tags": ["tip"],
790 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
790 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
791 "files": ["fourth", "second", "third"]
791 "files": ["fourth", "second", "third"]
792 },
792 },
793 {
793 {
794 "rev": 6,
794 "rev": 6,
795 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
795 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
796 "branch": "default",
796 "branch": "default",
797 "phase": "draft",
797 "phase": "draft",
798 "user": "person",
798 "user": "person",
799 "date": [1500001, 0],
799 "date": [1500001, 0],
800 "desc": "merge",
800 "desc": "merge",
801 "bookmarks": [],
801 "bookmarks": [],
802 "tags": [],
802 "tags": [],
803 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
803 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
804 "files": []
804 "files": []
805 },
805 },
806 {
806 {
807 "rev": 4,
807 "rev": 4,
808 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
808 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
809 "branch": "foo",
809 "branch": "foo",
810 "phase": "draft",
810 "phase": "draft",
811 "user": "person",
811 "user": "person",
812 "date": [1400000, 0],
812 "date": [1400000, 0],
813 "desc": "new branch",
813 "desc": "new branch",
814 "bookmarks": [],
814 "bookmarks": [],
815 "tags": [],
815 "tags": [],
816 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
816 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
817 "files": []
817 "files": []
818 }
818 }
819 ]
819 ]
820
820
821 $ hg log --debug -Tjson
821 $ hg log --debug -Tjson
822 [
822 [
823 {
823 {
824 "rev": 8,
824 "rev": 8,
825 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
825 "node": "95c24699272ef57d062b8bccc32c878bf841784a",
826 "branch": "default",
826 "branch": "default",
827 "phase": "draft",
827 "phase": "draft",
828 "user": "test",
828 "user": "test",
829 "date": [1577872860, 0],
829 "date": [1577872860, 0],
830 "desc": "third",
830 "desc": "third",
831 "bookmarks": [],
831 "bookmarks": [],
832 "tags": ["tip"],
832 "tags": ["tip"],
833 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
833 "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"],
834 "manifest": "94961b75a2da554b4df6fb599e5bfc7d48de0c64",
834 "manifest": "94961b75a2da554b4df6fb599e5bfc7d48de0c64",
835 "extra": {"branch": "default"},
835 "extra": {"branch": "default"},
836 "modified": [],
836 "modified": [],
837 "added": ["fourth", "third"],
837 "added": ["fourth", "third"],
838 "removed": ["second"]
838 "removed": ["second"]
839 },
839 },
840 {
840 {
841 "rev": 7,
841 "rev": 7,
842 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
842 "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453",
843 "branch": "default",
843 "branch": "default",
844 "phase": "draft",
844 "phase": "draft",
845 "user": "User Name <user@hostname>",
845 "user": "User Name <user@hostname>",
846 "date": [1000000, 0],
846 "date": [1000000, 0],
847 "desc": "second",
847 "desc": "second",
848 "bookmarks": [],
848 "bookmarks": [],
849 "tags": [],
849 "tags": [],
850 "parents": ["0000000000000000000000000000000000000000"],
850 "parents": ["0000000000000000000000000000000000000000"],
851 "manifest": "f2dbc354b94e5ec0b4f10680ee0cee816101d0bf",
851 "manifest": "f2dbc354b94e5ec0b4f10680ee0cee816101d0bf",
852 "extra": {"branch": "default"},
852 "extra": {"branch": "default"},
853 "modified": [],
853 "modified": [],
854 "added": ["second"],
854 "added": ["second"],
855 "removed": []
855 "removed": []
856 },
856 },
857 {
857 {
858 "rev": 6,
858 "rev": 6,
859 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
859 "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b",
860 "branch": "default",
860 "branch": "default",
861 "phase": "draft",
861 "phase": "draft",
862 "user": "person",
862 "user": "person",
863 "date": [1500001, 0],
863 "date": [1500001, 0],
864 "desc": "merge",
864 "desc": "merge",
865 "bookmarks": [],
865 "bookmarks": [],
866 "tags": [],
866 "tags": [],
867 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
867 "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"],
868 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
868 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
869 "extra": {"branch": "default"},
869 "extra": {"branch": "default"},
870 "modified": [],
870 "modified": [],
871 "added": [],
871 "added": [],
872 "removed": []
872 "removed": []
873 },
873 },
874 {
874 {
875 "rev": 5,
875 "rev": 5,
876 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
876 "node": "13207e5a10d9fd28ec424934298e176197f2c67f",
877 "branch": "default",
877 "branch": "default",
878 "phase": "draft",
878 "phase": "draft",
879 "user": "person",
879 "user": "person",
880 "date": [1500000, 0],
880 "date": [1500000, 0],
881 "desc": "new head",
881 "desc": "new head",
882 "bookmarks": [],
882 "bookmarks": [],
883 "tags": [],
883 "tags": [],
884 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
884 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
885 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
885 "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216",
886 "extra": {"branch": "default"},
886 "extra": {"branch": "default"},
887 "modified": [],
887 "modified": [],
888 "added": ["d"],
888 "added": ["d"],
889 "removed": []
889 "removed": []
890 },
890 },
891 {
891 {
892 "rev": 4,
892 "rev": 4,
893 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
893 "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74",
894 "branch": "foo",
894 "branch": "foo",
895 "phase": "draft",
895 "phase": "draft",
896 "user": "person",
896 "user": "person",
897 "date": [1400000, 0],
897 "date": [1400000, 0],
898 "desc": "new branch",
898 "desc": "new branch",
899 "bookmarks": [],
899 "bookmarks": [],
900 "tags": [],
900 "tags": [],
901 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
901 "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"],
902 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
902 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
903 "extra": {"branch": "foo"},
903 "extra": {"branch": "foo"},
904 "modified": [],
904 "modified": [],
905 "added": [],
905 "added": [],
906 "removed": []
906 "removed": []
907 },
907 },
908 {
908 {
909 "rev": 3,
909 "rev": 3,
910 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
910 "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47",
911 "branch": "default",
911 "branch": "default",
912 "phase": "draft",
912 "phase": "draft",
913 "user": "person",
913 "user": "person",
914 "date": [1300000, 0],
914 "date": [1300000, 0],
915 "desc": "no user, no domain",
915 "desc": "no user, no domain",
916 "bookmarks": [],
916 "bookmarks": [],
917 "tags": [],
917 "tags": [],
918 "parents": ["97054abb4ab824450e9164180baf491ae0078465"],
918 "parents": ["97054abb4ab824450e9164180baf491ae0078465"],
919 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
919 "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc",
920 "extra": {"branch": "default"},
920 "extra": {"branch": "default"},
921 "modified": ["c"],
921 "modified": ["c"],
922 "added": [],
922 "added": [],
923 "removed": []
923 "removed": []
924 },
924 },
925 {
925 {
926 "rev": 2,
926 "rev": 2,
927 "node": "97054abb4ab824450e9164180baf491ae0078465",
927 "node": "97054abb4ab824450e9164180baf491ae0078465",
928 "branch": "default",
928 "branch": "default",
929 "phase": "draft",
929 "phase": "draft",
930 "user": "other@place",
930 "user": "other@place",
931 "date": [1200000, 0],
931 "date": [1200000, 0],
932 "desc": "no person",
932 "desc": "no person",
933 "bookmarks": [],
933 "bookmarks": [],
934 "tags": [],
934 "tags": [],
935 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"],
935 "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"],
936 "manifest": "6e0e82995c35d0d57a52aca8da4e56139e06b4b1",
936 "manifest": "6e0e82995c35d0d57a52aca8da4e56139e06b4b1",
937 "extra": {"branch": "default"},
937 "extra": {"branch": "default"},
938 "modified": [],
938 "modified": [],
939 "added": ["c"],
939 "added": ["c"],
940 "removed": []
940 "removed": []
941 },
941 },
942 {
942 {
943 "rev": 1,
943 "rev": 1,
944 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
944 "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965",
945 "branch": "default",
945 "branch": "default",
946 "phase": "draft",
946 "phase": "draft",
947 "user": "A. N. Other <other@place>",
947 "user": "A. N. Other <other@place>",
948 "date": [1100000, 0],
948 "date": [1100000, 0],
949 "desc": "other 1\nother 2\n\nother 3",
949 "desc": "other 1\nother 2\n\nother 3",
950 "bookmarks": [],
950 "bookmarks": [],
951 "tags": [],
951 "tags": [],
952 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"],
952 "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"],
953 "manifest": "4e8d705b1e53e3f9375e0e60dc7b525d8211fe55",
953 "manifest": "4e8d705b1e53e3f9375e0e60dc7b525d8211fe55",
954 "extra": {"branch": "default"},
954 "extra": {"branch": "default"},
955 "modified": [],
955 "modified": [],
956 "added": ["b"],
956 "added": ["b"],
957 "removed": []
957 "removed": []
958 },
958 },
959 {
959 {
960 "rev": 0,
960 "rev": 0,
961 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
961 "node": "1e4e1b8f71e05681d422154f5421e385fec3454f",
962 "branch": "default",
962 "branch": "default",
963 "phase": "draft",
963 "phase": "draft",
964 "user": "User Name <user@hostname>",
964 "user": "User Name <user@hostname>",
965 "date": [1000000, 0],
965 "date": [1000000, 0],
966 "desc": "line 1\nline 2",
966 "desc": "line 1\nline 2",
967 "bookmarks": [],
967 "bookmarks": [],
968 "tags": [],
968 "tags": [],
969 "parents": ["0000000000000000000000000000000000000000"],
969 "parents": ["0000000000000000000000000000000000000000"],
970 "manifest": "a0c8bcbbb45c63b90b70ad007bf38961f64f2af0",
970 "manifest": "a0c8bcbbb45c63b90b70ad007bf38961f64f2af0",
971 "extra": {"branch": "default"},
971 "extra": {"branch": "default"},
972 "modified": [],
972 "modified": [],
973 "added": ["a"],
973 "added": ["a"],
974 "removed": []
974 "removed": []
975 }
975 }
976 ]
976 ]
977
977
978 Error if style not readable:
978 Error if style not readable:
979
979
980 #if unix-permissions no-root
980 #if unix-permissions no-root
981 $ touch q
981 $ touch q
982 $ chmod 0 q
982 $ chmod 0 q
983 $ hg log --style ./q
983 $ hg log --style ./q
984 abort: Permission denied: ./q
984 abort: Permission denied: ./q
985 [255]
985 [255]
986 #endif
986 #endif
987
987
988 Error if no style:
988 Error if no style:
989
989
990 $ hg log --style notexist
990 $ hg log --style notexist
991 abort: style 'notexist' not found
991 abort: style 'notexist' not found
992 (available styles: bisect, changelog, compact, default, phases, status, xml)
992 (available styles: bisect, changelog, compact, default, phases, status, xml)
993 [255]
993 [255]
994
994
995 $ hg log -T list
995 $ hg log -T list
996 available styles: bisect, changelog, compact, default, phases, status, xml
996 available styles: bisect, changelog, compact, default, phases, status, xml
997 abort: specify a template
997 abort: specify a template
998 [255]
998 [255]
999
999
1000 Error if style missing key:
1000 Error if style missing key:
1001
1001
1002 $ echo 'q = q' > t
1002 $ echo 'q = q' > t
1003 $ hg log --style ./t
1003 $ hg log --style ./t
1004 abort: "changeset" not in template map
1004 abort: "changeset" not in template map
1005 [255]
1005 [255]
1006
1006
1007 Error if style missing value:
1007 Error if style missing value:
1008
1008
1009 $ echo 'changeset =' > t
1009 $ echo 'changeset =' > t
1010 $ hg log --style t
1010 $ hg log --style t
1011 abort: t:1: missing value
1011 abort: t:1: missing value
1012 [255]
1012 [255]
1013
1013
1014 Error if include fails:
1014 Error if include fails:
1015
1015
1016 $ echo 'changeset = q' >> t
1016 $ echo 'changeset = q' >> t
1017 #if unix-permissions no-root
1017 #if unix-permissions no-root
1018 $ hg log --style ./t
1018 $ hg log --style ./t
1019 abort: template file ./q: Permission denied
1019 abort: template file ./q: Permission denied
1020 [255]
1020 [255]
1021 $ rm -f q
1021 $ rm -f q
1022 #endif
1022 #endif
1023
1023
1024 Include works:
1024 Include works:
1025
1025
1026 $ echo '{rev}' > q
1026 $ echo '{rev}' > q
1027 $ hg log --style ./t
1027 $ hg log --style ./t
1028 8
1028 8
1029 7
1029 7
1030 6
1030 6
1031 5
1031 5
1032 4
1032 4
1033 3
1033 3
1034 2
1034 2
1035 1
1035 1
1036 0
1036 0
1037
1037
1038 Check that recursive reference does not fall into RuntimeError (issue4758):
1038 Check that recursive reference does not fall into RuntimeError (issue4758):
1039
1039
1040 common mistake:
1040 common mistake:
1041
1041
1042 $ hg log -T '{changeset}\n'
1042 $ hg log -T '{changeset}\n'
1043 abort: recursive reference 'changeset' in template
1043 abort: recursive reference 'changeset' in template
1044 [255]
1044 [255]
1045
1045
1046 circular reference:
1046 circular reference:
1047
1047
1048 $ cat << EOF > issue4758
1048 $ cat << EOF > issue4758
1049 > changeset = '{foo}'
1049 > changeset = '{foo}'
1050 > foo = '{changeset}'
1050 > foo = '{changeset}'
1051 > EOF
1051 > EOF
1052 $ hg log --style ./issue4758
1052 $ hg log --style ./issue4758
1053 abort: recursive reference 'foo' in template
1053 abort: recursive reference 'foo' in template
1054 [255]
1054 [255]
1055
1055
1056 buildmap() -> gettemplate(), where no thunk was made:
1056 buildmap() -> gettemplate(), where no thunk was made:
1057
1057
1058 $ hg log -T '{files % changeset}\n'
1058 $ hg log -T '{files % changeset}\n'
1059 abort: recursive reference 'changeset' in template
1059 abort: recursive reference 'changeset' in template
1060 [255]
1060 [255]
1061
1061
1062 not a recursion if a keyword of the same name exists:
1062 not a recursion if a keyword of the same name exists:
1063
1063
1064 $ cat << EOF > issue4758
1064 $ cat << EOF > issue4758
1065 > changeset = '{tags % rev}'
1065 > changeset = '{tags % rev}'
1066 > rev = '{rev} {tag}\n'
1066 > rev = '{rev} {tag}\n'
1067 > EOF
1067 > EOF
1068 $ hg log --style ./issue4758 -r tip
1068 $ hg log --style ./issue4758 -r tip
1069 8 tip
1069 8 tip
1070
1070
1071 Check that {phase} works correctly on parents:
1071 Check that {phase} works correctly on parents:
1072
1072
1073 $ cat << EOF > parentphase
1073 $ cat << EOF > parentphase
1074 > changeset_debug = '{rev} ({phase}):{parents}\n'
1074 > changeset_debug = '{rev} ({phase}):{parents}\n'
1075 > parent = ' {rev} ({phase})'
1075 > parent = ' {rev} ({phase})'
1076 > EOF
1076 > EOF
1077 $ hg phase -r 5 --public
1077 $ hg phase -r 5 --public
1078 $ hg phase -r 7 --secret --force
1078 $ hg phase -r 7 --secret --force
1079 $ hg log --debug -G --style ./parentphase
1079 $ hg log --debug -G --style ./parentphase
1080 @ 8 (secret): 7 (secret) -1 (public)
1080 @ 8 (secret): 7 (secret) -1 (public)
1081 |
1081 |
1082 o 7 (secret): -1 (public) -1 (public)
1082 o 7 (secret): -1 (public) -1 (public)
1083
1083
1084 o 6 (draft): 5 (public) 4 (draft)
1084 o 6 (draft): 5 (public) 4 (draft)
1085 |\
1085 |\
1086 | o 5 (public): 3 (public) -1 (public)
1086 | o 5 (public): 3 (public) -1 (public)
1087 | |
1087 | |
1088 o | 4 (draft): 3 (public) -1 (public)
1088 o | 4 (draft): 3 (public) -1 (public)
1089 |/
1089 |/
1090 o 3 (public): 2 (public) -1 (public)
1090 o 3 (public): 2 (public) -1 (public)
1091 |
1091 |
1092 o 2 (public): 1 (public) -1 (public)
1092 o 2 (public): 1 (public) -1 (public)
1093 |
1093 |
1094 o 1 (public): 0 (public) -1 (public)
1094 o 1 (public): 0 (public) -1 (public)
1095 |
1095 |
1096 o 0 (public): -1 (public) -1 (public)
1096 o 0 (public): -1 (public) -1 (public)
1097
1097
1098
1098
1099 Missing non-standard names give no error (backward compatibility):
1099 Missing non-standard names give no error (backward compatibility):
1100
1100
1101 $ echo "changeset = '{c}'" > t
1101 $ echo "changeset = '{c}'" > t
1102 $ hg log --style ./t
1102 $ hg log --style ./t
1103
1103
1104 Defining non-standard name works:
1104 Defining non-standard name works:
1105
1105
1106 $ cat <<EOF > t
1106 $ cat <<EOF > t
1107 > changeset = '{c}'
1107 > changeset = '{c}'
1108 > c = q
1108 > c = q
1109 > EOF
1109 > EOF
1110 $ hg log --style ./t
1110 $ hg log --style ./t
1111 8
1111 8
1112 7
1112 7
1113 6
1113 6
1114 5
1114 5
1115 4
1115 4
1116 3
1116 3
1117 2
1117 2
1118 1
1118 1
1119 0
1119 0
1120
1120
1121 ui.style works:
1121 ui.style works:
1122
1122
1123 $ echo '[ui]' > .hg/hgrc
1123 $ echo '[ui]' > .hg/hgrc
1124 $ echo 'style = t' >> .hg/hgrc
1124 $ echo 'style = t' >> .hg/hgrc
1125 $ hg log
1125 $ hg log
1126 8
1126 8
1127 7
1127 7
1128 6
1128 6
1129 5
1129 5
1130 4
1130 4
1131 3
1131 3
1132 2
1132 2
1133 1
1133 1
1134 0
1134 0
1135
1135
1136
1136
1137 Issue338:
1137 Issue338:
1138
1138
1139 $ hg log --style=changelog > changelog
1139 $ hg log --style=changelog > changelog
1140
1140
1141 $ cat changelog
1141 $ cat changelog
1142 2020-01-01 test <test>
1142 2020-01-01 test <test>
1143
1143
1144 * fourth, second, third:
1144 * fourth, second, third:
1145 third
1145 third
1146 [95c24699272e] [tip]
1146 [95c24699272e] [tip]
1147
1147
1148 1970-01-12 User Name <user@hostname>
1148 1970-01-12 User Name <user@hostname>
1149
1149
1150 * second:
1150 * second:
1151 second
1151 second
1152 [29114dbae42b]
1152 [29114dbae42b]
1153
1153
1154 1970-01-18 person <person>
1154 1970-01-18 person <person>
1155
1155
1156 * merge
1156 * merge
1157 [d41e714fe50d]
1157 [d41e714fe50d]
1158
1158
1159 * d:
1159 * d:
1160 new head
1160 new head
1161 [13207e5a10d9]
1161 [13207e5a10d9]
1162
1162
1163 1970-01-17 person <person>
1163 1970-01-17 person <person>
1164
1164
1165 * new branch
1165 * new branch
1166 [bbe44766e73d] <foo>
1166 [bbe44766e73d] <foo>
1167
1167
1168 1970-01-16 person <person>
1168 1970-01-16 person <person>
1169
1169
1170 * c:
1170 * c:
1171 no user, no domain
1171 no user, no domain
1172 [10e46f2dcbf4]
1172 [10e46f2dcbf4]
1173
1173
1174 1970-01-14 other <other@place>
1174 1970-01-14 other <other@place>
1175
1175
1176 * c:
1176 * c:
1177 no person
1177 no person
1178 [97054abb4ab8]
1178 [97054abb4ab8]
1179
1179
1180 1970-01-13 A. N. Other <other@place>
1180 1970-01-13 A. N. Other <other@place>
1181
1181
1182 * b:
1182 * b:
1183 other 1 other 2
1183 other 1 other 2
1184
1184
1185 other 3
1185 other 3
1186 [b608e9d1a3f0]
1186 [b608e9d1a3f0]
1187
1187
1188 1970-01-12 User Name <user@hostname>
1188 1970-01-12 User Name <user@hostname>
1189
1189
1190 * a:
1190 * a:
1191 line 1 line 2
1191 line 1 line 2
1192 [1e4e1b8f71e0]
1192 [1e4e1b8f71e0]
1193
1193
1194
1194
1195 Issue2130: xml output for 'hg heads' is malformed
1195 Issue2130: xml output for 'hg heads' is malformed
1196
1196
1197 $ hg heads --style changelog
1197 $ hg heads --style changelog
1198 2020-01-01 test <test>
1198 2020-01-01 test <test>
1199
1199
1200 * fourth, second, third:
1200 * fourth, second, third:
1201 third
1201 third
1202 [95c24699272e] [tip]
1202 [95c24699272e] [tip]
1203
1203
1204 1970-01-18 person <person>
1204 1970-01-18 person <person>
1205
1205
1206 * merge
1206 * merge
1207 [d41e714fe50d]
1207 [d41e714fe50d]
1208
1208
1209 1970-01-17 person <person>
1209 1970-01-17 person <person>
1210
1210
1211 * new branch
1211 * new branch
1212 [bbe44766e73d] <foo>
1212 [bbe44766e73d] <foo>
1213
1213
1214
1214
1215 Keys work:
1215 Keys work:
1216
1216
1217 $ for key in author branch branches date desc file_adds file_dels file_mods \
1217 $ for key in author branch branches date desc file_adds file_dels file_mods \
1218 > file_copies file_copies_switch files \
1218 > file_copies file_copies_switch files \
1219 > manifest node parents rev tags diffstat extras \
1219 > manifest node parents rev tags diffstat extras \
1220 > p1rev p2rev p1node p2node; do
1220 > p1rev p2rev p1node p2node; do
1221 > for mode in '' --verbose --debug; do
1221 > for mode in '' --verbose --debug; do
1222 > hg log $mode --template "$key$mode: {$key}\n"
1222 > hg log $mode --template "$key$mode: {$key}\n"
1223 > done
1223 > done
1224 > done
1224 > done
1225 author: test
1225 author: test
1226 author: User Name <user@hostname>
1226 author: User Name <user@hostname>
1227 author: person
1227 author: person
1228 author: person
1228 author: person
1229 author: person
1229 author: person
1230 author: person
1230 author: person
1231 author: other@place
1231 author: other@place
1232 author: A. N. Other <other@place>
1232 author: A. N. Other <other@place>
1233 author: User Name <user@hostname>
1233 author: User Name <user@hostname>
1234 author--verbose: test
1234 author--verbose: test
1235 author--verbose: User Name <user@hostname>
1235 author--verbose: User Name <user@hostname>
1236 author--verbose: person
1236 author--verbose: person
1237 author--verbose: person
1237 author--verbose: person
1238 author--verbose: person
1238 author--verbose: person
1239 author--verbose: person
1239 author--verbose: person
1240 author--verbose: other@place
1240 author--verbose: other@place
1241 author--verbose: A. N. Other <other@place>
1241 author--verbose: A. N. Other <other@place>
1242 author--verbose: User Name <user@hostname>
1242 author--verbose: User Name <user@hostname>
1243 author--debug: test
1243 author--debug: test
1244 author--debug: User Name <user@hostname>
1244 author--debug: User Name <user@hostname>
1245 author--debug: person
1245 author--debug: person
1246 author--debug: person
1246 author--debug: person
1247 author--debug: person
1247 author--debug: person
1248 author--debug: person
1248 author--debug: person
1249 author--debug: other@place
1249 author--debug: other@place
1250 author--debug: A. N. Other <other@place>
1250 author--debug: A. N. Other <other@place>
1251 author--debug: User Name <user@hostname>
1251 author--debug: User Name <user@hostname>
1252 branch: default
1252 branch: default
1253 branch: default
1253 branch: default
1254 branch: default
1254 branch: default
1255 branch: default
1255 branch: default
1256 branch: foo
1256 branch: foo
1257 branch: default
1257 branch: default
1258 branch: default
1258 branch: default
1259 branch: default
1259 branch: default
1260 branch: default
1260 branch: default
1261 branch--verbose: default
1261 branch--verbose: default
1262 branch--verbose: default
1262 branch--verbose: default
1263 branch--verbose: default
1263 branch--verbose: default
1264 branch--verbose: default
1264 branch--verbose: default
1265 branch--verbose: foo
1265 branch--verbose: foo
1266 branch--verbose: default
1266 branch--verbose: default
1267 branch--verbose: default
1267 branch--verbose: default
1268 branch--verbose: default
1268 branch--verbose: default
1269 branch--verbose: default
1269 branch--verbose: default
1270 branch--debug: default
1270 branch--debug: default
1271 branch--debug: default
1271 branch--debug: default
1272 branch--debug: default
1272 branch--debug: default
1273 branch--debug: default
1273 branch--debug: default
1274 branch--debug: foo
1274 branch--debug: foo
1275 branch--debug: default
1275 branch--debug: default
1276 branch--debug: default
1276 branch--debug: default
1277 branch--debug: default
1277 branch--debug: default
1278 branch--debug: default
1278 branch--debug: default
1279 branches:
1279 branches:
1280 branches:
1280 branches:
1281 branches:
1281 branches:
1282 branches:
1282 branches:
1283 branches: foo
1283 branches: foo
1284 branches:
1284 branches:
1285 branches:
1285 branches:
1286 branches:
1286 branches:
1287 branches:
1287 branches:
1288 branches--verbose:
1288 branches--verbose:
1289 branches--verbose:
1289 branches--verbose:
1290 branches--verbose:
1290 branches--verbose:
1291 branches--verbose:
1291 branches--verbose:
1292 branches--verbose: foo
1292 branches--verbose: foo
1293 branches--verbose:
1293 branches--verbose:
1294 branches--verbose:
1294 branches--verbose:
1295 branches--verbose:
1295 branches--verbose:
1296 branches--verbose:
1296 branches--verbose:
1297 branches--debug:
1297 branches--debug:
1298 branches--debug:
1298 branches--debug:
1299 branches--debug:
1299 branches--debug:
1300 branches--debug:
1300 branches--debug:
1301 branches--debug: foo
1301 branches--debug: foo
1302 branches--debug:
1302 branches--debug:
1303 branches--debug:
1303 branches--debug:
1304 branches--debug:
1304 branches--debug:
1305 branches--debug:
1305 branches--debug:
1306 date: 1577872860.00
1306 date: 1577872860.00
1307 date: 1000000.00
1307 date: 1000000.00
1308 date: 1500001.00
1308 date: 1500001.00
1309 date: 1500000.00
1309 date: 1500000.00
1310 date: 1400000.00
1310 date: 1400000.00
1311 date: 1300000.00
1311 date: 1300000.00
1312 date: 1200000.00
1312 date: 1200000.00
1313 date: 1100000.00
1313 date: 1100000.00
1314 date: 1000000.00
1314 date: 1000000.00
1315 date--verbose: 1577872860.00
1315 date--verbose: 1577872860.00
1316 date--verbose: 1000000.00
1316 date--verbose: 1000000.00
1317 date--verbose: 1500001.00
1317 date--verbose: 1500001.00
1318 date--verbose: 1500000.00
1318 date--verbose: 1500000.00
1319 date--verbose: 1400000.00
1319 date--verbose: 1400000.00
1320 date--verbose: 1300000.00
1320 date--verbose: 1300000.00
1321 date--verbose: 1200000.00
1321 date--verbose: 1200000.00
1322 date--verbose: 1100000.00
1322 date--verbose: 1100000.00
1323 date--verbose: 1000000.00
1323 date--verbose: 1000000.00
1324 date--debug: 1577872860.00
1324 date--debug: 1577872860.00
1325 date--debug: 1000000.00
1325 date--debug: 1000000.00
1326 date--debug: 1500001.00
1326 date--debug: 1500001.00
1327 date--debug: 1500000.00
1327 date--debug: 1500000.00
1328 date--debug: 1400000.00
1328 date--debug: 1400000.00
1329 date--debug: 1300000.00
1329 date--debug: 1300000.00
1330 date--debug: 1200000.00
1330 date--debug: 1200000.00
1331 date--debug: 1100000.00
1331 date--debug: 1100000.00
1332 date--debug: 1000000.00
1332 date--debug: 1000000.00
1333 desc: third
1333 desc: third
1334 desc: second
1334 desc: second
1335 desc: merge
1335 desc: merge
1336 desc: new head
1336 desc: new head
1337 desc: new branch
1337 desc: new branch
1338 desc: no user, no domain
1338 desc: no user, no domain
1339 desc: no person
1339 desc: no person
1340 desc: other 1
1340 desc: other 1
1341 other 2
1341 other 2
1342
1342
1343 other 3
1343 other 3
1344 desc: line 1
1344 desc: line 1
1345 line 2
1345 line 2
1346 desc--verbose: third
1346 desc--verbose: third
1347 desc--verbose: second
1347 desc--verbose: second
1348 desc--verbose: merge
1348 desc--verbose: merge
1349 desc--verbose: new head
1349 desc--verbose: new head
1350 desc--verbose: new branch
1350 desc--verbose: new branch
1351 desc--verbose: no user, no domain
1351 desc--verbose: no user, no domain
1352 desc--verbose: no person
1352 desc--verbose: no person
1353 desc--verbose: other 1
1353 desc--verbose: other 1
1354 other 2
1354 other 2
1355
1355
1356 other 3
1356 other 3
1357 desc--verbose: line 1
1357 desc--verbose: line 1
1358 line 2
1358 line 2
1359 desc--debug: third
1359 desc--debug: third
1360 desc--debug: second
1360 desc--debug: second
1361 desc--debug: merge
1361 desc--debug: merge
1362 desc--debug: new head
1362 desc--debug: new head
1363 desc--debug: new branch
1363 desc--debug: new branch
1364 desc--debug: no user, no domain
1364 desc--debug: no user, no domain
1365 desc--debug: no person
1365 desc--debug: no person
1366 desc--debug: other 1
1366 desc--debug: other 1
1367 other 2
1367 other 2
1368
1368
1369 other 3
1369 other 3
1370 desc--debug: line 1
1370 desc--debug: line 1
1371 line 2
1371 line 2
1372 file_adds: fourth third
1372 file_adds: fourth third
1373 file_adds: second
1373 file_adds: second
1374 file_adds:
1374 file_adds:
1375 file_adds: d
1375 file_adds: d
1376 file_adds:
1376 file_adds:
1377 file_adds:
1377 file_adds:
1378 file_adds: c
1378 file_adds: c
1379 file_adds: b
1379 file_adds: b
1380 file_adds: a
1380 file_adds: a
1381 file_adds--verbose: fourth third
1381 file_adds--verbose: fourth third
1382 file_adds--verbose: second
1382 file_adds--verbose: second
1383 file_adds--verbose:
1383 file_adds--verbose:
1384 file_adds--verbose: d
1384 file_adds--verbose: d
1385 file_adds--verbose:
1385 file_adds--verbose:
1386 file_adds--verbose:
1386 file_adds--verbose:
1387 file_adds--verbose: c
1387 file_adds--verbose: c
1388 file_adds--verbose: b
1388 file_adds--verbose: b
1389 file_adds--verbose: a
1389 file_adds--verbose: a
1390 file_adds--debug: fourth third
1390 file_adds--debug: fourth third
1391 file_adds--debug: second
1391 file_adds--debug: second
1392 file_adds--debug:
1392 file_adds--debug:
1393 file_adds--debug: d
1393 file_adds--debug: d
1394 file_adds--debug:
1394 file_adds--debug:
1395 file_adds--debug:
1395 file_adds--debug:
1396 file_adds--debug: c
1396 file_adds--debug: c
1397 file_adds--debug: b
1397 file_adds--debug: b
1398 file_adds--debug: a
1398 file_adds--debug: a
1399 file_dels: second
1399 file_dels: second
1400 file_dels:
1400 file_dels:
1401 file_dels:
1401 file_dels:
1402 file_dels:
1402 file_dels:
1403 file_dels:
1403 file_dels:
1404 file_dels:
1404 file_dels:
1405 file_dels:
1405 file_dels:
1406 file_dels:
1406 file_dels:
1407 file_dels:
1407 file_dels:
1408 file_dels--verbose: second
1408 file_dels--verbose: second
1409 file_dels--verbose:
1409 file_dels--verbose:
1410 file_dels--verbose:
1410 file_dels--verbose:
1411 file_dels--verbose:
1411 file_dels--verbose:
1412 file_dels--verbose:
1412 file_dels--verbose:
1413 file_dels--verbose:
1413 file_dels--verbose:
1414 file_dels--verbose:
1414 file_dels--verbose:
1415 file_dels--verbose:
1415 file_dels--verbose:
1416 file_dels--verbose:
1416 file_dels--verbose:
1417 file_dels--debug: second
1417 file_dels--debug: second
1418 file_dels--debug:
1418 file_dels--debug:
1419 file_dels--debug:
1419 file_dels--debug:
1420 file_dels--debug:
1420 file_dels--debug:
1421 file_dels--debug:
1421 file_dels--debug:
1422 file_dels--debug:
1422 file_dels--debug:
1423 file_dels--debug:
1423 file_dels--debug:
1424 file_dels--debug:
1424 file_dels--debug:
1425 file_dels--debug:
1425 file_dels--debug:
1426 file_mods:
1426 file_mods:
1427 file_mods:
1427 file_mods:
1428 file_mods:
1428 file_mods:
1429 file_mods:
1429 file_mods:
1430 file_mods:
1430 file_mods:
1431 file_mods: c
1431 file_mods: c
1432 file_mods:
1432 file_mods:
1433 file_mods:
1433 file_mods:
1434 file_mods:
1434 file_mods:
1435 file_mods--verbose:
1435 file_mods--verbose:
1436 file_mods--verbose:
1436 file_mods--verbose:
1437 file_mods--verbose:
1437 file_mods--verbose:
1438 file_mods--verbose:
1438 file_mods--verbose:
1439 file_mods--verbose:
1439 file_mods--verbose:
1440 file_mods--verbose: c
1440 file_mods--verbose: c
1441 file_mods--verbose:
1441 file_mods--verbose:
1442 file_mods--verbose:
1442 file_mods--verbose:
1443 file_mods--verbose:
1443 file_mods--verbose:
1444 file_mods--debug:
1444 file_mods--debug:
1445 file_mods--debug:
1445 file_mods--debug:
1446 file_mods--debug:
1446 file_mods--debug:
1447 file_mods--debug:
1447 file_mods--debug:
1448 file_mods--debug:
1448 file_mods--debug:
1449 file_mods--debug: c
1449 file_mods--debug: c
1450 file_mods--debug:
1450 file_mods--debug:
1451 file_mods--debug:
1451 file_mods--debug:
1452 file_mods--debug:
1452 file_mods--debug:
1453 file_copies: fourth (second)
1453 file_copies: fourth (second)
1454 file_copies:
1454 file_copies:
1455 file_copies:
1455 file_copies:
1456 file_copies:
1456 file_copies:
1457 file_copies:
1457 file_copies:
1458 file_copies:
1458 file_copies:
1459 file_copies:
1459 file_copies:
1460 file_copies:
1460 file_copies:
1461 file_copies:
1461 file_copies:
1462 file_copies--verbose: fourth (second)
1462 file_copies--verbose: fourth (second)
1463 file_copies--verbose:
1463 file_copies--verbose:
1464 file_copies--verbose:
1464 file_copies--verbose:
1465 file_copies--verbose:
1465 file_copies--verbose:
1466 file_copies--verbose:
1466 file_copies--verbose:
1467 file_copies--verbose:
1467 file_copies--verbose:
1468 file_copies--verbose:
1468 file_copies--verbose:
1469 file_copies--verbose:
1469 file_copies--verbose:
1470 file_copies--verbose:
1470 file_copies--verbose:
1471 file_copies--debug: fourth (second)
1471 file_copies--debug: fourth (second)
1472 file_copies--debug:
1472 file_copies--debug:
1473 file_copies--debug:
1473 file_copies--debug:
1474 file_copies--debug:
1474 file_copies--debug:
1475 file_copies--debug:
1475 file_copies--debug:
1476 file_copies--debug:
1476 file_copies--debug:
1477 file_copies--debug:
1477 file_copies--debug:
1478 file_copies--debug:
1478 file_copies--debug:
1479 file_copies--debug:
1479 file_copies--debug:
1480 file_copies_switch:
1480 file_copies_switch:
1481 file_copies_switch:
1481 file_copies_switch:
1482 file_copies_switch:
1482 file_copies_switch:
1483 file_copies_switch:
1483 file_copies_switch:
1484 file_copies_switch:
1484 file_copies_switch:
1485 file_copies_switch:
1485 file_copies_switch:
1486 file_copies_switch:
1486 file_copies_switch:
1487 file_copies_switch:
1487 file_copies_switch:
1488 file_copies_switch:
1488 file_copies_switch:
1489 file_copies_switch--verbose:
1489 file_copies_switch--verbose:
1490 file_copies_switch--verbose:
1490 file_copies_switch--verbose:
1491 file_copies_switch--verbose:
1491 file_copies_switch--verbose:
1492 file_copies_switch--verbose:
1492 file_copies_switch--verbose:
1493 file_copies_switch--verbose:
1493 file_copies_switch--verbose:
1494 file_copies_switch--verbose:
1494 file_copies_switch--verbose:
1495 file_copies_switch--verbose:
1495 file_copies_switch--verbose:
1496 file_copies_switch--verbose:
1496 file_copies_switch--verbose:
1497 file_copies_switch--verbose:
1497 file_copies_switch--verbose:
1498 file_copies_switch--debug:
1498 file_copies_switch--debug:
1499 file_copies_switch--debug:
1499 file_copies_switch--debug:
1500 file_copies_switch--debug:
1500 file_copies_switch--debug:
1501 file_copies_switch--debug:
1501 file_copies_switch--debug:
1502 file_copies_switch--debug:
1502 file_copies_switch--debug:
1503 file_copies_switch--debug:
1503 file_copies_switch--debug:
1504 file_copies_switch--debug:
1504 file_copies_switch--debug:
1505 file_copies_switch--debug:
1505 file_copies_switch--debug:
1506 file_copies_switch--debug:
1506 file_copies_switch--debug:
1507 files: fourth second third
1507 files: fourth second third
1508 files: second
1508 files: second
1509 files:
1509 files:
1510 files: d
1510 files: d
1511 files:
1511 files:
1512 files: c
1512 files: c
1513 files: c
1513 files: c
1514 files: b
1514 files: b
1515 files: a
1515 files: a
1516 files--verbose: fourth second third
1516 files--verbose: fourth second third
1517 files--verbose: second
1517 files--verbose: second
1518 files--verbose:
1518 files--verbose:
1519 files--verbose: d
1519 files--verbose: d
1520 files--verbose:
1520 files--verbose:
1521 files--verbose: c
1521 files--verbose: c
1522 files--verbose: c
1522 files--verbose: c
1523 files--verbose: b
1523 files--verbose: b
1524 files--verbose: a
1524 files--verbose: a
1525 files--debug: fourth second third
1525 files--debug: fourth second third
1526 files--debug: second
1526 files--debug: second
1527 files--debug:
1527 files--debug:
1528 files--debug: d
1528 files--debug: d
1529 files--debug:
1529 files--debug:
1530 files--debug: c
1530 files--debug: c
1531 files--debug: c
1531 files--debug: c
1532 files--debug: b
1532 files--debug: b
1533 files--debug: a
1533 files--debug: a
1534 manifest: 6:94961b75a2da
1534 manifest: 6:94961b75a2da
1535 manifest: 5:f2dbc354b94e
1535 manifest: 5:f2dbc354b94e
1536 manifest: 4:4dc3def4f9b4
1536 manifest: 4:4dc3def4f9b4
1537 manifest: 4:4dc3def4f9b4
1537 manifest: 4:4dc3def4f9b4
1538 manifest: 3:cb5a1327723b
1538 manifest: 3:cb5a1327723b
1539 manifest: 3:cb5a1327723b
1539 manifest: 3:cb5a1327723b
1540 manifest: 2:6e0e82995c35
1540 manifest: 2:6e0e82995c35
1541 manifest: 1:4e8d705b1e53
1541 manifest: 1:4e8d705b1e53
1542 manifest: 0:a0c8bcbbb45c
1542 manifest: 0:a0c8bcbbb45c
1543 manifest--verbose: 6:94961b75a2da
1543 manifest--verbose: 6:94961b75a2da
1544 manifest--verbose: 5:f2dbc354b94e
1544 manifest--verbose: 5:f2dbc354b94e
1545 manifest--verbose: 4:4dc3def4f9b4
1545 manifest--verbose: 4:4dc3def4f9b4
1546 manifest--verbose: 4:4dc3def4f9b4
1546 manifest--verbose: 4:4dc3def4f9b4
1547 manifest--verbose: 3:cb5a1327723b
1547 manifest--verbose: 3:cb5a1327723b
1548 manifest--verbose: 3:cb5a1327723b
1548 manifest--verbose: 3:cb5a1327723b
1549 manifest--verbose: 2:6e0e82995c35
1549 manifest--verbose: 2:6e0e82995c35
1550 manifest--verbose: 1:4e8d705b1e53
1550 manifest--verbose: 1:4e8d705b1e53
1551 manifest--verbose: 0:a0c8bcbbb45c
1551 manifest--verbose: 0:a0c8bcbbb45c
1552 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
1552 manifest--debug: 6:94961b75a2da554b4df6fb599e5bfc7d48de0c64
1553 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
1553 manifest--debug: 5:f2dbc354b94e5ec0b4f10680ee0cee816101d0bf
1554 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1554 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1555 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1555 manifest--debug: 4:4dc3def4f9b4c6e8de820f6ee74737f91e96a216
1556 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1556 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1557 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1557 manifest--debug: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
1558 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
1558 manifest--debug: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
1559 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
1559 manifest--debug: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
1560 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
1560 manifest--debug: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
1561 node: 95c24699272ef57d062b8bccc32c878bf841784a
1561 node: 95c24699272ef57d062b8bccc32c878bf841784a
1562 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1562 node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1563 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1563 node: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1564 node: 13207e5a10d9fd28ec424934298e176197f2c67f
1564 node: 13207e5a10d9fd28ec424934298e176197f2c67f
1565 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1565 node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1566 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1566 node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1567 node: 97054abb4ab824450e9164180baf491ae0078465
1567 node: 97054abb4ab824450e9164180baf491ae0078465
1568 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1568 node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1569 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1569 node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1570 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
1570 node--verbose: 95c24699272ef57d062b8bccc32c878bf841784a
1571 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1571 node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1572 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1572 node--verbose: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1573 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1573 node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1574 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1574 node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1575 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1575 node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1576 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1576 node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1577 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1577 node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1578 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1578 node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1579 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
1579 node--debug: 95c24699272ef57d062b8bccc32c878bf841784a
1580 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1580 node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1581 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1581 node--debug: d41e714fe50d9e4a5f11b4d595d543481b5f980b
1582 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1582 node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1583 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1583 node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1584 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1584 node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1585 node--debug: 97054abb4ab824450e9164180baf491ae0078465
1585 node--debug: 97054abb4ab824450e9164180baf491ae0078465
1586 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1586 node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1587 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1587 node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1588 parents:
1588 parents:
1589 parents: -1:000000000000
1589 parents: -1:000000000000
1590 parents: 5:13207e5a10d9 4:bbe44766e73d
1590 parents: 5:13207e5a10d9 4:bbe44766e73d
1591 parents: 3:10e46f2dcbf4
1591 parents: 3:10e46f2dcbf4
1592 parents:
1592 parents:
1593 parents:
1593 parents:
1594 parents:
1594 parents:
1595 parents:
1595 parents:
1596 parents:
1596 parents:
1597 parents--verbose:
1597 parents--verbose:
1598 parents--verbose: -1:000000000000
1598 parents--verbose: -1:000000000000
1599 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
1599 parents--verbose: 5:13207e5a10d9 4:bbe44766e73d
1600 parents--verbose: 3:10e46f2dcbf4
1600 parents--verbose: 3:10e46f2dcbf4
1601 parents--verbose:
1601 parents--verbose:
1602 parents--verbose:
1602 parents--verbose:
1603 parents--verbose:
1603 parents--verbose:
1604 parents--verbose:
1604 parents--verbose:
1605 parents--verbose:
1605 parents--verbose:
1606 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
1606 parents--debug: 7:29114dbae42b9f078cf2714dbe3a86bba8ec7453 -1:0000000000000000000000000000000000000000
1607 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1607 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1608 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
1608 parents--debug: 5:13207e5a10d9fd28ec424934298e176197f2c67f 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
1609 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1609 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1610 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1610 parents--debug: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47 -1:0000000000000000000000000000000000000000
1611 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
1611 parents--debug: 2:97054abb4ab824450e9164180baf491ae0078465 -1:0000000000000000000000000000000000000000
1612 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
1612 parents--debug: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965 -1:0000000000000000000000000000000000000000
1613 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
1613 parents--debug: 0:1e4e1b8f71e05681d422154f5421e385fec3454f -1:0000000000000000000000000000000000000000
1614 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1614 parents--debug: -1:0000000000000000000000000000000000000000 -1:0000000000000000000000000000000000000000
1615 rev: 8
1615 rev: 8
1616 rev: 7
1616 rev: 7
1617 rev: 6
1617 rev: 6
1618 rev: 5
1618 rev: 5
1619 rev: 4
1619 rev: 4
1620 rev: 3
1620 rev: 3
1621 rev: 2
1621 rev: 2
1622 rev: 1
1622 rev: 1
1623 rev: 0
1623 rev: 0
1624 rev--verbose: 8
1624 rev--verbose: 8
1625 rev--verbose: 7
1625 rev--verbose: 7
1626 rev--verbose: 6
1626 rev--verbose: 6
1627 rev--verbose: 5
1627 rev--verbose: 5
1628 rev--verbose: 4
1628 rev--verbose: 4
1629 rev--verbose: 3
1629 rev--verbose: 3
1630 rev--verbose: 2
1630 rev--verbose: 2
1631 rev--verbose: 1
1631 rev--verbose: 1
1632 rev--verbose: 0
1632 rev--verbose: 0
1633 rev--debug: 8
1633 rev--debug: 8
1634 rev--debug: 7
1634 rev--debug: 7
1635 rev--debug: 6
1635 rev--debug: 6
1636 rev--debug: 5
1636 rev--debug: 5
1637 rev--debug: 4
1637 rev--debug: 4
1638 rev--debug: 3
1638 rev--debug: 3
1639 rev--debug: 2
1639 rev--debug: 2
1640 rev--debug: 1
1640 rev--debug: 1
1641 rev--debug: 0
1641 rev--debug: 0
1642 tags: tip
1642 tags: tip
1643 tags:
1643 tags:
1644 tags:
1644 tags:
1645 tags:
1645 tags:
1646 tags:
1646 tags:
1647 tags:
1647 tags:
1648 tags:
1648 tags:
1649 tags:
1649 tags:
1650 tags:
1650 tags:
1651 tags--verbose: tip
1651 tags--verbose: tip
1652 tags--verbose:
1652 tags--verbose:
1653 tags--verbose:
1653 tags--verbose:
1654 tags--verbose:
1654 tags--verbose:
1655 tags--verbose:
1655 tags--verbose:
1656 tags--verbose:
1656 tags--verbose:
1657 tags--verbose:
1657 tags--verbose:
1658 tags--verbose:
1658 tags--verbose:
1659 tags--verbose:
1659 tags--verbose:
1660 tags--debug: tip
1660 tags--debug: tip
1661 tags--debug:
1661 tags--debug:
1662 tags--debug:
1662 tags--debug:
1663 tags--debug:
1663 tags--debug:
1664 tags--debug:
1664 tags--debug:
1665 tags--debug:
1665 tags--debug:
1666 tags--debug:
1666 tags--debug:
1667 tags--debug:
1667 tags--debug:
1668 tags--debug:
1668 tags--debug:
1669 diffstat: 3: +2/-1
1669 diffstat: 3: +2/-1
1670 diffstat: 1: +1/-0
1670 diffstat: 1: +1/-0
1671 diffstat: 0: +0/-0
1671 diffstat: 0: +0/-0
1672 diffstat: 1: +1/-0
1672 diffstat: 1: +1/-0
1673 diffstat: 0: +0/-0
1673 diffstat: 0: +0/-0
1674 diffstat: 1: +1/-0
1674 diffstat: 1: +1/-0
1675 diffstat: 1: +4/-0
1675 diffstat: 1: +4/-0
1676 diffstat: 1: +2/-0
1676 diffstat: 1: +2/-0
1677 diffstat: 1: +1/-0
1677 diffstat: 1: +1/-0
1678 diffstat--verbose: 3: +2/-1
1678 diffstat--verbose: 3: +2/-1
1679 diffstat--verbose: 1: +1/-0
1679 diffstat--verbose: 1: +1/-0
1680 diffstat--verbose: 0: +0/-0
1680 diffstat--verbose: 0: +0/-0
1681 diffstat--verbose: 1: +1/-0
1681 diffstat--verbose: 1: +1/-0
1682 diffstat--verbose: 0: +0/-0
1682 diffstat--verbose: 0: +0/-0
1683 diffstat--verbose: 1: +1/-0
1683 diffstat--verbose: 1: +1/-0
1684 diffstat--verbose: 1: +4/-0
1684 diffstat--verbose: 1: +4/-0
1685 diffstat--verbose: 1: +2/-0
1685 diffstat--verbose: 1: +2/-0
1686 diffstat--verbose: 1: +1/-0
1686 diffstat--verbose: 1: +1/-0
1687 diffstat--debug: 3: +2/-1
1687 diffstat--debug: 3: +2/-1
1688 diffstat--debug: 1: +1/-0
1688 diffstat--debug: 1: +1/-0
1689 diffstat--debug: 0: +0/-0
1689 diffstat--debug: 0: +0/-0
1690 diffstat--debug: 1: +1/-0
1690 diffstat--debug: 1: +1/-0
1691 diffstat--debug: 0: +0/-0
1691 diffstat--debug: 0: +0/-0
1692 diffstat--debug: 1: +1/-0
1692 diffstat--debug: 1: +1/-0
1693 diffstat--debug: 1: +4/-0
1693 diffstat--debug: 1: +4/-0
1694 diffstat--debug: 1: +2/-0
1694 diffstat--debug: 1: +2/-0
1695 diffstat--debug: 1: +1/-0
1695 diffstat--debug: 1: +1/-0
1696 extras: branch=default
1696 extras: branch=default
1697 extras: branch=default
1697 extras: branch=default
1698 extras: branch=default
1698 extras: branch=default
1699 extras: branch=default
1699 extras: branch=default
1700 extras: branch=foo
1700 extras: branch=foo
1701 extras: branch=default
1701 extras: branch=default
1702 extras: branch=default
1702 extras: branch=default
1703 extras: branch=default
1703 extras: branch=default
1704 extras: branch=default
1704 extras: branch=default
1705 extras--verbose: branch=default
1705 extras--verbose: branch=default
1706 extras--verbose: branch=default
1706 extras--verbose: branch=default
1707 extras--verbose: branch=default
1707 extras--verbose: branch=default
1708 extras--verbose: branch=default
1708 extras--verbose: branch=default
1709 extras--verbose: branch=foo
1709 extras--verbose: branch=foo
1710 extras--verbose: branch=default
1710 extras--verbose: branch=default
1711 extras--verbose: branch=default
1711 extras--verbose: branch=default
1712 extras--verbose: branch=default
1712 extras--verbose: branch=default
1713 extras--verbose: branch=default
1713 extras--verbose: branch=default
1714 extras--debug: branch=default
1714 extras--debug: branch=default
1715 extras--debug: branch=default
1715 extras--debug: branch=default
1716 extras--debug: branch=default
1716 extras--debug: branch=default
1717 extras--debug: branch=default
1717 extras--debug: branch=default
1718 extras--debug: branch=foo
1718 extras--debug: branch=foo
1719 extras--debug: branch=default
1719 extras--debug: branch=default
1720 extras--debug: branch=default
1720 extras--debug: branch=default
1721 extras--debug: branch=default
1721 extras--debug: branch=default
1722 extras--debug: branch=default
1722 extras--debug: branch=default
1723 p1rev: 7
1723 p1rev: 7
1724 p1rev: -1
1724 p1rev: -1
1725 p1rev: 5
1725 p1rev: 5
1726 p1rev: 3
1726 p1rev: 3
1727 p1rev: 3
1727 p1rev: 3
1728 p1rev: 2
1728 p1rev: 2
1729 p1rev: 1
1729 p1rev: 1
1730 p1rev: 0
1730 p1rev: 0
1731 p1rev: -1
1731 p1rev: -1
1732 p1rev--verbose: 7
1732 p1rev--verbose: 7
1733 p1rev--verbose: -1
1733 p1rev--verbose: -1
1734 p1rev--verbose: 5
1734 p1rev--verbose: 5
1735 p1rev--verbose: 3
1735 p1rev--verbose: 3
1736 p1rev--verbose: 3
1736 p1rev--verbose: 3
1737 p1rev--verbose: 2
1737 p1rev--verbose: 2
1738 p1rev--verbose: 1
1738 p1rev--verbose: 1
1739 p1rev--verbose: 0
1739 p1rev--verbose: 0
1740 p1rev--verbose: -1
1740 p1rev--verbose: -1
1741 p1rev--debug: 7
1741 p1rev--debug: 7
1742 p1rev--debug: -1
1742 p1rev--debug: -1
1743 p1rev--debug: 5
1743 p1rev--debug: 5
1744 p1rev--debug: 3
1744 p1rev--debug: 3
1745 p1rev--debug: 3
1745 p1rev--debug: 3
1746 p1rev--debug: 2
1746 p1rev--debug: 2
1747 p1rev--debug: 1
1747 p1rev--debug: 1
1748 p1rev--debug: 0
1748 p1rev--debug: 0
1749 p1rev--debug: -1
1749 p1rev--debug: -1
1750 p2rev: -1
1750 p2rev: -1
1751 p2rev: -1
1751 p2rev: -1
1752 p2rev: 4
1752 p2rev: 4
1753 p2rev: -1
1753 p2rev: -1
1754 p2rev: -1
1754 p2rev: -1
1755 p2rev: -1
1755 p2rev: -1
1756 p2rev: -1
1756 p2rev: -1
1757 p2rev: -1
1757 p2rev: -1
1758 p2rev: -1
1758 p2rev: -1
1759 p2rev--verbose: -1
1759 p2rev--verbose: -1
1760 p2rev--verbose: -1
1760 p2rev--verbose: -1
1761 p2rev--verbose: 4
1761 p2rev--verbose: 4
1762 p2rev--verbose: -1
1762 p2rev--verbose: -1
1763 p2rev--verbose: -1
1763 p2rev--verbose: -1
1764 p2rev--verbose: -1
1764 p2rev--verbose: -1
1765 p2rev--verbose: -1
1765 p2rev--verbose: -1
1766 p2rev--verbose: -1
1766 p2rev--verbose: -1
1767 p2rev--verbose: -1
1767 p2rev--verbose: -1
1768 p2rev--debug: -1
1768 p2rev--debug: -1
1769 p2rev--debug: -1
1769 p2rev--debug: -1
1770 p2rev--debug: 4
1770 p2rev--debug: 4
1771 p2rev--debug: -1
1771 p2rev--debug: -1
1772 p2rev--debug: -1
1772 p2rev--debug: -1
1773 p2rev--debug: -1
1773 p2rev--debug: -1
1774 p2rev--debug: -1
1774 p2rev--debug: -1
1775 p2rev--debug: -1
1775 p2rev--debug: -1
1776 p2rev--debug: -1
1776 p2rev--debug: -1
1777 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1777 p1node: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1778 p1node: 0000000000000000000000000000000000000000
1778 p1node: 0000000000000000000000000000000000000000
1779 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
1779 p1node: 13207e5a10d9fd28ec424934298e176197f2c67f
1780 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1780 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1781 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1781 p1node: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1782 p1node: 97054abb4ab824450e9164180baf491ae0078465
1782 p1node: 97054abb4ab824450e9164180baf491ae0078465
1783 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1783 p1node: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1784 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1784 p1node: 1e4e1b8f71e05681d422154f5421e385fec3454f
1785 p1node: 0000000000000000000000000000000000000000
1785 p1node: 0000000000000000000000000000000000000000
1786 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1786 p1node--verbose: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1787 p1node--verbose: 0000000000000000000000000000000000000000
1787 p1node--verbose: 0000000000000000000000000000000000000000
1788 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1788 p1node--verbose: 13207e5a10d9fd28ec424934298e176197f2c67f
1789 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1789 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1790 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1790 p1node--verbose: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1791 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1791 p1node--verbose: 97054abb4ab824450e9164180baf491ae0078465
1792 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1792 p1node--verbose: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1793 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1793 p1node--verbose: 1e4e1b8f71e05681d422154f5421e385fec3454f
1794 p1node--verbose: 0000000000000000000000000000000000000000
1794 p1node--verbose: 0000000000000000000000000000000000000000
1795 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1795 p1node--debug: 29114dbae42b9f078cf2714dbe3a86bba8ec7453
1796 p1node--debug: 0000000000000000000000000000000000000000
1796 p1node--debug: 0000000000000000000000000000000000000000
1797 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1797 p1node--debug: 13207e5a10d9fd28ec424934298e176197f2c67f
1798 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1798 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1799 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1799 p1node--debug: 10e46f2dcbf4823578cf180f33ecf0b957964c47
1800 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
1800 p1node--debug: 97054abb4ab824450e9164180baf491ae0078465
1801 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1801 p1node--debug: b608e9d1a3f0273ccf70fb85fd6866b3482bf965
1802 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1802 p1node--debug: 1e4e1b8f71e05681d422154f5421e385fec3454f
1803 p1node--debug: 0000000000000000000000000000000000000000
1803 p1node--debug: 0000000000000000000000000000000000000000
1804 p2node: 0000000000000000000000000000000000000000
1804 p2node: 0000000000000000000000000000000000000000
1805 p2node: 0000000000000000000000000000000000000000
1805 p2node: 0000000000000000000000000000000000000000
1806 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1806 p2node: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1807 p2node: 0000000000000000000000000000000000000000
1807 p2node: 0000000000000000000000000000000000000000
1808 p2node: 0000000000000000000000000000000000000000
1808 p2node: 0000000000000000000000000000000000000000
1809 p2node: 0000000000000000000000000000000000000000
1809 p2node: 0000000000000000000000000000000000000000
1810 p2node: 0000000000000000000000000000000000000000
1810 p2node: 0000000000000000000000000000000000000000
1811 p2node: 0000000000000000000000000000000000000000
1811 p2node: 0000000000000000000000000000000000000000
1812 p2node: 0000000000000000000000000000000000000000
1812 p2node: 0000000000000000000000000000000000000000
1813 p2node--verbose: 0000000000000000000000000000000000000000
1813 p2node--verbose: 0000000000000000000000000000000000000000
1814 p2node--verbose: 0000000000000000000000000000000000000000
1814 p2node--verbose: 0000000000000000000000000000000000000000
1815 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1815 p2node--verbose: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1816 p2node--verbose: 0000000000000000000000000000000000000000
1816 p2node--verbose: 0000000000000000000000000000000000000000
1817 p2node--verbose: 0000000000000000000000000000000000000000
1817 p2node--verbose: 0000000000000000000000000000000000000000
1818 p2node--verbose: 0000000000000000000000000000000000000000
1818 p2node--verbose: 0000000000000000000000000000000000000000
1819 p2node--verbose: 0000000000000000000000000000000000000000
1819 p2node--verbose: 0000000000000000000000000000000000000000
1820 p2node--verbose: 0000000000000000000000000000000000000000
1820 p2node--verbose: 0000000000000000000000000000000000000000
1821 p2node--verbose: 0000000000000000000000000000000000000000
1821 p2node--verbose: 0000000000000000000000000000000000000000
1822 p2node--debug: 0000000000000000000000000000000000000000
1822 p2node--debug: 0000000000000000000000000000000000000000
1823 p2node--debug: 0000000000000000000000000000000000000000
1823 p2node--debug: 0000000000000000000000000000000000000000
1824 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1824 p2node--debug: bbe44766e73d5f11ed2177f1838de10c53ef3e74
1825 p2node--debug: 0000000000000000000000000000000000000000
1825 p2node--debug: 0000000000000000000000000000000000000000
1826 p2node--debug: 0000000000000000000000000000000000000000
1826 p2node--debug: 0000000000000000000000000000000000000000
1827 p2node--debug: 0000000000000000000000000000000000000000
1827 p2node--debug: 0000000000000000000000000000000000000000
1828 p2node--debug: 0000000000000000000000000000000000000000
1828 p2node--debug: 0000000000000000000000000000000000000000
1829 p2node--debug: 0000000000000000000000000000000000000000
1829 p2node--debug: 0000000000000000000000000000000000000000
1830 p2node--debug: 0000000000000000000000000000000000000000
1830 p2node--debug: 0000000000000000000000000000000000000000
1831
1831
1832 Filters work:
1832 Filters work:
1833
1833
1834 $ hg log --template '{author|domain}\n'
1834 $ hg log --template '{author|domain}\n'
1835
1835
1836 hostname
1836 hostname
1837
1837
1838
1838
1839
1839
1840
1840
1841 place
1841 place
1842 place
1842 place
1843 hostname
1843 hostname
1844
1844
1845 $ hg log --template '{author|person}\n'
1845 $ hg log --template '{author|person}\n'
1846 test
1846 test
1847 User Name
1847 User Name
1848 person
1848 person
1849 person
1849 person
1850 person
1850 person
1851 person
1851 person
1852 other
1852 other
1853 A. N. Other
1853 A. N. Other
1854 User Name
1854 User Name
1855
1855
1856 $ hg log --template '{author|user}\n'
1856 $ hg log --template '{author|user}\n'
1857 test
1857 test
1858 user
1858 user
1859 person
1859 person
1860 person
1860 person
1861 person
1861 person
1862 person
1862 person
1863 other
1863 other
1864 other
1864 other
1865 user
1865 user
1866
1866
1867 $ hg log --template '{date|date}\n'
1867 $ hg log --template '{date|date}\n'
1868 Wed Jan 01 10:01:00 2020 +0000
1868 Wed Jan 01 10:01:00 2020 +0000
1869 Mon Jan 12 13:46:40 1970 +0000
1869 Mon Jan 12 13:46:40 1970 +0000
1870 Sun Jan 18 08:40:01 1970 +0000
1870 Sun Jan 18 08:40:01 1970 +0000
1871 Sun Jan 18 08:40:00 1970 +0000
1871 Sun Jan 18 08:40:00 1970 +0000
1872 Sat Jan 17 04:53:20 1970 +0000
1872 Sat Jan 17 04:53:20 1970 +0000
1873 Fri Jan 16 01:06:40 1970 +0000
1873 Fri Jan 16 01:06:40 1970 +0000
1874 Wed Jan 14 21:20:00 1970 +0000
1874 Wed Jan 14 21:20:00 1970 +0000
1875 Tue Jan 13 17:33:20 1970 +0000
1875 Tue Jan 13 17:33:20 1970 +0000
1876 Mon Jan 12 13:46:40 1970 +0000
1876 Mon Jan 12 13:46:40 1970 +0000
1877
1877
1878 $ hg log --template '{date|isodate}\n'
1878 $ hg log --template '{date|isodate}\n'
1879 2020-01-01 10:01 +0000
1879 2020-01-01 10:01 +0000
1880 1970-01-12 13:46 +0000
1880 1970-01-12 13:46 +0000
1881 1970-01-18 08:40 +0000
1881 1970-01-18 08:40 +0000
1882 1970-01-18 08:40 +0000
1882 1970-01-18 08:40 +0000
1883 1970-01-17 04:53 +0000
1883 1970-01-17 04:53 +0000
1884 1970-01-16 01:06 +0000
1884 1970-01-16 01:06 +0000
1885 1970-01-14 21:20 +0000
1885 1970-01-14 21:20 +0000
1886 1970-01-13 17:33 +0000
1886 1970-01-13 17:33 +0000
1887 1970-01-12 13:46 +0000
1887 1970-01-12 13:46 +0000
1888
1888
1889 $ hg log --template '{date|isodatesec}\n'
1889 $ hg log --template '{date|isodatesec}\n'
1890 2020-01-01 10:01:00 +0000
1890 2020-01-01 10:01:00 +0000
1891 1970-01-12 13:46:40 +0000
1891 1970-01-12 13:46:40 +0000
1892 1970-01-18 08:40:01 +0000
1892 1970-01-18 08:40:01 +0000
1893 1970-01-18 08:40:00 +0000
1893 1970-01-18 08:40:00 +0000
1894 1970-01-17 04:53:20 +0000
1894 1970-01-17 04:53:20 +0000
1895 1970-01-16 01:06:40 +0000
1895 1970-01-16 01:06:40 +0000
1896 1970-01-14 21:20:00 +0000
1896 1970-01-14 21:20:00 +0000
1897 1970-01-13 17:33:20 +0000
1897 1970-01-13 17:33:20 +0000
1898 1970-01-12 13:46:40 +0000
1898 1970-01-12 13:46:40 +0000
1899
1899
1900 $ hg log --template '{date|rfc822date}\n'
1900 $ hg log --template '{date|rfc822date}\n'
1901 Wed, 01 Jan 2020 10:01:00 +0000
1901 Wed, 01 Jan 2020 10:01:00 +0000
1902 Mon, 12 Jan 1970 13:46:40 +0000
1902 Mon, 12 Jan 1970 13:46:40 +0000
1903 Sun, 18 Jan 1970 08:40:01 +0000
1903 Sun, 18 Jan 1970 08:40:01 +0000
1904 Sun, 18 Jan 1970 08:40:00 +0000
1904 Sun, 18 Jan 1970 08:40:00 +0000
1905 Sat, 17 Jan 1970 04:53:20 +0000
1905 Sat, 17 Jan 1970 04:53:20 +0000
1906 Fri, 16 Jan 1970 01:06:40 +0000
1906 Fri, 16 Jan 1970 01:06:40 +0000
1907 Wed, 14 Jan 1970 21:20:00 +0000
1907 Wed, 14 Jan 1970 21:20:00 +0000
1908 Tue, 13 Jan 1970 17:33:20 +0000
1908 Tue, 13 Jan 1970 17:33:20 +0000
1909 Mon, 12 Jan 1970 13:46:40 +0000
1909 Mon, 12 Jan 1970 13:46:40 +0000
1910
1910
1911 $ hg log --template '{desc|firstline}\n'
1911 $ hg log --template '{desc|firstline}\n'
1912 third
1912 third
1913 second
1913 second
1914 merge
1914 merge
1915 new head
1915 new head
1916 new branch
1916 new branch
1917 no user, no domain
1917 no user, no domain
1918 no person
1918 no person
1919 other 1
1919 other 1
1920 line 1
1920 line 1
1921
1921
1922 $ hg log --template '{node|short}\n'
1922 $ hg log --template '{node|short}\n'
1923 95c24699272e
1923 95c24699272e
1924 29114dbae42b
1924 29114dbae42b
1925 d41e714fe50d
1925 d41e714fe50d
1926 13207e5a10d9
1926 13207e5a10d9
1927 bbe44766e73d
1927 bbe44766e73d
1928 10e46f2dcbf4
1928 10e46f2dcbf4
1929 97054abb4ab8
1929 97054abb4ab8
1930 b608e9d1a3f0
1930 b608e9d1a3f0
1931 1e4e1b8f71e0
1931 1e4e1b8f71e0
1932
1932
1933 $ hg log --template '<changeset author="{author|xmlescape}"/>\n'
1933 $ hg log --template '<changeset author="{author|xmlescape}"/>\n'
1934 <changeset author="test"/>
1934 <changeset author="test"/>
1935 <changeset author="User Name &lt;user@hostname&gt;"/>
1935 <changeset author="User Name &lt;user@hostname&gt;"/>
1936 <changeset author="person"/>
1936 <changeset author="person"/>
1937 <changeset author="person"/>
1937 <changeset author="person"/>
1938 <changeset author="person"/>
1938 <changeset author="person"/>
1939 <changeset author="person"/>
1939 <changeset author="person"/>
1940 <changeset author="other@place"/>
1940 <changeset author="other@place"/>
1941 <changeset author="A. N. Other &lt;other@place&gt;"/>
1941 <changeset author="A. N. Other &lt;other@place&gt;"/>
1942 <changeset author="User Name &lt;user@hostname&gt;"/>
1942 <changeset author="User Name &lt;user@hostname&gt;"/>
1943
1943
1944 $ hg log --template '{rev}: {children}\n'
1944 $ hg log --template '{rev}: {children}\n'
1945 8:
1945 8:
1946 7: 8:95c24699272e
1946 7: 8:95c24699272e
1947 6:
1947 6:
1948 5: 6:d41e714fe50d
1948 5: 6:d41e714fe50d
1949 4: 6:d41e714fe50d
1949 4: 6:d41e714fe50d
1950 3: 4:bbe44766e73d 5:13207e5a10d9
1950 3: 4:bbe44766e73d 5:13207e5a10d9
1951 2: 3:10e46f2dcbf4
1951 2: 3:10e46f2dcbf4
1952 1: 2:97054abb4ab8
1952 1: 2:97054abb4ab8
1953 0: 1:b608e9d1a3f0
1953 0: 1:b608e9d1a3f0
1954
1954
1955 Formatnode filter works:
1955 Formatnode filter works:
1956
1956
1957 $ hg -q log -r 0 --template '{node|formatnode}\n'
1957 $ hg -q log -r 0 --template '{node|formatnode}\n'
1958 1e4e1b8f71e0
1958 1e4e1b8f71e0
1959
1959
1960 $ hg log -r 0 --template '{node|formatnode}\n'
1960 $ hg log -r 0 --template '{node|formatnode}\n'
1961 1e4e1b8f71e0
1961 1e4e1b8f71e0
1962
1962
1963 $ hg -v log -r 0 --template '{node|formatnode}\n'
1963 $ hg -v log -r 0 --template '{node|formatnode}\n'
1964 1e4e1b8f71e0
1964 1e4e1b8f71e0
1965
1965
1966 $ hg --debug log -r 0 --template '{node|formatnode}\n'
1966 $ hg --debug log -r 0 --template '{node|formatnode}\n'
1967 1e4e1b8f71e05681d422154f5421e385fec3454f
1967 1e4e1b8f71e05681d422154f5421e385fec3454f
1968
1968
1969 Age filter:
1969 Age filter:
1970
1970
1971 $ hg init unstable-hash
1971 $ hg init unstable-hash
1972 $ cd unstable-hash
1972 $ cd unstable-hash
1973 $ hg log --template '{date|age}\n' > /dev/null || exit 1
1973 $ hg log --template '{date|age}\n' > /dev/null || exit 1
1974
1974
1975 >>> from datetime import datetime, timedelta
1975 >>> from datetime import datetime, timedelta
1976 >>> fp = open('a', 'w')
1976 >>> fp = open('a', 'w')
1977 >>> n = datetime.now() + timedelta(366 * 7)
1977 >>> n = datetime.now() + timedelta(366 * 7)
1978 >>> fp.write('%d-%d-%d 00:00' % (n.year, n.month, n.day))
1978 >>> fp.write('%d-%d-%d 00:00' % (n.year, n.month, n.day))
1979 >>> fp.close()
1979 >>> fp.close()
1980 $ hg add a
1980 $ hg add a
1981 $ hg commit -m future -d "`cat a`"
1981 $ hg commit -m future -d "`cat a`"
1982
1982
1983 $ hg log -l1 --template '{date|age}\n'
1983 $ hg log -l1 --template '{date|age}\n'
1984 7 years from now
1984 7 years from now
1985
1985
1986 $ cd ..
1986 $ cd ..
1987 $ rm -rf unstable-hash
1987 $ rm -rf unstable-hash
1988
1988
1989 Add a dummy commit to make up for the instability of the above:
1989 Add a dummy commit to make up for the instability of the above:
1990
1990
1991 $ echo a > a
1991 $ echo a > a
1992 $ hg add a
1992 $ hg add a
1993 $ hg ci -m future
1993 $ hg ci -m future
1994
1994
1995 Count filter:
1995 Count filter:
1996
1996
1997 $ hg log -l1 --template '{node|count} {node|short|count}\n'
1997 $ hg log -l1 --template '{node|count} {node|short|count}\n'
1998 40 12
1998 40 12
1999
1999
2000 $ hg log -l1 --template '{revset("null^")|count} {revset(".")|count} {revset("0::3")|count}\n'
2000 $ hg log -l1 --template '{revset("null^")|count} {revset(".")|count} {revset("0::3")|count}\n'
2001 0 1 4
2001 0 1 4
2002
2002
2003 $ hg log -G --template '{rev}: children: {children|count}, \
2003 $ hg log -G --template '{rev}: children: {children|count}, \
2004 > tags: {tags|count}, file_adds: {file_adds|count}, \
2004 > tags: {tags|count}, file_adds: {file_adds|count}, \
2005 > ancestors: {revset("ancestors(%s)", rev)|count}'
2005 > ancestors: {revset("ancestors(%s)", rev)|count}'
2006 @ 9: children: 0, tags: 1, file_adds: 1, ancestors: 3
2006 @ 9: children: 0, tags: 1, file_adds: 1, ancestors: 3
2007 |
2007 |
2008 o 8: children: 1, tags: 0, file_adds: 2, ancestors: 2
2008 o 8: children: 1, tags: 0, file_adds: 2, ancestors: 2
2009 |
2009 |
2010 o 7: children: 1, tags: 0, file_adds: 1, ancestors: 1
2010 o 7: children: 1, tags: 0, file_adds: 1, ancestors: 1
2011
2011
2012 o 6: children: 0, tags: 0, file_adds: 0, ancestors: 7
2012 o 6: children: 0, tags: 0, file_adds: 0, ancestors: 7
2013 |\
2013 |\
2014 | o 5: children: 1, tags: 0, file_adds: 1, ancestors: 5
2014 | o 5: children: 1, tags: 0, file_adds: 1, ancestors: 5
2015 | |
2015 | |
2016 o | 4: children: 1, tags: 0, file_adds: 0, ancestors: 5
2016 o | 4: children: 1, tags: 0, file_adds: 0, ancestors: 5
2017 |/
2017 |/
2018 o 3: children: 2, tags: 0, file_adds: 0, ancestors: 4
2018 o 3: children: 2, tags: 0, file_adds: 0, ancestors: 4
2019 |
2019 |
2020 o 2: children: 1, tags: 0, file_adds: 1, ancestors: 3
2020 o 2: children: 1, tags: 0, file_adds: 1, ancestors: 3
2021 |
2021 |
2022 o 1: children: 1, tags: 0, file_adds: 1, ancestors: 2
2022 o 1: children: 1, tags: 0, file_adds: 1, ancestors: 2
2023 |
2023 |
2024 o 0: children: 1, tags: 0, file_adds: 1, ancestors: 1
2024 o 0: children: 1, tags: 0, file_adds: 1, ancestors: 1
2025
2025
2026
2026
2027 Upper/lower filters:
2027 Upper/lower filters:
2028
2028
2029 $ hg log -r0 --template '{branch|upper}\n'
2029 $ hg log -r0 --template '{branch|upper}\n'
2030 DEFAULT
2030 DEFAULT
2031 $ hg log -r0 --template '{author|lower}\n'
2031 $ hg log -r0 --template '{author|lower}\n'
2032 user name <user@hostname>
2032 user name <user@hostname>
2033 $ hg log -r0 --template '{date|upper}\n'
2033 $ hg log -r0 --template '{date|upper}\n'
2034 abort: template filter 'upper' is not compatible with keyword 'date'
2034 abort: template filter 'upper' is not compatible with keyword 'date'
2035 [255]
2035 [255]
2036
2036
2037 Add a commit that does all possible modifications at once
2037 Add a commit that does all possible modifications at once
2038
2038
2039 $ echo modify >> third
2039 $ echo modify >> third
2040 $ touch b
2040 $ touch b
2041 $ hg add b
2041 $ hg add b
2042 $ hg mv fourth fifth
2042 $ hg mv fourth fifth
2043 $ hg rm a
2043 $ hg rm a
2044 $ hg ci -m "Modify, add, remove, rename"
2044 $ hg ci -m "Modify, add, remove, rename"
2045
2045
2046 Check the status template
2046 Check the status template
2047
2047
2048 $ cat <<EOF >> $HGRCPATH
2048 $ cat <<EOF >> $HGRCPATH
2049 > [extensions]
2049 > [extensions]
2050 > color=
2050 > color=
2051 > EOF
2051 > EOF
2052
2052
2053 $ hg log -T status -r 10
2053 $ hg log -T status -r 10
2054 changeset: 10:0f9759ec227a
2054 changeset: 10:0f9759ec227a
2055 tag: tip
2055 tag: tip
2056 user: test
2056 user: test
2057 date: Thu Jan 01 00:00:00 1970 +0000
2057 date: Thu Jan 01 00:00:00 1970 +0000
2058 summary: Modify, add, remove, rename
2058 summary: Modify, add, remove, rename
2059 files:
2059 files:
2060 M third
2060 M third
2061 A b
2061 A b
2062 A fifth
2062 A fifth
2063 R a
2063 R a
2064 R fourth
2064 R fourth
2065
2065
2066 $ hg log -T status -C -r 10
2066 $ hg log -T status -C -r 10
2067 changeset: 10:0f9759ec227a
2067 changeset: 10:0f9759ec227a
2068 tag: tip
2068 tag: tip
2069 user: test
2069 user: test
2070 date: Thu Jan 01 00:00:00 1970 +0000
2070 date: Thu Jan 01 00:00:00 1970 +0000
2071 summary: Modify, add, remove, rename
2071 summary: Modify, add, remove, rename
2072 files:
2072 files:
2073 M third
2073 M third
2074 A b
2074 A b
2075 A fifth
2075 A fifth
2076 fourth
2076 fourth
2077 R a
2077 R a
2078 R fourth
2078 R fourth
2079
2079
2080 $ hg log -T status -C -r 10 -v
2080 $ hg log -T status -C -r 10 -v
2081 changeset: 10:0f9759ec227a
2081 changeset: 10:0f9759ec227a
2082 tag: tip
2082 tag: tip
2083 user: test
2083 user: test
2084 date: Thu Jan 01 00:00:00 1970 +0000
2084 date: Thu Jan 01 00:00:00 1970 +0000
2085 description:
2085 description:
2086 Modify, add, remove, rename
2086 Modify, add, remove, rename
2087
2087
2088 files:
2088 files:
2089 M third
2089 M third
2090 A b
2090 A b
2091 A fifth
2091 A fifth
2092 fourth
2092 fourth
2093 R a
2093 R a
2094 R fourth
2094 R fourth
2095
2095
2096 $ hg log -T status -C -r 10 --debug
2096 $ hg log -T status -C -r 10 --debug
2097 changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c
2097 changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c
2098 tag: tip
2098 tag: tip
2099 phase: secret
2099 phase: secret
2100 parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066
2100 parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066
2101 parent: -1:0000000000000000000000000000000000000000
2101 parent: -1:0000000000000000000000000000000000000000
2102 manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567
2102 manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567
2103 user: test
2103 user: test
2104 date: Thu Jan 01 00:00:00 1970 +0000
2104 date: Thu Jan 01 00:00:00 1970 +0000
2105 extra: branch=default
2105 extra: branch=default
2106 description:
2106 description:
2107 Modify, add, remove, rename
2107 Modify, add, remove, rename
2108
2108
2109 files:
2109 files:
2110 M third
2110 M third
2111 A b
2111 A b
2112 A fifth
2112 A fifth
2113 fourth
2113 fourth
2114 R a
2114 R a
2115 R fourth
2115 R fourth
2116
2116
2117 $ hg log -T status -C -r 10 --quiet
2117 $ hg log -T status -C -r 10 --quiet
2118 10:0f9759ec227a
2118 10:0f9759ec227a
2119 $ hg --color=debug log -T status -r 10
2119 $ hg --color=debug log -T status -r 10
2120 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2120 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2121 [log.tag|tag: tip]
2121 [log.tag|tag: tip]
2122 [log.user|user: test]
2122 [log.user|user: test]
2123 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2123 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2124 [log.summary|summary: Modify, add, remove, rename]
2124 [log.summary|summary: Modify, add, remove, rename]
2125 [ui.note log.files|files:]
2125 [ui.note log.files|files:]
2126 [status.modified|M third]
2126 [status.modified|M third]
2127 [status.added|A b]
2127 [status.added|A b]
2128 [status.added|A fifth]
2128 [status.added|A fifth]
2129 [status.removed|R a]
2129 [status.removed|R a]
2130 [status.removed|R fourth]
2130 [status.removed|R fourth]
2131
2131
2132 $ hg --color=debug log -T status -C -r 10
2132 $ hg --color=debug log -T status -C -r 10
2133 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2133 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2134 [log.tag|tag: tip]
2134 [log.tag|tag: tip]
2135 [log.user|user: test]
2135 [log.user|user: test]
2136 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2136 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2137 [log.summary|summary: Modify, add, remove, rename]
2137 [log.summary|summary: Modify, add, remove, rename]
2138 [ui.note log.files|files:]
2138 [ui.note log.files|files:]
2139 [status.modified|M third]
2139 [status.modified|M third]
2140 [status.added|A b]
2140 [status.added|A b]
2141 [status.added|A fifth]
2141 [status.added|A fifth]
2142 [status.copied| fourth]
2142 [status.copied| fourth]
2143 [status.removed|R a]
2143 [status.removed|R a]
2144 [status.removed|R fourth]
2144 [status.removed|R fourth]
2145
2145
2146 $ hg --color=debug log -T status -C -r 10 -v
2146 $ hg --color=debug log -T status -C -r 10 -v
2147 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2147 [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
2148 [log.tag|tag: tip]
2148 [log.tag|tag: tip]
2149 [log.user|user: test]
2149 [log.user|user: test]
2150 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2150 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2151 [ui.note log.description|description:]
2151 [ui.note log.description|description:]
2152 [ui.note log.description|Modify, add, remove, rename]
2152 [ui.note log.description|Modify, add, remove, rename]
2153
2153
2154 [ui.note log.files|files:]
2154 [ui.note log.files|files:]
2155 [status.modified|M third]
2155 [status.modified|M third]
2156 [status.added|A b]
2156 [status.added|A b]
2157 [status.added|A fifth]
2157 [status.added|A fifth]
2158 [status.copied| fourth]
2158 [status.copied| fourth]
2159 [status.removed|R a]
2159 [status.removed|R a]
2160 [status.removed|R fourth]
2160 [status.removed|R fourth]
2161
2161
2162 $ hg --color=debug log -T status -C -r 10 --debug
2162 $ hg --color=debug log -T status -C -r 10 --debug
2163 [log.changeset changeset.secret|changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c]
2163 [log.changeset changeset.secret|changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c]
2164 [log.tag|tag: tip]
2164 [log.tag|tag: tip]
2165 [log.phase|phase: secret]
2165 [log.phase|phase: secret]
2166 [log.parent changeset.secret|parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066]
2166 [log.parent changeset.secret|parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066]
2167 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2167 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2168 [ui.debug log.manifest|manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567]
2168 [ui.debug log.manifest|manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567]
2169 [log.user|user: test]
2169 [log.user|user: test]
2170 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2170 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
2171 [ui.debug log.extra|extra: branch=default]
2171 [ui.debug log.extra|extra: branch=default]
2172 [ui.note log.description|description:]
2172 [ui.note log.description|description:]
2173 [ui.note log.description|Modify, add, remove, rename]
2173 [ui.note log.description|Modify, add, remove, rename]
2174
2174
2175 [ui.note log.files|files:]
2175 [ui.note log.files|files:]
2176 [status.modified|M third]
2176 [status.modified|M third]
2177 [status.added|A b]
2177 [status.added|A b]
2178 [status.added|A fifth]
2178 [status.added|A fifth]
2179 [status.copied| fourth]
2179 [status.copied| fourth]
2180 [status.removed|R a]
2180 [status.removed|R a]
2181 [status.removed|R fourth]
2181 [status.removed|R fourth]
2182
2182
2183 $ hg --color=debug log -T status -C -r 10 --quiet
2183 $ hg --color=debug log -T status -C -r 10 --quiet
2184 [log.node|10:0f9759ec227a]
2184 [log.node|10:0f9759ec227a]
2185
2185
2186 Check the bisect template
2186 Check the bisect template
2187
2187
2188 $ hg bisect -g 1
2188 $ hg bisect -g 1
2189 $ hg bisect -b 3 --noupdate
2189 $ hg bisect -b 3 --noupdate
2190 Testing changeset 2:97054abb4ab8 (2 changesets remaining, ~1 tests)
2190 Testing changeset 2:97054abb4ab8 (2 changesets remaining, ~1 tests)
2191 $ hg log -T bisect -r 0:4
2191 $ hg log -T bisect -r 0:4
2192 changeset: 0:1e4e1b8f71e0
2192 changeset: 0:1e4e1b8f71e0
2193 bisect: good (implicit)
2193 bisect: good (implicit)
2194 user: User Name <user@hostname>
2194 user: User Name <user@hostname>
2195 date: Mon Jan 12 13:46:40 1970 +0000
2195 date: Mon Jan 12 13:46:40 1970 +0000
2196 summary: line 1
2196 summary: line 1
2197
2197
2198 changeset: 1:b608e9d1a3f0
2198 changeset: 1:b608e9d1a3f0
2199 bisect: good
2199 bisect: good
2200 user: A. N. Other <other@place>
2200 user: A. N. Other <other@place>
2201 date: Tue Jan 13 17:33:20 1970 +0000
2201 date: Tue Jan 13 17:33:20 1970 +0000
2202 summary: other 1
2202 summary: other 1
2203
2203
2204 changeset: 2:97054abb4ab8
2204 changeset: 2:97054abb4ab8
2205 bisect: untested
2205 bisect: untested
2206 user: other@place
2206 user: other@place
2207 date: Wed Jan 14 21:20:00 1970 +0000
2207 date: Wed Jan 14 21:20:00 1970 +0000
2208 summary: no person
2208 summary: no person
2209
2209
2210 changeset: 3:10e46f2dcbf4
2210 changeset: 3:10e46f2dcbf4
2211 bisect: bad
2211 bisect: bad
2212 user: person
2212 user: person
2213 date: Fri Jan 16 01:06:40 1970 +0000
2213 date: Fri Jan 16 01:06:40 1970 +0000
2214 summary: no user, no domain
2214 summary: no user, no domain
2215
2215
2216 changeset: 4:bbe44766e73d
2216 changeset: 4:bbe44766e73d
2217 bisect: bad (implicit)
2217 bisect: bad (implicit)
2218 branch: foo
2218 branch: foo
2219 user: person
2219 user: person
2220 date: Sat Jan 17 04:53:20 1970 +0000
2220 date: Sat Jan 17 04:53:20 1970 +0000
2221 summary: new branch
2221 summary: new branch
2222
2222
2223 $ hg log --debug -T bisect -r 0:4
2223 $ hg log --debug -T bisect -r 0:4
2224 changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2224 changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2225 bisect: good (implicit)
2225 bisect: good (implicit)
2226 phase: public
2226 phase: public
2227 parent: -1:0000000000000000000000000000000000000000
2227 parent: -1:0000000000000000000000000000000000000000
2228 parent: -1:0000000000000000000000000000000000000000
2228 parent: -1:0000000000000000000000000000000000000000
2229 manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
2229 manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
2230 user: User Name <user@hostname>
2230 user: User Name <user@hostname>
2231 date: Mon Jan 12 13:46:40 1970 +0000
2231 date: Mon Jan 12 13:46:40 1970 +0000
2232 files+: a
2232 files+: a
2233 extra: branch=default
2233 extra: branch=default
2234 description:
2234 description:
2235 line 1
2235 line 1
2236 line 2
2236 line 2
2237
2237
2238
2238
2239 changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2239 changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2240 bisect: good
2240 bisect: good
2241 phase: public
2241 phase: public
2242 parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2242 parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
2243 parent: -1:0000000000000000000000000000000000000000
2243 parent: -1:0000000000000000000000000000000000000000
2244 manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
2244 manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
2245 user: A. N. Other <other@place>
2245 user: A. N. Other <other@place>
2246 date: Tue Jan 13 17:33:20 1970 +0000
2246 date: Tue Jan 13 17:33:20 1970 +0000
2247 files+: b
2247 files+: b
2248 extra: branch=default
2248 extra: branch=default
2249 description:
2249 description:
2250 other 1
2250 other 1
2251 other 2
2251 other 2
2252
2252
2253 other 3
2253 other 3
2254
2254
2255
2255
2256 changeset: 2:97054abb4ab824450e9164180baf491ae0078465
2256 changeset: 2:97054abb4ab824450e9164180baf491ae0078465
2257 bisect: untested
2257 bisect: untested
2258 phase: public
2258 phase: public
2259 parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2259 parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
2260 parent: -1:0000000000000000000000000000000000000000
2260 parent: -1:0000000000000000000000000000000000000000
2261 manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
2261 manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
2262 user: other@place
2262 user: other@place
2263 date: Wed Jan 14 21:20:00 1970 +0000
2263 date: Wed Jan 14 21:20:00 1970 +0000
2264 files+: c
2264 files+: c
2265 extra: branch=default
2265 extra: branch=default
2266 description:
2266 description:
2267 no person
2267 no person
2268
2268
2269
2269
2270 changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2270 changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2271 bisect: bad
2271 bisect: bad
2272 phase: public
2272 phase: public
2273 parent: 2:97054abb4ab824450e9164180baf491ae0078465
2273 parent: 2:97054abb4ab824450e9164180baf491ae0078465
2274 parent: -1:0000000000000000000000000000000000000000
2274 parent: -1:0000000000000000000000000000000000000000
2275 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2275 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2276 user: person
2276 user: person
2277 date: Fri Jan 16 01:06:40 1970 +0000
2277 date: Fri Jan 16 01:06:40 1970 +0000
2278 files: c
2278 files: c
2279 extra: branch=default
2279 extra: branch=default
2280 description:
2280 description:
2281 no user, no domain
2281 no user, no domain
2282
2282
2283
2283
2284 changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
2284 changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
2285 bisect: bad (implicit)
2285 bisect: bad (implicit)
2286 branch: foo
2286 branch: foo
2287 phase: draft
2287 phase: draft
2288 parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2288 parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
2289 parent: -1:0000000000000000000000000000000000000000
2289 parent: -1:0000000000000000000000000000000000000000
2290 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2290 manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
2291 user: person
2291 user: person
2292 date: Sat Jan 17 04:53:20 1970 +0000
2292 date: Sat Jan 17 04:53:20 1970 +0000
2293 extra: branch=foo
2293 extra: branch=foo
2294 description:
2294 description:
2295 new branch
2295 new branch
2296
2296
2297
2297
2298 $ hg log -v -T bisect -r 0:4
2298 $ hg log -v -T bisect -r 0:4
2299 changeset: 0:1e4e1b8f71e0
2299 changeset: 0:1e4e1b8f71e0
2300 bisect: good (implicit)
2300 bisect: good (implicit)
2301 user: User Name <user@hostname>
2301 user: User Name <user@hostname>
2302 date: Mon Jan 12 13:46:40 1970 +0000
2302 date: Mon Jan 12 13:46:40 1970 +0000
2303 files: a
2303 files: a
2304 description:
2304 description:
2305 line 1
2305 line 1
2306 line 2
2306 line 2
2307
2307
2308
2308
2309 changeset: 1:b608e9d1a3f0
2309 changeset: 1:b608e9d1a3f0
2310 bisect: good
2310 bisect: good
2311 user: A. N. Other <other@place>
2311 user: A. N. Other <other@place>
2312 date: Tue Jan 13 17:33:20 1970 +0000
2312 date: Tue Jan 13 17:33:20 1970 +0000
2313 files: b
2313 files: b
2314 description:
2314 description:
2315 other 1
2315 other 1
2316 other 2
2316 other 2
2317
2317
2318 other 3
2318 other 3
2319
2319
2320
2320
2321 changeset: 2:97054abb4ab8
2321 changeset: 2:97054abb4ab8
2322 bisect: untested
2322 bisect: untested
2323 user: other@place
2323 user: other@place
2324 date: Wed Jan 14 21:20:00 1970 +0000
2324 date: Wed Jan 14 21:20:00 1970 +0000
2325 files: c
2325 files: c
2326 description:
2326 description:
2327 no person
2327 no person
2328
2328
2329
2329
2330 changeset: 3:10e46f2dcbf4
2330 changeset: 3:10e46f2dcbf4
2331 bisect: bad
2331 bisect: bad
2332 user: person
2332 user: person
2333 date: Fri Jan 16 01:06:40 1970 +0000
2333 date: Fri Jan 16 01:06:40 1970 +0000
2334 files: c
2334 files: c
2335 description:
2335 description:
2336 no user, no domain
2336 no user, no domain
2337
2337
2338
2338
2339 changeset: 4:bbe44766e73d
2339 changeset: 4:bbe44766e73d
2340 bisect: bad (implicit)
2340 bisect: bad (implicit)
2341 branch: foo
2341 branch: foo
2342 user: person
2342 user: person
2343 date: Sat Jan 17 04:53:20 1970 +0000
2343 date: Sat Jan 17 04:53:20 1970 +0000
2344 description:
2344 description:
2345 new branch
2345 new branch
2346
2346
2347
2347
2348 $ hg --color=debug log -T bisect -r 0:4
2348 $ hg --color=debug log -T bisect -r 0:4
2349 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2349 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2350 [log.bisect bisect.good|bisect: good (implicit)]
2350 [log.bisect bisect.good|bisect: good (implicit)]
2351 [log.user|user: User Name <user@hostname>]
2351 [log.user|user: User Name <user@hostname>]
2352 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2352 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2353 [log.summary|summary: line 1]
2353 [log.summary|summary: line 1]
2354
2354
2355 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2355 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2356 [log.bisect bisect.good|bisect: good]
2356 [log.bisect bisect.good|bisect: good]
2357 [log.user|user: A. N. Other <other@place>]
2357 [log.user|user: A. N. Other <other@place>]
2358 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2358 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2359 [log.summary|summary: other 1]
2359 [log.summary|summary: other 1]
2360
2360
2361 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2361 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2362 [log.bisect bisect.untested|bisect: untested]
2362 [log.bisect bisect.untested|bisect: untested]
2363 [log.user|user: other@place]
2363 [log.user|user: other@place]
2364 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2364 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2365 [log.summary|summary: no person]
2365 [log.summary|summary: no person]
2366
2366
2367 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2367 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2368 [log.bisect bisect.bad|bisect: bad]
2368 [log.bisect bisect.bad|bisect: bad]
2369 [log.user|user: person]
2369 [log.user|user: person]
2370 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2370 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2371 [log.summary|summary: no user, no domain]
2371 [log.summary|summary: no user, no domain]
2372
2372
2373 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2373 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2374 [log.bisect bisect.bad|bisect: bad (implicit)]
2374 [log.bisect bisect.bad|bisect: bad (implicit)]
2375 [log.branch|branch: foo]
2375 [log.branch|branch: foo]
2376 [log.user|user: person]
2376 [log.user|user: person]
2377 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2377 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2378 [log.summary|summary: new branch]
2378 [log.summary|summary: new branch]
2379
2379
2380 $ hg --color=debug log --debug -T bisect -r 0:4
2380 $ hg --color=debug log --debug -T bisect -r 0:4
2381 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2381 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2382 [log.bisect bisect.good|bisect: good (implicit)]
2382 [log.bisect bisect.good|bisect: good (implicit)]
2383 [log.phase|phase: public]
2383 [log.phase|phase: public]
2384 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2384 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2385 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2385 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2386 [ui.debug log.manifest|manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0]
2386 [ui.debug log.manifest|manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0]
2387 [log.user|user: User Name <user@hostname>]
2387 [log.user|user: User Name <user@hostname>]
2388 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2388 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2389 [ui.debug log.files|files+: a]
2389 [ui.debug log.files|files+: a]
2390 [ui.debug log.extra|extra: branch=default]
2390 [ui.debug log.extra|extra: branch=default]
2391 [ui.note log.description|description:]
2391 [ui.note log.description|description:]
2392 [ui.note log.description|line 1
2392 [ui.note log.description|line 1
2393 line 2]
2393 line 2]
2394
2394
2395
2395
2396 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2396 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2397 [log.bisect bisect.good|bisect: good]
2397 [log.bisect bisect.good|bisect: good]
2398 [log.phase|phase: public]
2398 [log.phase|phase: public]
2399 [log.parent changeset.public|parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2399 [log.parent changeset.public|parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
2400 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2400 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2401 [ui.debug log.manifest|manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55]
2401 [ui.debug log.manifest|manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55]
2402 [log.user|user: A. N. Other <other@place>]
2402 [log.user|user: A. N. Other <other@place>]
2403 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2403 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2404 [ui.debug log.files|files+: b]
2404 [ui.debug log.files|files+: b]
2405 [ui.debug log.extra|extra: branch=default]
2405 [ui.debug log.extra|extra: branch=default]
2406 [ui.note log.description|description:]
2406 [ui.note log.description|description:]
2407 [ui.note log.description|other 1
2407 [ui.note log.description|other 1
2408 other 2
2408 other 2
2409
2409
2410 other 3]
2410 other 3]
2411
2411
2412
2412
2413 [log.changeset changeset.public|changeset: 2:97054abb4ab824450e9164180baf491ae0078465]
2413 [log.changeset changeset.public|changeset: 2:97054abb4ab824450e9164180baf491ae0078465]
2414 [log.bisect bisect.untested|bisect: untested]
2414 [log.bisect bisect.untested|bisect: untested]
2415 [log.phase|phase: public]
2415 [log.phase|phase: public]
2416 [log.parent changeset.public|parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2416 [log.parent changeset.public|parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
2417 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2417 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2418 [ui.debug log.manifest|manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1]
2418 [ui.debug log.manifest|manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1]
2419 [log.user|user: other@place]
2419 [log.user|user: other@place]
2420 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2420 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2421 [ui.debug log.files|files+: c]
2421 [ui.debug log.files|files+: c]
2422 [ui.debug log.extra|extra: branch=default]
2422 [ui.debug log.extra|extra: branch=default]
2423 [ui.note log.description|description:]
2423 [ui.note log.description|description:]
2424 [ui.note log.description|no person]
2424 [ui.note log.description|no person]
2425
2425
2426
2426
2427 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2427 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2428 [log.bisect bisect.bad|bisect: bad]
2428 [log.bisect bisect.bad|bisect: bad]
2429 [log.phase|phase: public]
2429 [log.phase|phase: public]
2430 [log.parent changeset.public|parent: 2:97054abb4ab824450e9164180baf491ae0078465]
2430 [log.parent changeset.public|parent: 2:97054abb4ab824450e9164180baf491ae0078465]
2431 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2431 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2432 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2432 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2433 [log.user|user: person]
2433 [log.user|user: person]
2434 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2434 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2435 [ui.debug log.files|files: c]
2435 [ui.debug log.files|files: c]
2436 [ui.debug log.extra|extra: branch=default]
2436 [ui.debug log.extra|extra: branch=default]
2437 [ui.note log.description|description:]
2437 [ui.note log.description|description:]
2438 [ui.note log.description|no user, no domain]
2438 [ui.note log.description|no user, no domain]
2439
2439
2440
2440
2441 [log.changeset changeset.draft|changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74]
2441 [log.changeset changeset.draft|changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74]
2442 [log.bisect bisect.bad|bisect: bad (implicit)]
2442 [log.bisect bisect.bad|bisect: bad (implicit)]
2443 [log.branch|branch: foo]
2443 [log.branch|branch: foo]
2444 [log.phase|phase: draft]
2444 [log.phase|phase: draft]
2445 [log.parent changeset.public|parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2445 [log.parent changeset.public|parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
2446 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2446 [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
2447 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2447 [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
2448 [log.user|user: person]
2448 [log.user|user: person]
2449 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2449 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2450 [ui.debug log.extra|extra: branch=foo]
2450 [ui.debug log.extra|extra: branch=foo]
2451 [ui.note log.description|description:]
2451 [ui.note log.description|description:]
2452 [ui.note log.description|new branch]
2452 [ui.note log.description|new branch]
2453
2453
2454
2454
2455 $ hg --color=debug log -v -T bisect -r 0:4
2455 $ hg --color=debug log -v -T bisect -r 0:4
2456 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2456 [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
2457 [log.bisect bisect.good|bisect: good (implicit)]
2457 [log.bisect bisect.good|bisect: good (implicit)]
2458 [log.user|user: User Name <user@hostname>]
2458 [log.user|user: User Name <user@hostname>]
2459 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2459 [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
2460 [ui.note log.files|files: a]
2460 [ui.note log.files|files: a]
2461 [ui.note log.description|description:]
2461 [ui.note log.description|description:]
2462 [ui.note log.description|line 1
2462 [ui.note log.description|line 1
2463 line 2]
2463 line 2]
2464
2464
2465
2465
2466 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2466 [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
2467 [log.bisect bisect.good|bisect: good]
2467 [log.bisect bisect.good|bisect: good]
2468 [log.user|user: A. N. Other <other@place>]
2468 [log.user|user: A. N. Other <other@place>]
2469 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2469 [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
2470 [ui.note log.files|files: b]
2470 [ui.note log.files|files: b]
2471 [ui.note log.description|description:]
2471 [ui.note log.description|description:]
2472 [ui.note log.description|other 1
2472 [ui.note log.description|other 1
2473 other 2
2473 other 2
2474
2474
2475 other 3]
2475 other 3]
2476
2476
2477
2477
2478 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2478 [log.changeset changeset.public|changeset: 2:97054abb4ab8]
2479 [log.bisect bisect.untested|bisect: untested]
2479 [log.bisect bisect.untested|bisect: untested]
2480 [log.user|user: other@place]
2480 [log.user|user: other@place]
2481 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2481 [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
2482 [ui.note log.files|files: c]
2482 [ui.note log.files|files: c]
2483 [ui.note log.description|description:]
2483 [ui.note log.description|description:]
2484 [ui.note log.description|no person]
2484 [ui.note log.description|no person]
2485
2485
2486
2486
2487 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2487 [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
2488 [log.bisect bisect.bad|bisect: bad]
2488 [log.bisect bisect.bad|bisect: bad]
2489 [log.user|user: person]
2489 [log.user|user: person]
2490 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2490 [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
2491 [ui.note log.files|files: c]
2491 [ui.note log.files|files: c]
2492 [ui.note log.description|description:]
2492 [ui.note log.description|description:]
2493 [ui.note log.description|no user, no domain]
2493 [ui.note log.description|no user, no domain]
2494
2494
2495
2495
2496 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2496 [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
2497 [log.bisect bisect.bad|bisect: bad (implicit)]
2497 [log.bisect bisect.bad|bisect: bad (implicit)]
2498 [log.branch|branch: foo]
2498 [log.branch|branch: foo]
2499 [log.user|user: person]
2499 [log.user|user: person]
2500 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2500 [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
2501 [ui.note log.description|description:]
2501 [ui.note log.description|description:]
2502 [ui.note log.description|new branch]
2502 [ui.note log.description|new branch]
2503
2503
2504
2504
2505 $ hg bisect --reset
2505 $ hg bisect --reset
2506
2506
2507 Error on syntax:
2507 Error on syntax:
2508
2508
2509 $ echo 'x = "f' >> t
2509 $ echo 'x = "f' >> t
2510 $ hg log
2510 $ hg log
2511 abort: t:3: unmatched quotes
2511 abort: t:3: unmatched quotes
2512 [255]
2512 [255]
2513
2513
2514 $ hg log -T '{date'
2514 $ hg log -T '{date'
2515 hg: parse error at 1: unterminated template expansion
2515 hg: parse error at 1: unterminated template expansion
2516 [255]
2516 [255]
2517
2517
2518 Behind the scenes, this will throw TypeError
2518 Behind the scenes, this will throw TypeError
2519
2519
2520 $ hg log -l 3 --template '{date|obfuscate}\n'
2520 $ hg log -l 3 --template '{date|obfuscate}\n'
2521 abort: template filter 'obfuscate' is not compatible with keyword 'date'
2521 abort: template filter 'obfuscate' is not compatible with keyword 'date'
2522 [255]
2522 [255]
2523
2523
2524 Behind the scenes, this will throw a ValueError
2524 Behind the scenes, this will throw a ValueError
2525
2525
2526 $ hg log -l 3 --template 'line: {desc|shortdate}\n'
2526 $ hg log -l 3 --template 'line: {desc|shortdate}\n'
2527 abort: template filter 'shortdate' is not compatible with keyword 'desc'
2527 abort: template filter 'shortdate' is not compatible with keyword 'desc'
2528 [255]
2528 [255]
2529
2529
2530 Behind the scenes, this will throw AttributeError
2530 Behind the scenes, this will throw AttributeError
2531
2531
2532 $ hg log -l 3 --template 'line: {date|escape}\n'
2532 $ hg log -l 3 --template 'line: {date|escape}\n'
2533 abort: template filter 'escape' is not compatible with keyword 'date'
2533 abort: template filter 'escape' is not compatible with keyword 'date'
2534 [255]
2534 [255]
2535
2535
2536 $ hg log -l 3 --template 'line: {extras|localdate}\n'
2536 $ hg log -l 3 --template 'line: {extras|localdate}\n'
2537 hg: parse error: localdate expects a date information
2537 hg: parse error: localdate expects a date information
2538 [255]
2538 [255]
2539
2539
2540 Behind the scenes, this will throw ValueError
2540 Behind the scenes, this will throw ValueError
2541
2541
2542 $ hg tip --template '{author|email|date}\n'
2542 $ hg tip --template '{author|email|date}\n'
2543 hg: parse error: date expects a date information
2543 hg: parse error: date expects a date information
2544 [255]
2544 [255]
2545
2545
2546 Error in nested template:
2546 Error in nested template:
2547
2547
2548 $ hg log -T '{"date'
2548 $ hg log -T '{"date'
2549 hg: parse error at 2: unterminated string
2549 hg: parse error at 2: unterminated string
2550 [255]
2550 [255]
2551
2551
2552 $ hg log -T '{"foo{date|=}"}'
2552 $ hg log -T '{"foo{date|=}"}'
2553 hg: parse error at 11: syntax error
2553 hg: parse error at 11: syntax error
2554 [255]
2554 [255]
2555
2555
2556 Thrown an error if a template function doesn't exist
2556 Thrown an error if a template function doesn't exist
2557
2557
2558 $ hg tip --template '{foo()}\n'
2558 $ hg tip --template '{foo()}\n'
2559 hg: parse error: unknown function 'foo'
2559 hg: parse error: unknown function 'foo'
2560 [255]
2560 [255]
2561
2561
2562 Pass generator object created by template function to filter
2562 Pass generator object created by template function to filter
2563
2563
2564 $ hg log -l 1 --template '{if(author, author)|user}\n'
2564 $ hg log -l 1 --template '{if(author, author)|user}\n'
2565 test
2565 test
2566
2566
2567 Test diff function:
2567 Test diff function:
2568
2568
2569 $ hg diff -c 8
2569 $ hg diff -c 8
2570 diff -r 29114dbae42b -r 95c24699272e fourth
2570 diff -r 29114dbae42b -r 95c24699272e fourth
2571 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2571 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2572 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2572 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2573 @@ -0,0 +1,1 @@
2573 @@ -0,0 +1,1 @@
2574 +second
2574 +second
2575 diff -r 29114dbae42b -r 95c24699272e second
2575 diff -r 29114dbae42b -r 95c24699272e second
2576 --- a/second Mon Jan 12 13:46:40 1970 +0000
2576 --- a/second Mon Jan 12 13:46:40 1970 +0000
2577 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2577 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2578 @@ -1,1 +0,0 @@
2578 @@ -1,1 +0,0 @@
2579 -second
2579 -second
2580 diff -r 29114dbae42b -r 95c24699272e third
2580 diff -r 29114dbae42b -r 95c24699272e third
2581 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2581 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2582 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2582 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2583 @@ -0,0 +1,1 @@
2583 @@ -0,0 +1,1 @@
2584 +third
2584 +third
2585
2585
2586 $ hg log -r 8 -T "{diff()}"
2586 $ hg log -r 8 -T "{diff()}"
2587 diff -r 29114dbae42b -r 95c24699272e fourth
2587 diff -r 29114dbae42b -r 95c24699272e fourth
2588 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2588 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2589 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2589 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2590 @@ -0,0 +1,1 @@
2590 @@ -0,0 +1,1 @@
2591 +second
2591 +second
2592 diff -r 29114dbae42b -r 95c24699272e second
2592 diff -r 29114dbae42b -r 95c24699272e second
2593 --- a/second Mon Jan 12 13:46:40 1970 +0000
2593 --- a/second Mon Jan 12 13:46:40 1970 +0000
2594 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2594 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2595 @@ -1,1 +0,0 @@
2595 @@ -1,1 +0,0 @@
2596 -second
2596 -second
2597 diff -r 29114dbae42b -r 95c24699272e third
2597 diff -r 29114dbae42b -r 95c24699272e third
2598 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2598 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2599 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2599 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2600 @@ -0,0 +1,1 @@
2600 @@ -0,0 +1,1 @@
2601 +third
2601 +third
2602
2602
2603 $ hg log -r 8 -T "{diff('glob:f*')}"
2603 $ hg log -r 8 -T "{diff('glob:f*')}"
2604 diff -r 29114dbae42b -r 95c24699272e fourth
2604 diff -r 29114dbae42b -r 95c24699272e fourth
2605 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2605 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2606 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2606 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2607 @@ -0,0 +1,1 @@
2607 @@ -0,0 +1,1 @@
2608 +second
2608 +second
2609
2609
2610 $ hg log -r 8 -T "{diff('', 'glob:f*')}"
2610 $ hg log -r 8 -T "{diff('', 'glob:f*')}"
2611 diff -r 29114dbae42b -r 95c24699272e second
2611 diff -r 29114dbae42b -r 95c24699272e second
2612 --- a/second Mon Jan 12 13:46:40 1970 +0000
2612 --- a/second Mon Jan 12 13:46:40 1970 +0000
2613 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2613 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
2614 @@ -1,1 +0,0 @@
2614 @@ -1,1 +0,0 @@
2615 -second
2615 -second
2616 diff -r 29114dbae42b -r 95c24699272e third
2616 diff -r 29114dbae42b -r 95c24699272e third
2617 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2617 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2618 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2618 +++ b/third Wed Jan 01 10:01:00 2020 +0000
2619 @@ -0,0 +1,1 @@
2619 @@ -0,0 +1,1 @@
2620 +third
2620 +third
2621
2621
2622 $ hg log -r 8 -T "{diff('FOURTH'|lower)}"
2622 $ hg log -r 8 -T "{diff('FOURTH'|lower)}"
2623 diff -r 29114dbae42b -r 95c24699272e fourth
2623 diff -r 29114dbae42b -r 95c24699272e fourth
2624 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2624 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2625 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2625 +++ b/fourth Wed Jan 01 10:01:00 2020 +0000
2626 @@ -0,0 +1,1 @@
2626 @@ -0,0 +1,1 @@
2627 +second
2627 +second
2628
2628
2629 $ cd ..
2629 $ cd ..
2630
2630
2631
2631
2632 latesttag:
2632 latesttag:
2633
2633
2634 $ hg init latesttag
2634 $ hg init latesttag
2635 $ cd latesttag
2635 $ cd latesttag
2636
2636
2637 $ echo a > file
2637 $ echo a > file
2638 $ hg ci -Am a -d '0 0'
2638 $ hg ci -Am a -d '0 0'
2639 adding file
2639 adding file
2640
2640
2641 $ echo b >> file
2641 $ echo b >> file
2642 $ hg ci -m b -d '1 0'
2642 $ hg ci -m b -d '1 0'
2643
2643
2644 $ echo c >> head1
2644 $ echo c >> head1
2645 $ hg ci -Am h1c -d '2 0'
2645 $ hg ci -Am h1c -d '2 0'
2646 adding head1
2646 adding head1
2647
2647
2648 $ hg update -q 1
2648 $ hg update -q 1
2649 $ echo d >> head2
2649 $ echo d >> head2
2650 $ hg ci -Am h2d -d '3 0'
2650 $ hg ci -Am h2d -d '3 0'
2651 adding head2
2651 adding head2
2652 created new head
2652 created new head
2653
2653
2654 $ echo e >> head2
2654 $ echo e >> head2
2655 $ hg ci -m h2e -d '4 0'
2655 $ hg ci -m h2e -d '4 0'
2656
2656
2657 $ hg merge -q
2657 $ hg merge -q
2658 $ hg ci -m merge -d '5 -3600'
2658 $ hg ci -m merge -d '5 -3600'
2659
2659
2660 No tag set:
2660 No tag set:
2661
2661
2662 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2662 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2663 5: null+5
2663 5: null+5
2664 4: null+4
2664 4: null+4
2665 3: null+3
2665 3: null+3
2666 2: null+3
2666 2: null+3
2667 1: null+2
2667 1: null+2
2668 0: null+1
2668 0: null+1
2669
2669
2670 One common tag: longest path wins:
2670 One common tag: longest path wins:
2671
2671
2672 $ hg tag -r 1 -m t1 -d '6 0' t1
2672 $ hg tag -r 1 -m t1 -d '6 0' t1
2673 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2673 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2674 6: t1+4
2674 6: t1+4
2675 5: t1+3
2675 5: t1+3
2676 4: t1+2
2676 4: t1+2
2677 3: t1+1
2677 3: t1+1
2678 2: t1+1
2678 2: t1+1
2679 1: t1+0
2679 1: t1+0
2680 0: null+1
2680 0: null+1
2681
2681
2682 One ancestor tag: more recent wins:
2682 One ancestor tag: more recent wins:
2683
2683
2684 $ hg tag -r 2 -m t2 -d '7 0' t2
2684 $ hg tag -r 2 -m t2 -d '7 0' t2
2685 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2685 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2686 7: t2+3
2686 7: t2+3
2687 6: t2+2
2687 6: t2+2
2688 5: t2+1
2688 5: t2+1
2689 4: t1+2
2689 4: t1+2
2690 3: t1+1
2690 3: t1+1
2691 2: t2+0
2691 2: t2+0
2692 1: t1+0
2692 1: t1+0
2693 0: null+1
2693 0: null+1
2694
2694
2695 Two branch tags: more recent wins:
2695 Two branch tags: more recent wins:
2696
2696
2697 $ hg tag -r 3 -m t3 -d '8 0' t3
2697 $ hg tag -r 3 -m t3 -d '8 0' t3
2698 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2698 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2699 8: t3+5
2699 8: t3+5
2700 7: t3+4
2700 7: t3+4
2701 6: t3+3
2701 6: t3+3
2702 5: t3+2
2702 5: t3+2
2703 4: t3+1
2703 4: t3+1
2704 3: t3+0
2704 3: t3+0
2705 2: t2+0
2705 2: t2+0
2706 1: t1+0
2706 1: t1+0
2707 0: null+1
2707 0: null+1
2708
2708
2709 Merged tag overrides:
2709 Merged tag overrides:
2710
2710
2711 $ hg tag -r 5 -m t5 -d '9 0' t5
2711 $ hg tag -r 5 -m t5 -d '9 0' t5
2712 $ hg tag -r 3 -m at3 -d '10 0' at3
2712 $ hg tag -r 3 -m at3 -d '10 0' at3
2713 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2713 $ hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
2714 10: t5+5
2714 10: t5+5
2715 9: t5+4
2715 9: t5+4
2716 8: t5+3
2716 8: t5+3
2717 7: t5+2
2717 7: t5+2
2718 6: t5+1
2718 6: t5+1
2719 5: t5+0
2719 5: t5+0
2720 4: at3:t3+1
2720 4: at3:t3+1
2721 3: at3:t3+0
2721 3: at3:t3+0
2722 2: t2+0
2722 2: t2+0
2723 1: t1+0
2723 1: t1+0
2724 0: null+1
2724 0: null+1
2725
2725
2726 $ hg log --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
2726 $ hg log --template "{rev}: {latesttag % '{tag}+{distance},{changes} '}\n"
2727 10: t5+5,5
2727 10: t5+5,5
2728 9: t5+4,4
2728 9: t5+4,4
2729 8: t5+3,3
2729 8: t5+3,3
2730 7: t5+2,2
2730 7: t5+2,2
2731 6: t5+1,1
2731 6: t5+1,1
2732 5: t5+0,0
2732 5: t5+0,0
2733 4: at3+1,1 t3+1,1
2733 4: at3+1,1 t3+1,1
2734 3: at3+0,0 t3+0,0
2734 3: at3+0,0 t3+0,0
2735 2: t2+0,0
2735 2: t2+0,0
2736 1: t1+0,0
2736 1: t1+0,0
2737 0: null+1,1
2737 0: null+1,1
2738
2738
2739 $ hg log --template "{rev}: {latesttag('re:^t[13]$') % '{tag}, C: {changes}, D: {distance}'}\n"
2739 $ hg log --template "{rev}: {latesttag('re:^t[13]$') % '{tag}, C: {changes}, D: {distance}'}\n"
2740 10: t3, C: 8, D: 7
2740 10: t3, C: 8, D: 7
2741 9: t3, C: 7, D: 6
2741 9: t3, C: 7, D: 6
2742 8: t3, C: 6, D: 5
2742 8: t3, C: 6, D: 5
2743 7: t3, C: 5, D: 4
2743 7: t3, C: 5, D: 4
2744 6: t3, C: 4, D: 3
2744 6: t3, C: 4, D: 3
2745 5: t3, C: 3, D: 2
2745 5: t3, C: 3, D: 2
2746 4: t3, C: 1, D: 1
2746 4: t3, C: 1, D: 1
2747 3: t3, C: 0, D: 0
2747 3: t3, C: 0, D: 0
2748 2: t1, C: 1, D: 1
2748 2: t1, C: 1, D: 1
2749 1: t1, C: 0, D: 0
2749 1: t1, C: 0, D: 0
2750 0: null, C: 1, D: 1
2750 0: null, C: 1, D: 1
2751
2751
2752 $ cd ..
2752 $ cd ..
2753
2753
2754
2754
2755 Style path expansion: issue1948 - ui.style option doesn't work on OSX
2755 Style path expansion: issue1948 - ui.style option doesn't work on OSX
2756 if it is a relative path
2756 if it is a relative path
2757
2757
2758 $ mkdir -p home/styles
2758 $ mkdir -p home/styles
2759
2759
2760 $ cat > home/styles/teststyle <<EOF
2760 $ cat > home/styles/teststyle <<EOF
2761 > changeset = 'test {rev}:{node|short}\n'
2761 > changeset = 'test {rev}:{node|short}\n'
2762 > EOF
2762 > EOF
2763
2763
2764 $ HOME=`pwd`/home; export HOME
2764 $ HOME=`pwd`/home; export HOME
2765
2765
2766 $ cat > latesttag/.hg/hgrc <<EOF
2766 $ cat > latesttag/.hg/hgrc <<EOF
2767 > [ui]
2767 > [ui]
2768 > style = ~/styles/teststyle
2768 > style = ~/styles/teststyle
2769 > EOF
2769 > EOF
2770
2770
2771 $ hg -R latesttag tip
2771 $ hg -R latesttag tip
2772 test 10:9b4a630e5f5f
2772 test 10:9b4a630e5f5f
2773
2773
2774 Test recursive showlist template (issue1989):
2774 Test recursive showlist template (issue1989):
2775
2775
2776 $ cat > style1989 <<EOF
2776 $ cat > style1989 <<EOF
2777 > changeset = '{file_mods}{manifest}{extras}'
2777 > changeset = '{file_mods}{manifest}{extras}'
2778 > file_mod = 'M|{author|person}\n'
2778 > file_mod = 'M|{author|person}\n'
2779 > manifest = '{rev},{author}\n'
2779 > manifest = '{rev},{author}\n'
2780 > extra = '{key}: {author}\n'
2780 > extra = '{key}: {author}\n'
2781 > EOF
2781 > EOF
2782
2782
2783 $ hg -R latesttag log -r tip --style=style1989
2783 $ hg -R latesttag log -r tip --style=style1989
2784 M|test
2784 M|test
2785 10,test
2785 10,test
2786 branch: test
2786 branch: test
2787
2787
2788 Test new-style inline templating:
2788 Test new-style inline templating:
2789
2789
2790 $ hg log -R latesttag -r tip --template 'modified files: {file_mods % " {file}\n"}\n'
2790 $ hg log -R latesttag -r tip --template 'modified files: {file_mods % " {file}\n"}\n'
2791 modified files: .hgtags
2791 modified files: .hgtags
2792
2792
2793
2793
2794 $ hg log -R latesttag -r tip -T '{rev % "a"}\n'
2794 $ hg log -R latesttag -r tip -T '{rev % "a"}\n'
2795 hg: parse error: keyword 'rev' is not iterable
2795 hg: parse error: keyword 'rev' is not iterable
2796 [255]
2796 [255]
2797 $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "a"}\n'
2797 $ hg log -R latesttag -r tip -T '{get(extras, "unknown") % "a"}\n'
2798 hg: parse error: None is not iterable
2798 hg: parse error: None is not iterable
2799 [255]
2799 [255]
2800
2800
2801 Test the sub function of templating for expansion:
2801 Test the sub function of templating for expansion:
2802
2802
2803 $ hg log -R latesttag -r 10 --template '{sub("[0-9]", "x", "{rev}")}\n'
2803 $ hg log -R latesttag -r 10 --template '{sub("[0-9]", "x", "{rev}")}\n'
2804 xx
2804 xx
2805
2805
2806 $ hg log -R latesttag -r 10 -T '{sub("[", "x", rev)}\n'
2806 $ hg log -R latesttag -r 10 -T '{sub("[", "x", rev)}\n'
2807 hg: parse error: sub got an invalid pattern: [
2807 hg: parse error: sub got an invalid pattern: [
2808 [255]
2808 [255]
2809 $ hg log -R latesttag -r 10 -T '{sub("[0-9]", r"\1", rev)}\n'
2809 $ hg log -R latesttag -r 10 -T '{sub("[0-9]", r"\1", rev)}\n'
2810 hg: parse error: sub got an invalid replacement: \1
2810 hg: parse error: sub got an invalid replacement: \1
2811 [255]
2811 [255]
2812
2812
2813 Test the strip function with chars specified:
2813 Test the strip function with chars specified:
2814
2814
2815 $ hg log -R latesttag --template '{desc}\n'
2815 $ hg log -R latesttag --template '{desc}\n'
2816 at3
2816 at3
2817 t5
2817 t5
2818 t3
2818 t3
2819 t2
2819 t2
2820 t1
2820 t1
2821 merge
2821 merge
2822 h2e
2822 h2e
2823 h2d
2823 h2d
2824 h1c
2824 h1c
2825 b
2825 b
2826 a
2826 a
2827
2827
2828 $ hg log -R latesttag --template '{strip(desc, "te")}\n'
2828 $ hg log -R latesttag --template '{strip(desc, "te")}\n'
2829 at3
2829 at3
2830 5
2830 5
2831 3
2831 3
2832 2
2832 2
2833 1
2833 1
2834 merg
2834 merg
2835 h2
2835 h2
2836 h2d
2836 h2d
2837 h1c
2837 h1c
2838 b
2838 b
2839 a
2839 a
2840
2840
2841 Test date format:
2841 Test date format:
2842
2842
2843 $ hg log -R latesttag --template 'date: {date(date, "%y %m %d %S %z")}\n'
2843 $ hg log -R latesttag --template 'date: {date(date, "%y %m %d %S %z")}\n'
2844 date: 70 01 01 10 +0000
2844 date: 70 01 01 10 +0000
2845 date: 70 01 01 09 +0000
2845 date: 70 01 01 09 +0000
2846 date: 70 01 01 08 +0000
2846 date: 70 01 01 08 +0000
2847 date: 70 01 01 07 +0000
2847 date: 70 01 01 07 +0000
2848 date: 70 01 01 06 +0000
2848 date: 70 01 01 06 +0000
2849 date: 70 01 01 05 +0100
2849 date: 70 01 01 05 +0100
2850 date: 70 01 01 04 +0000
2850 date: 70 01 01 04 +0000
2851 date: 70 01 01 03 +0000
2851 date: 70 01 01 03 +0000
2852 date: 70 01 01 02 +0000
2852 date: 70 01 01 02 +0000
2853 date: 70 01 01 01 +0000
2853 date: 70 01 01 01 +0000
2854 date: 70 01 01 00 +0000
2854 date: 70 01 01 00 +0000
2855
2855
2856 Test invalid date:
2856 Test invalid date:
2857
2857
2858 $ hg log -R latesttag -T '{date(rev)}\n'
2858 $ hg log -R latesttag -T '{date(rev)}\n'
2859 hg: parse error: date expects a date information
2859 hg: parse error: date expects a date information
2860 [255]
2860 [255]
2861
2861
2862 Test integer literal:
2862 Test integer literal:
2863
2863
2864 $ hg log -Ra -r0 -T '{(0)}\n'
2864 $ hg log -Ra -r0 -T '{(0)}\n'
2865 0
2865 0
2866 $ hg log -Ra -r0 -T '{(123)}\n'
2866 $ hg log -Ra -r0 -T '{(123)}\n'
2867 123
2867 123
2868 $ hg log -Ra -r0 -T '{(-4)}\n'
2868 $ hg log -Ra -r0 -T '{(-4)}\n'
2869 -4
2869 -4
2870 $ hg log -Ra -r0 -T '{(-)}\n'
2870 $ hg log -Ra -r0 -T '{(-)}\n'
2871 hg: parse error at 2: integer literal without digits
2871 hg: parse error at 2: integer literal without digits
2872 [255]
2872 [255]
2873 $ hg log -Ra -r0 -T '{(-a)}\n'
2873 $ hg log -Ra -r0 -T '{(-a)}\n'
2874 hg: parse error at 2: integer literal without digits
2874 hg: parse error at 2: integer literal without digits
2875 [255]
2875 [255]
2876
2876
2877 top-level integer literal is interpreted as symbol (i.e. variable name):
2877 top-level integer literal is interpreted as symbol (i.e. variable name):
2878
2878
2879 $ hg log -Ra -r0 -T '{1}\n'
2879 $ hg log -Ra -r0 -T '{1}\n'
2880
2880
2881 $ hg log -Ra -r0 -T '{if("t", "{1}")}\n'
2881 $ hg log -Ra -r0 -T '{if("t", "{1}")}\n'
2882
2882
2883 $ hg log -Ra -r0 -T '{1|stringify}\n'
2883 $ hg log -Ra -r0 -T '{1|stringify}\n'
2884
2884
2885
2885
2886 unless explicit symbol is expected:
2886 unless explicit symbol is expected:
2887
2887
2888 $ hg log -Ra -r0 -T '{desc|1}\n'
2888 $ hg log -Ra -r0 -T '{desc|1}\n'
2889 hg: parse error: expected a symbol, got 'integer'
2889 hg: parse error: expected a symbol, got 'integer'
2890 [255]
2890 [255]
2891 $ hg log -Ra -r0 -T '{1()}\n'
2891 $ hg log -Ra -r0 -T '{1()}\n'
2892 hg: parse error: expected a symbol, got 'integer'
2892 hg: parse error: expected a symbol, got 'integer'
2893 [255]
2893 [255]
2894
2894
2895 Test string literal:
2895 Test string literal:
2896
2896
2897 $ hg log -Ra -r0 -T '{"string with no template fragment"}\n'
2897 $ hg log -Ra -r0 -T '{"string with no template fragment"}\n'
2898 string with no template fragment
2898 string with no template fragment
2899 $ hg log -Ra -r0 -T '{"template: {rev}"}\n'
2899 $ hg log -Ra -r0 -T '{"template: {rev}"}\n'
2900 template: 0
2900 template: 0
2901 $ hg log -Ra -r0 -T '{r"rawstring: {rev}"}\n'
2901 $ hg log -Ra -r0 -T '{r"rawstring: {rev}"}\n'
2902 rawstring: {rev}
2902 rawstring: {rev}
2903
2903
2904 because map operation requires template, raw string can't be used
2904 because map operation requires template, raw string can't be used
2905
2905
2906 $ hg log -Ra -r0 -T '{files % r"rawstring"}\n'
2906 $ hg log -Ra -r0 -T '{files % r"rawstring"}\n'
2907 hg: parse error: expected template specifier
2907 hg: parse error: expected template specifier
2908 [255]
2908 [255]
2909
2909
2910 Test string escaping:
2910 Test string escaping:
2911
2911
2912 $ hg log -R latesttag -r 0 --template '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
2912 $ hg log -R latesttag -r 0 --template '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
2913 >
2913 >
2914 <>\n<[>
2914 <>\n<[>
2915 <>\n<]>
2915 <>\n<]>
2916 <>\n<
2916 <>\n<
2917
2917
2918 $ hg log -R latesttag -r 0 \
2918 $ hg log -R latesttag -r 0 \
2919 > --config ui.logtemplate='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
2919 > --config ui.logtemplate='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
2920 >
2920 >
2921 <>\n<[>
2921 <>\n<[>
2922 <>\n<]>
2922 <>\n<]>
2923 <>\n<
2923 <>\n<
2924
2924
2925 $ hg log -R latesttag -r 0 -T esc \
2925 $ hg log -R latesttag -r 0 -T esc \
2926 > --config templates.esc='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
2926 > --config templates.esc='>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
2927 >
2927 >
2928 <>\n<[>
2928 <>\n<[>
2929 <>\n<]>
2929 <>\n<]>
2930 <>\n<
2930 <>\n<
2931
2931
2932 $ cat <<'EOF' > esctmpl
2932 $ cat <<'EOF' > esctmpl
2933 > changeset = '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
2933 > changeset = '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
2934 > EOF
2934 > EOF
2935 $ hg log -R latesttag -r 0 --style ./esctmpl
2935 $ hg log -R latesttag -r 0 --style ./esctmpl
2936 >
2936 >
2937 <>\n<[>
2937 <>\n<[>
2938 <>\n<]>
2938 <>\n<]>
2939 <>\n<
2939 <>\n<
2940
2940
2941 Test string escaping of quotes:
2941 Test string escaping of quotes:
2942
2942
2943 $ hg log -Ra -r0 -T '{"\""}\n'
2943 $ hg log -Ra -r0 -T '{"\""}\n'
2944 "
2944 "
2945 $ hg log -Ra -r0 -T '{"\\\""}\n'
2945 $ hg log -Ra -r0 -T '{"\\\""}\n'
2946 \"
2946 \"
2947 $ hg log -Ra -r0 -T '{r"\""}\n'
2947 $ hg log -Ra -r0 -T '{r"\""}\n'
2948 \"
2948 \"
2949 $ hg log -Ra -r0 -T '{r"\\\""}\n'
2949 $ hg log -Ra -r0 -T '{r"\\\""}\n'
2950 \\\"
2950 \\\"
2951
2951
2952
2952
2953 $ hg log -Ra -r0 -T '{"\""}\n'
2953 $ hg log -Ra -r0 -T '{"\""}\n'
2954 "
2954 "
2955 $ hg log -Ra -r0 -T '{"\\\""}\n'
2955 $ hg log -Ra -r0 -T '{"\\\""}\n'
2956 \"
2956 \"
2957 $ hg log -Ra -r0 -T '{r"\""}\n'
2957 $ hg log -Ra -r0 -T '{r"\""}\n'
2958 \"
2958 \"
2959 $ hg log -Ra -r0 -T '{r"\\\""}\n'
2959 $ hg log -Ra -r0 -T '{r"\\\""}\n'
2960 \\\"
2960 \\\"
2961
2961
2962 Test exception in quoted template. single backslash before quotation mark is
2962 Test exception in quoted template. single backslash before quotation mark is
2963 stripped before parsing:
2963 stripped before parsing:
2964
2964
2965 $ cat <<'EOF' > escquotetmpl
2965 $ cat <<'EOF' > escquotetmpl
2966 > changeset = "\" \\" \\\" \\\\" {files % \"{file}\"}\n"
2966 > changeset = "\" \\" \\\" \\\\" {files % \"{file}\"}\n"
2967 > EOF
2967 > EOF
2968 $ cd latesttag
2968 $ cd latesttag
2969 $ hg log -r 2 --style ../escquotetmpl
2969 $ hg log -r 2 --style ../escquotetmpl
2970 " \" \" \\" head1
2970 " \" \" \\" head1
2971
2971
2972 $ hg log -r 2 -T esc --config templates.esc='"{\"valid\"}\n"'
2972 $ hg log -r 2 -T esc --config templates.esc='"{\"valid\"}\n"'
2973 valid
2973 valid
2974 $ hg log -r 2 -T esc --config templates.esc="'"'{\'"'"'valid\'"'"'}\n'"'"
2974 $ hg log -r 2 -T esc --config templates.esc="'"'{\'"'"'valid\'"'"'}\n'"'"
2975 valid
2975 valid
2976
2976
2977 Test compatibility with 2.9.2-3.4 of escaped quoted strings in nested
2977 Test compatibility with 2.9.2-3.4 of escaped quoted strings in nested
2978 _evalifliteral() templates (issue4733):
2978 _evalifliteral() templates (issue4733):
2979
2979
2980 $ hg log -r 2 -T '{if(rev, "\"{rev}")}\n'
2980 $ hg log -r 2 -T '{if(rev, "\"{rev}")}\n'
2981 "2
2981 "2
2982 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\"{rev}\")}")}\n'
2982 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\"{rev}\")}")}\n'
2983 "2
2983 "2
2984 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\"{rev}\\\")}\")}")}\n'
2984 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\"{rev}\\\")}\")}")}\n'
2985 "2
2985 "2
2986
2986
2987 $ hg log -r 2 -T '{if(rev, "\\\"")}\n'
2987 $ hg log -r 2 -T '{if(rev, "\\\"")}\n'
2988 \"
2988 \"
2989 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\\\\\"\")}")}\n'
2989 $ hg log -r 2 -T '{if(rev, "{if(rev, \"\\\\\\\"\")}")}\n'
2990 \"
2990 \"
2991 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
2991 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, \\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
2992 \"
2992 \"
2993
2993
2994 $ hg log -r 2 -T '{if(rev, r"\\\"")}\n'
2994 $ hg log -r 2 -T '{if(rev, r"\\\"")}\n'
2995 \\\"
2995 \\\"
2996 $ hg log -r 2 -T '{if(rev, "{if(rev, r\"\\\\\\\"\")}")}\n'
2996 $ hg log -r 2 -T '{if(rev, "{if(rev, r\"\\\\\\\"\")}")}\n'
2997 \\\"
2997 \\\"
2998 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, r\\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
2998 $ hg log -r 2 -T '{if(rev, "{if(rev, \"{if(rev, r\\\"\\\\\\\\\\\\\\\"\\\")}\")}")}\n'
2999 \\\"
2999 \\\"
3000
3000
3001 escaped single quotes and errors:
3001 escaped single quotes and errors:
3002
3002
3003 $ hg log -r 2 -T "{if(rev, '{if(rev, \'foo\')}')}"'\n'
3003 $ hg log -r 2 -T "{if(rev, '{if(rev, \'foo\')}')}"'\n'
3004 foo
3004 foo
3005 $ hg log -r 2 -T "{if(rev, '{if(rev, r\'foo\')}')}"'\n'
3005 $ hg log -r 2 -T "{if(rev, '{if(rev, r\'foo\')}')}"'\n'
3006 foo
3006 foo
3007 $ hg log -r 2 -T '{if(rev, "{if(rev, \")}")}\n'
3007 $ hg log -r 2 -T '{if(rev, "{if(rev, \")}")}\n'
3008 hg: parse error at 21: unterminated string
3008 hg: parse error at 21: unterminated string
3009 [255]
3009 [255]
3010 $ hg log -r 2 -T '{if(rev, \"\\"")}\n'
3010 $ hg log -r 2 -T '{if(rev, \"\\"")}\n'
3011 hg: parse error: trailing \ in string
3011 hg: parse error: trailing \ in string
3012 [255]
3012 [255]
3013 $ hg log -r 2 -T '{if(rev, r\"\\"")}\n'
3013 $ hg log -r 2 -T '{if(rev, r\"\\"")}\n'
3014 hg: parse error: trailing \ in string
3014 hg: parse error: trailing \ in string
3015 [255]
3015 [255]
3016
3016
3017 $ cd ..
3017 $ cd ..
3018
3018
3019 Test leading backslashes:
3019 Test leading backslashes:
3020
3020
3021 $ cd latesttag
3021 $ cd latesttag
3022 $ hg log -r 2 -T '\{rev} {files % "\{file}"}\n'
3022 $ hg log -r 2 -T '\{rev} {files % "\{file}"}\n'
3023 {rev} {file}
3023 {rev} {file}
3024 $ hg log -r 2 -T '\\{rev} {files % "\\{file}"}\n'
3024 $ hg log -r 2 -T '\\{rev} {files % "\\{file}"}\n'
3025 \2 \head1
3025 \2 \head1
3026 $ hg log -r 2 -T '\\\{rev} {files % "\\\{file}"}\n'
3026 $ hg log -r 2 -T '\\\{rev} {files % "\\\{file}"}\n'
3027 \{rev} \{file}
3027 \{rev} \{file}
3028 $ cd ..
3028 $ cd ..
3029
3029
3030 Test leading backslashes in "if" expression (issue4714):
3030 Test leading backslashes in "if" expression (issue4714):
3031
3031
3032 $ cd latesttag
3032 $ cd latesttag
3033 $ hg log -r 2 -T '{if("1", "\{rev}")} {if("1", r"\{rev}")}\n'
3033 $ hg log -r 2 -T '{if("1", "\{rev}")} {if("1", r"\{rev}")}\n'
3034 {rev} \{rev}
3034 {rev} \{rev}
3035 $ hg log -r 2 -T '{if("1", "\\{rev}")} {if("1", r"\\{rev}")}\n'
3035 $ hg log -r 2 -T '{if("1", "\\{rev}")} {if("1", r"\\{rev}")}\n'
3036 \2 \\{rev}
3036 \2 \\{rev}
3037 $ hg log -r 2 -T '{if("1", "\\\{rev}")} {if("1", r"\\\{rev}")}\n'
3037 $ hg log -r 2 -T '{if("1", "\\\{rev}")} {if("1", r"\\\{rev}")}\n'
3038 \{rev} \\\{rev}
3038 \{rev} \\\{rev}
3039 $ cd ..
3039 $ cd ..
3040
3040
3041 "string-escape"-ed "\x5c\x786e" becomes r"\x6e" (once) or r"n" (twice)
3041 "string-escape"-ed "\x5c\x786e" becomes r"\x6e" (once) or r"n" (twice)
3042
3042
3043 $ hg log -R a -r 0 --template '{if("1", "\x5c\x786e", "NG")}\n'
3043 $ hg log -R a -r 0 --template '{if("1", "\x5c\x786e", "NG")}\n'
3044 \x6e
3044 \x6e
3045 $ hg log -R a -r 0 --template '{if("1", r"\x5c\x786e", "NG")}\n'
3045 $ hg log -R a -r 0 --template '{if("1", r"\x5c\x786e", "NG")}\n'
3046 \x5c\x786e
3046 \x5c\x786e
3047 $ hg log -R a -r 0 --template '{if("", "NG", "\x5c\x786e")}\n'
3047 $ hg log -R a -r 0 --template '{if("", "NG", "\x5c\x786e")}\n'
3048 \x6e
3048 \x6e
3049 $ hg log -R a -r 0 --template '{if("", "NG", r"\x5c\x786e")}\n'
3049 $ hg log -R a -r 0 --template '{if("", "NG", r"\x5c\x786e")}\n'
3050 \x5c\x786e
3050 \x5c\x786e
3051
3051
3052 $ hg log -R a -r 2 --template '{ifeq("no perso\x6e", desc, "\x5c\x786e", "NG")}\n'
3052 $ hg log -R a -r 2 --template '{ifeq("no perso\x6e", desc, "\x5c\x786e", "NG")}\n'
3053 \x6e
3053 \x6e
3054 $ hg log -R a -r 2 --template '{ifeq(r"no perso\x6e", desc, "NG", r"\x5c\x786e")}\n'
3054 $ hg log -R a -r 2 --template '{ifeq(r"no perso\x6e", desc, "NG", r"\x5c\x786e")}\n'
3055 \x5c\x786e
3055 \x5c\x786e
3056 $ hg log -R a -r 2 --template '{ifeq(desc, "no perso\x6e", "\x5c\x786e", "NG")}\n'
3056 $ hg log -R a -r 2 --template '{ifeq(desc, "no perso\x6e", "\x5c\x786e", "NG")}\n'
3057 \x6e
3057 \x6e
3058 $ hg log -R a -r 2 --template '{ifeq(desc, r"no perso\x6e", "NG", r"\x5c\x786e")}\n'
3058 $ hg log -R a -r 2 --template '{ifeq(desc, r"no perso\x6e", "NG", r"\x5c\x786e")}\n'
3059 \x5c\x786e
3059 \x5c\x786e
3060
3060
3061 $ hg log -R a -r 8 --template '{join(files, "\n")}\n'
3061 $ hg log -R a -r 8 --template '{join(files, "\n")}\n'
3062 fourth
3062 fourth
3063 second
3063 second
3064 third
3064 third
3065 $ hg log -R a -r 8 --template '{join(files, r"\n")}\n'
3065 $ hg log -R a -r 8 --template '{join(files, r"\n")}\n'
3066 fourth\nsecond\nthird
3066 fourth\nsecond\nthird
3067
3067
3068 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", "htm\x6c")}'
3068 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", "htm\x6c")}'
3069 <p>
3069 <p>
3070 1st
3070 1st
3071 </p>
3071 </p>
3072 <p>
3072 <p>
3073 2nd
3073 2nd
3074 </p>
3074 </p>
3075 $ hg log -R a -r 2 --template '{rstdoc(r"1st\n\n2nd", "html")}'
3075 $ hg log -R a -r 2 --template '{rstdoc(r"1st\n\n2nd", "html")}'
3076 <p>
3076 <p>
3077 1st\n\n2nd
3077 1st\n\n2nd
3078 </p>
3078 </p>
3079 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", r"htm\x6c")}'
3079 $ hg log -R a -r 2 --template '{rstdoc("1st\n\n2nd", r"htm\x6c")}'
3080 1st
3080 1st
3081
3081
3082 2nd
3082 2nd
3083
3083
3084 $ hg log -R a -r 2 --template '{strip(desc, "\x6e")}\n'
3084 $ hg log -R a -r 2 --template '{strip(desc, "\x6e")}\n'
3085 o perso
3085 o perso
3086 $ hg log -R a -r 2 --template '{strip(desc, r"\x6e")}\n'
3086 $ hg log -R a -r 2 --template '{strip(desc, r"\x6e")}\n'
3087 no person
3087 no person
3088 $ hg log -R a -r 2 --template '{strip("no perso\x6e", "\x6e")}\n'
3088 $ hg log -R a -r 2 --template '{strip("no perso\x6e", "\x6e")}\n'
3089 o perso
3089 o perso
3090 $ hg log -R a -r 2 --template '{strip(r"no perso\x6e", r"\x6e")}\n'
3090 $ hg log -R a -r 2 --template '{strip(r"no perso\x6e", r"\x6e")}\n'
3091 no perso
3091 no perso
3092
3092
3093 $ hg log -R a -r 2 --template '{sub("\\x6e", "\x2d", desc)}\n'
3093 $ hg log -R a -r 2 --template '{sub("\\x6e", "\x2d", desc)}\n'
3094 -o perso-
3094 -o perso-
3095 $ hg log -R a -r 2 --template '{sub(r"\\x6e", "-", desc)}\n'
3095 $ hg log -R a -r 2 --template '{sub(r"\\x6e", "-", desc)}\n'
3096 no person
3096 no person
3097 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", desc)}\n'
3097 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", desc)}\n'
3098 \x2do perso\x2d
3098 \x2do perso\x2d
3099 $ hg log -R a -r 2 --template '{sub("n", "\x2d", "no perso\x6e")}\n'
3099 $ hg log -R a -r 2 --template '{sub("n", "\x2d", "no perso\x6e")}\n'
3100 -o perso-
3100 -o perso-
3101 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", r"no perso\x6e")}\n'
3101 $ hg log -R a -r 2 --template '{sub("n", r"\x2d", r"no perso\x6e")}\n'
3102 \x2do perso\x6e
3102 \x2do perso\x6e
3103
3103
3104 $ hg log -R a -r 8 --template '{files % "{file}\n"}'
3104 $ hg log -R a -r 8 --template '{files % "{file}\n"}'
3105 fourth
3105 fourth
3106 second
3106 second
3107 third
3107 third
3108
3108
3109 Test string escaping in nested expression:
3109 Test string escaping in nested expression:
3110
3110
3111 $ hg log -R a -r 8 --template '{ifeq(r"\x6e", if("1", "\x5c\x786e"), join(files, "\x5c\x786e"))}\n'
3111 $ hg log -R a -r 8 --template '{ifeq(r"\x6e", if("1", "\x5c\x786e"), join(files, "\x5c\x786e"))}\n'
3112 fourth\x6esecond\x6ethird
3112 fourth\x6esecond\x6ethird
3113 $ hg log -R a -r 8 --template '{ifeq(if("1", r"\x6e"), "\x5c\x786e", join(files, "\x5c\x786e"))}\n'
3113 $ hg log -R a -r 8 --template '{ifeq(if("1", r"\x6e"), "\x5c\x786e", join(files, "\x5c\x786e"))}\n'
3114 fourth\x6esecond\x6ethird
3114 fourth\x6esecond\x6ethird
3115
3115
3116 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", "\x5c\x786e"))}\n'
3116 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", "\x5c\x786e"))}\n'
3117 fourth\x6esecond\x6ethird
3117 fourth\x6esecond\x6ethird
3118 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", r"\x5c\x786e"))}\n'
3118 $ hg log -R a -r 8 --template '{join(files, ifeq(branch, "default", r"\x5c\x786e"))}\n'
3119 fourth\x5c\x786esecond\x5c\x786ethird
3119 fourth\x5c\x786esecond\x5c\x786ethird
3120
3120
3121 $ hg log -R a -r 3:4 --template '{rev}:{sub(if("1", "\x6e"), ifeq(branch, "foo", r"\x5c\x786e", "\x5c\x786e"), desc)}\n'
3121 $ hg log -R a -r 3:4 --template '{rev}:{sub(if("1", "\x6e"), ifeq(branch, "foo", r"\x5c\x786e", "\x5c\x786e"), desc)}\n'
3122 3:\x6eo user, \x6eo domai\x6e
3122 3:\x6eo user, \x6eo domai\x6e
3123 4:\x5c\x786eew bra\x5c\x786ech
3123 4:\x5c\x786eew bra\x5c\x786ech
3124
3124
3125 Test quotes in nested expression are evaluated just like a $(command)
3125 Test quotes in nested expression are evaluated just like a $(command)
3126 substitution in POSIX shells:
3126 substitution in POSIX shells:
3127
3127
3128 $ hg log -R a -r 8 -T '{"{"{rev}:{node|short}"}"}\n'
3128 $ hg log -R a -r 8 -T '{"{"{rev}:{node|short}"}"}\n'
3129 8:95c24699272e
3129 8:95c24699272e
3130 $ hg log -R a -r 8 -T '{"{"\{{rev}} \"{node|short}\""}"}\n'
3130 $ hg log -R a -r 8 -T '{"{"\{{rev}} \"{node|short}\""}"}\n'
3131 {8} "95c24699272e"
3131 {8} "95c24699272e"
3132
3132
3133 Test recursive evaluation:
3133 Test recursive evaluation:
3134
3134
3135 $ hg init r
3135 $ hg init r
3136 $ cd r
3136 $ cd r
3137 $ echo a > a
3137 $ echo a > a
3138 $ hg ci -Am '{rev}'
3138 $ hg ci -Am '{rev}'
3139 adding a
3139 adding a
3140 $ hg log -r 0 --template '{if(rev, desc)}\n'
3140 $ hg log -r 0 --template '{if(rev, desc)}\n'
3141 {rev}
3141 {rev}
3142 $ hg log -r 0 --template '{if(rev, "{author} {rev}")}\n'
3142 $ hg log -r 0 --template '{if(rev, "{author} {rev}")}\n'
3143 test 0
3143 test 0
3144
3144
3145 $ hg branch -q 'text.{rev}'
3145 $ hg branch -q 'text.{rev}'
3146 $ echo aa >> aa
3146 $ echo aa >> aa
3147 $ hg ci -u '{node|short}' -m 'desc to be wrapped desc to be wrapped'
3147 $ hg ci -u '{node|short}' -m 'desc to be wrapped desc to be wrapped'
3148
3148
3149 $ hg log -l1 --template '{fill(desc, "20", author, branch)}'
3149 $ hg log -l1 --template '{fill(desc, "20", author, branch)}'
3150 {node|short}desc to
3150 {node|short}desc to
3151 text.{rev}be wrapped
3151 text.{rev}be wrapped
3152 text.{rev}desc to be
3152 text.{rev}desc to be
3153 text.{rev}wrapped (no-eol)
3153 text.{rev}wrapped (no-eol)
3154 $ hg log -l1 --template '{fill(desc, "20", "{node|short}:", "text.{rev}:")}'
3154 $ hg log -l1 --template '{fill(desc, "20", "{node|short}:", "text.{rev}:")}'
3155 bcc7ff960b8e:desc to
3155 bcc7ff960b8e:desc to
3156 text.1:be wrapped
3156 text.1:be wrapped
3157 text.1:desc to be
3157 text.1:desc to be
3158 text.1:wrapped (no-eol)
3158 text.1:wrapped (no-eol)
3159 $ hg log -l1 -T '{fill(desc, date, "", "")}\n'
3159 $ hg log -l1 -T '{fill(desc, date, "", "")}\n'
3160 hg: parse error: fill expects an integer width
3160 hg: parse error: fill expects an integer width
3161 [255]
3161 [255]
3162
3162
3163 $ hg log -l 1 --template '{sub(r"[0-9]", "-", author)}'
3163 $ hg log -l 1 --template '{sub(r"[0-9]", "-", author)}'
3164 {node|short} (no-eol)
3164 {node|short} (no-eol)
3165 $ hg log -l 1 --template '{sub(r"[0-9]", "-", "{node|short}")}'
3165 $ hg log -l 1 --template '{sub(r"[0-9]", "-", "{node|short}")}'
3166 bcc-ff---b-e (no-eol)
3166 bcc-ff---b-e (no-eol)
3167
3167
3168 $ cat >> .hg/hgrc <<EOF
3168 $ cat >> .hg/hgrc <<EOF
3169 > [extensions]
3169 > [extensions]
3170 > color=
3170 > color=
3171 > [color]
3171 > [color]
3172 > mode=ansi
3172 > mode=ansi
3173 > text.{rev} = red
3173 > text.{rev} = red
3174 > text.1 = green
3174 > text.1 = green
3175 > EOF
3175 > EOF
3176 $ hg log --color=always -l 1 --template '{label(branch, "text\n")}'
3176 $ hg log --color=always -l 1 --template '{label(branch, "text\n")}'
3177 \x1b[0;31mtext\x1b[0m (esc)
3177 \x1b[0;31mtext\x1b[0m (esc)
3178 $ hg log --color=always -l 1 --template '{label("text.{rev}", "text\n")}'
3178 $ hg log --color=always -l 1 --template '{label("text.{rev}", "text\n")}'
3179 \x1b[0;32mtext\x1b[0m (esc)
3179 \x1b[0;32mtext\x1b[0m (esc)
3180
3180
3181 color effect can be specified without quoting:
3182
3183 $ hg log --color=always -l 1 --template '{label(red, "text\n")}'
3184 \x1b[0;31mtext\x1b[0m (esc)
3185
3181 Test branches inside if statement:
3186 Test branches inside if statement:
3182
3187
3183 $ hg log -r 0 --template '{if(branches, "yes", "no")}\n'
3188 $ hg log -r 0 --template '{if(branches, "yes", "no")}\n'
3184 no
3189 no
3185
3190
3186 Test get function:
3191 Test get function:
3187
3192
3188 $ hg log -r 0 --template '{get(extras, "branch")}\n'
3193 $ hg log -r 0 --template '{get(extras, "branch")}\n'
3189 default
3194 default
3190 $ hg log -r 0 --template '{get(extras, "br{"anch"}")}\n'
3195 $ hg log -r 0 --template '{get(extras, "br{"anch"}")}\n'
3191 default
3196 default
3192 $ hg log -r 0 --template '{get(files, "should_fail")}\n'
3197 $ hg log -r 0 --template '{get(files, "should_fail")}\n'
3193 hg: parse error: get() expects a dict as first argument
3198 hg: parse error: get() expects a dict as first argument
3194 [255]
3199 [255]
3195
3200
3196 Test localdate(date, tz) function:
3201 Test localdate(date, tz) function:
3197
3202
3198 $ TZ=JST-09 hg log -r0 -T '{date|localdate|isodate}\n'
3203 $ TZ=JST-09 hg log -r0 -T '{date|localdate|isodate}\n'
3199 1970-01-01 09:00 +0900
3204 1970-01-01 09:00 +0900
3200 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "UTC")|isodate}\n'
3205 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "UTC")|isodate}\n'
3201 1970-01-01 00:00 +0000
3206 1970-01-01 00:00 +0000
3202 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "+0200")|isodate}\n'
3207 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "+0200")|isodate}\n'
3203 1970-01-01 02:00 +0200
3208 1970-01-01 02:00 +0200
3204 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "0")|isodate}\n'
3209 $ TZ=JST-09 hg log -r0 -T '{localdate(date, "0")|isodate}\n'
3205 1970-01-01 00:00 +0000
3210 1970-01-01 00:00 +0000
3206 $ TZ=JST-09 hg log -r0 -T '{localdate(date, 0)|isodate}\n'
3211 $ TZ=JST-09 hg log -r0 -T '{localdate(date, 0)|isodate}\n'
3207 1970-01-01 00:00 +0000
3212 1970-01-01 00:00 +0000
3208 $ hg log -r0 -T '{localdate(date, "invalid")|isodate}\n'
3213 $ hg log -r0 -T '{localdate(date, "invalid")|isodate}\n'
3209 hg: parse error: localdate expects a timezone
3214 hg: parse error: localdate expects a timezone
3210 [255]
3215 [255]
3211 $ hg log -r0 -T '{localdate(date, date)|isodate}\n'
3216 $ hg log -r0 -T '{localdate(date, date)|isodate}\n'
3212 hg: parse error: localdate expects a timezone
3217 hg: parse error: localdate expects a timezone
3213 [255]
3218 [255]
3214
3219
3215 Test shortest(node) function:
3220 Test shortest(node) function:
3216
3221
3217 $ echo b > b
3222 $ echo b > b
3218 $ hg ci -qAm b
3223 $ hg ci -qAm b
3219 $ hg log --template '{shortest(node)}\n'
3224 $ hg log --template '{shortest(node)}\n'
3220 e777
3225 e777
3221 bcc7
3226 bcc7
3222 f776
3227 f776
3223 $ hg log --template '{shortest(node, 10)}\n'
3228 $ hg log --template '{shortest(node, 10)}\n'
3224 e777603221
3229 e777603221
3225 bcc7ff960b
3230 bcc7ff960b
3226 f7769ec2ab
3231 f7769ec2ab
3227 $ hg log --template '{node|shortest}\n' -l1
3232 $ hg log --template '{node|shortest}\n' -l1
3228 e777
3233 e777
3229
3234
3230 $ hg log -r 0 -T '{shortest(node, "1{"0"}")}\n'
3235 $ hg log -r 0 -T '{shortest(node, "1{"0"}")}\n'
3231 f7769ec2ab
3236 f7769ec2ab
3232 $ hg log -r 0 -T '{shortest(node, "not an int")}\n'
3237 $ hg log -r 0 -T '{shortest(node, "not an int")}\n'
3233 hg: parse error: shortest() expects an integer minlength
3238 hg: parse error: shortest() expects an integer minlength
3234 [255]
3239 [255]
3235
3240
3236 Test pad function
3241 Test pad function
3237
3242
3238 $ hg log --template '{pad(rev, 20)} {author|user}\n'
3243 $ hg log --template '{pad(rev, 20)} {author|user}\n'
3239 2 test
3244 2 test
3240 1 {node|short}
3245 1 {node|short}
3241 0 test
3246 0 test
3242
3247
3243 $ hg log --template '{pad(rev, 20, " ", True)} {author|user}\n'
3248 $ hg log --template '{pad(rev, 20, " ", True)} {author|user}\n'
3244 2 test
3249 2 test
3245 1 {node|short}
3250 1 {node|short}
3246 0 test
3251 0 test
3247
3252
3248 $ hg log --template '{pad(rev, 20, "-", False)} {author|user}\n'
3253 $ hg log --template '{pad(rev, 20, "-", False)} {author|user}\n'
3249 2------------------- test
3254 2------------------- test
3250 1------------------- {node|short}
3255 1------------------- {node|short}
3251 0------------------- test
3256 0------------------- test
3252
3257
3253 Test template string in pad function
3258 Test template string in pad function
3254
3259
3255 $ hg log -r 0 -T '{pad("\{{rev}}", 10)} {author|user}\n'
3260 $ hg log -r 0 -T '{pad("\{{rev}}", 10)} {author|user}\n'
3256 {0} test
3261 {0} test
3257
3262
3258 $ hg log -r 0 -T '{pad(r"\{rev}", 10)} {author|user}\n'
3263 $ hg log -r 0 -T '{pad(r"\{rev}", 10)} {author|user}\n'
3259 \{rev} test
3264 \{rev} test
3260
3265
3261 Test width argument passed to pad function
3266 Test width argument passed to pad function
3262
3267
3263 $ hg log -r 0 -T '{pad(rev, "1{"0"}")} {author|user}\n'
3268 $ hg log -r 0 -T '{pad(rev, "1{"0"}")} {author|user}\n'
3264 0 test
3269 0 test
3265 $ hg log -r 0 -T '{pad(rev, "not an int")}\n'
3270 $ hg log -r 0 -T '{pad(rev, "not an int")}\n'
3266 hg: parse error: pad() expects an integer width
3271 hg: parse error: pad() expects an integer width
3267 [255]
3272 [255]
3268
3273
3269 Test ifcontains function
3274 Test ifcontains function
3270
3275
3271 $ hg log --template '{rev} {ifcontains(rev, "2 two 0", "is in the string", "is not")}\n'
3276 $ hg log --template '{rev} {ifcontains(rev, "2 two 0", "is in the string", "is not")}\n'
3272 2 is in the string
3277 2 is in the string
3273 1 is not
3278 1 is not
3274 0 is in the string
3279 0 is in the string
3275
3280
3276 $ hg log -T '{rev} {ifcontains(rev, "2 two{" 0"}", "is in the string", "is not")}\n'
3281 $ hg log -T '{rev} {ifcontains(rev, "2 two{" 0"}", "is in the string", "is not")}\n'
3277 2 is in the string
3282 2 is in the string
3278 1 is not
3283 1 is not
3279 0 is in the string
3284 0 is in the string
3280
3285
3281 $ hg log --template '{rev} {ifcontains("a", file_adds, "added a", "did not add a")}\n'
3286 $ hg log --template '{rev} {ifcontains("a", file_adds, "added a", "did not add a")}\n'
3282 2 did not add a
3287 2 did not add a
3283 1 did not add a
3288 1 did not add a
3284 0 added a
3289 0 added a
3285
3290
3286 $ hg log --debug -T '{rev}{ifcontains(1, parents, " is parent of 1")}\n'
3291 $ hg log --debug -T '{rev}{ifcontains(1, parents, " is parent of 1")}\n'
3287 2 is parent of 1
3292 2 is parent of 1
3288 1
3293 1
3289 0
3294 0
3290
3295
3291 Test revset function
3296 Test revset function
3292
3297
3293 $ hg log --template '{rev} {ifcontains(rev, revset("."), "current rev", "not current rev")}\n'
3298 $ hg log --template '{rev} {ifcontains(rev, revset("."), "current rev", "not current rev")}\n'
3294 2 current rev
3299 2 current rev
3295 1 not current rev
3300 1 not current rev
3296 0 not current rev
3301 0 not current rev
3297
3302
3298 $ hg log --template '{rev} {ifcontains(rev, revset(". + .^"), "match rev", "not match rev")}\n'
3303 $ hg log --template '{rev} {ifcontains(rev, revset(". + .^"), "match rev", "not match rev")}\n'
3299 2 match rev
3304 2 match rev
3300 1 match rev
3305 1 match rev
3301 0 not match rev
3306 0 not match rev
3302
3307
3303 $ hg log --template '{rev} Parents: {revset("parents(%s)", rev)}\n'
3308 $ hg log --template '{rev} Parents: {revset("parents(%s)", rev)}\n'
3304 2 Parents: 1
3309 2 Parents: 1
3305 1 Parents: 0
3310 1 Parents: 0
3306 0 Parents:
3311 0 Parents:
3307
3312
3308 $ cat >> .hg/hgrc <<EOF
3313 $ cat >> .hg/hgrc <<EOF
3309 > [revsetalias]
3314 > [revsetalias]
3310 > myparents(\$1) = parents(\$1)
3315 > myparents(\$1) = parents(\$1)
3311 > EOF
3316 > EOF
3312 $ hg log --template '{rev} Parents: {revset("myparents(%s)", rev)}\n'
3317 $ hg log --template '{rev} Parents: {revset("myparents(%s)", rev)}\n'
3313 2 Parents: 1
3318 2 Parents: 1
3314 1 Parents: 0
3319 1 Parents: 0
3315 0 Parents:
3320 0 Parents:
3316
3321
3317 $ hg log --template 'Rev: {rev}\n{revset("::%s", rev) % "Ancestor: {revision}\n"}\n'
3322 $ hg log --template 'Rev: {rev}\n{revset("::%s", rev) % "Ancestor: {revision}\n"}\n'
3318 Rev: 2
3323 Rev: 2
3319 Ancestor: 0
3324 Ancestor: 0
3320 Ancestor: 1
3325 Ancestor: 1
3321 Ancestor: 2
3326 Ancestor: 2
3322
3327
3323 Rev: 1
3328 Rev: 1
3324 Ancestor: 0
3329 Ancestor: 0
3325 Ancestor: 1
3330 Ancestor: 1
3326
3331
3327 Rev: 0
3332 Rev: 0
3328 Ancestor: 0
3333 Ancestor: 0
3329
3334
3330 $ hg log --template '{revset("TIP"|lower)}\n' -l1
3335 $ hg log --template '{revset("TIP"|lower)}\n' -l1
3331 2
3336 2
3332
3337
3333 $ hg log -T '{revset("%s", "t{"ip"}")}\n' -l1
3338 $ hg log -T '{revset("%s", "t{"ip"}")}\n' -l1
3334 2
3339 2
3335
3340
3336 a list template is evaluated for each item of revset/parents
3341 a list template is evaluated for each item of revset/parents
3337
3342
3338 $ hg log -T '{rev} p: {revset("p1(%s)", rev) % "{rev}:{node|short}"}\n'
3343 $ hg log -T '{rev} p: {revset("p1(%s)", rev) % "{rev}:{node|short}"}\n'
3339 2 p: 1:bcc7ff960b8e
3344 2 p: 1:bcc7ff960b8e
3340 1 p: 0:f7769ec2ab97
3345 1 p: 0:f7769ec2ab97
3341 0 p:
3346 0 p:
3342
3347
3343 $ hg log --debug -T '{rev} p:{parents % " {rev}:{node|short}"}\n'
3348 $ hg log --debug -T '{rev} p:{parents % " {rev}:{node|short}"}\n'
3344 2 p: 1:bcc7ff960b8e -1:000000000000
3349 2 p: 1:bcc7ff960b8e -1:000000000000
3345 1 p: 0:f7769ec2ab97 -1:000000000000
3350 1 p: 0:f7769ec2ab97 -1:000000000000
3346 0 p: -1:000000000000 -1:000000000000
3351 0 p: -1:000000000000 -1:000000000000
3347
3352
3348 therefore, 'revcache' should be recreated for each rev
3353 therefore, 'revcache' should be recreated for each rev
3349
3354
3350 $ hg log -T '{rev} {file_adds}\np {revset("p1(%s)", rev) % "{file_adds}"}\n'
3355 $ hg log -T '{rev} {file_adds}\np {revset("p1(%s)", rev) % "{file_adds}"}\n'
3351 2 aa b
3356 2 aa b
3352 p
3357 p
3353 1
3358 1
3354 p a
3359 p a
3355 0 a
3360 0 a
3356 p
3361 p
3357
3362
3358 $ hg log --debug -T '{rev} {file_adds}\np {parents % "{file_adds}"}\n'
3363 $ hg log --debug -T '{rev} {file_adds}\np {parents % "{file_adds}"}\n'
3359 2 aa b
3364 2 aa b
3360 p
3365 p
3361 1
3366 1
3362 p a
3367 p a
3363 0 a
3368 0 a
3364 p
3369 p
3365
3370
3366 a revset item must be evaluated as an integer revision, not an offset from tip
3371 a revset item must be evaluated as an integer revision, not an offset from tip
3367
3372
3368 $ hg log -l 1 -T '{revset("null") % "{rev}:{node|short}"}\n'
3373 $ hg log -l 1 -T '{revset("null") % "{rev}:{node|short}"}\n'
3369 -1:000000000000
3374 -1:000000000000
3370 $ hg log -l 1 -T '{revset("%s", "null") % "{rev}:{node|short}"}\n'
3375 $ hg log -l 1 -T '{revset("%s", "null") % "{rev}:{node|short}"}\n'
3371 -1:000000000000
3376 -1:000000000000
3372
3377
3373 Test active bookmark templating
3378 Test active bookmark templating
3374
3379
3375 $ hg book foo
3380 $ hg book foo
3376 $ hg book bar
3381 $ hg book bar
3377 $ hg log --template "{rev} {bookmarks % '{bookmark}{ifeq(bookmark, active, \"*\")} '}\n"
3382 $ hg log --template "{rev} {bookmarks % '{bookmark}{ifeq(bookmark, active, \"*\")} '}\n"
3378 2 bar* foo
3383 2 bar* foo
3379 1
3384 1
3380 0
3385 0
3381 $ hg log --template "{rev} {activebookmark}\n"
3386 $ hg log --template "{rev} {activebookmark}\n"
3382 2 bar
3387 2 bar
3383 1
3388 1
3384 0
3389 0
3385 $ hg bookmarks --inactive bar
3390 $ hg bookmarks --inactive bar
3386 $ hg log --template "{rev} {activebookmark}\n"
3391 $ hg log --template "{rev} {activebookmark}\n"
3387 2
3392 2
3388 1
3393 1
3389 0
3394 0
3390 $ hg book -r1 baz
3395 $ hg book -r1 baz
3391 $ hg log --template "{rev} {join(bookmarks, ' ')}\n"
3396 $ hg log --template "{rev} {join(bookmarks, ' ')}\n"
3392 2 bar foo
3397 2 bar foo
3393 1 baz
3398 1 baz
3394 0
3399 0
3395 $ hg log --template "{rev} {ifcontains('foo', bookmarks, 't', 'f')}\n"
3400 $ hg log --template "{rev} {ifcontains('foo', bookmarks, 't', 'f')}\n"
3396 2 t
3401 2 t
3397 1 f
3402 1 f
3398 0 f
3403 0 f
3399
3404
3400 Test namespaces dict
3405 Test namespaces dict
3401
3406
3402 $ hg log -T '{rev}{namespaces % " {namespace}={join(names, ",")}"}\n'
3407 $ hg log -T '{rev}{namespaces % " {namespace}={join(names, ",")}"}\n'
3403 2 bookmarks=bar,foo tags=tip branches=text.{rev}
3408 2 bookmarks=bar,foo tags=tip branches=text.{rev}
3404 1 bookmarks=baz tags= branches=text.{rev}
3409 1 bookmarks=baz tags= branches=text.{rev}
3405 0 bookmarks= tags= branches=default
3410 0 bookmarks= tags= branches=default
3406 $ hg log -r2 -T '{namespaces % "{namespace}: {names}\n"}'
3411 $ hg log -r2 -T '{namespaces % "{namespace}: {names}\n"}'
3407 bookmarks: bar foo
3412 bookmarks: bar foo
3408 tags: tip
3413 tags: tip
3409 branches: text.{rev}
3414 branches: text.{rev}
3410 $ hg log -r2 -T '{namespaces % "{namespace}:\n{names % " {name}\n"}"}'
3415 $ hg log -r2 -T '{namespaces % "{namespace}:\n{names % " {name}\n"}"}'
3411 bookmarks:
3416 bookmarks:
3412 bar
3417 bar
3413 foo
3418 foo
3414 tags:
3419 tags:
3415 tip
3420 tip
3416 branches:
3421 branches:
3417 text.{rev}
3422 text.{rev}
3418 $ hg log -r2 -T '{get(namespaces, "bookmarks") % "{name}\n"}'
3423 $ hg log -r2 -T '{get(namespaces, "bookmarks") % "{name}\n"}'
3419 bar
3424 bar
3420 foo
3425 foo
3421
3426
3422 Test stringify on sub expressions
3427 Test stringify on sub expressions
3423
3428
3424 $ cd ..
3429 $ cd ..
3425 $ hg log -R a -r 8 --template '{join(files, if("1", if("1", ", ")))}\n'
3430 $ hg log -R a -r 8 --template '{join(files, if("1", if("1", ", ")))}\n'
3426 fourth, second, third
3431 fourth, second, third
3427 $ hg log -R a -r 8 --template '{strip(if("1", if("1", "-abc-")), if("1", if("1", "-")))}\n'
3432 $ hg log -R a -r 8 --template '{strip(if("1", if("1", "-abc-")), if("1", if("1", "-")))}\n'
3428 abc
3433 abc
3429
3434
3430 Test splitlines
3435 Test splitlines
3431
3436
3432 $ hg log -Gv -R a --template "{splitlines(desc) % 'foo {line}\n'}"
3437 $ hg log -Gv -R a --template "{splitlines(desc) % 'foo {line}\n'}"
3433 @ foo Modify, add, remove, rename
3438 @ foo Modify, add, remove, rename
3434 |
3439 |
3435 o foo future
3440 o foo future
3436 |
3441 |
3437 o foo third
3442 o foo third
3438 |
3443 |
3439 o foo second
3444 o foo second
3440
3445
3441 o foo merge
3446 o foo merge
3442 |\
3447 |\
3443 | o foo new head
3448 | o foo new head
3444 | |
3449 | |
3445 o | foo new branch
3450 o | foo new branch
3446 |/
3451 |/
3447 o foo no user, no domain
3452 o foo no user, no domain
3448 |
3453 |
3449 o foo no person
3454 o foo no person
3450 |
3455 |
3451 o foo other 1
3456 o foo other 1
3452 | foo other 2
3457 | foo other 2
3453 | foo
3458 | foo
3454 | foo other 3
3459 | foo other 3
3455 o foo line 1
3460 o foo line 1
3456 foo line 2
3461 foo line 2
3457
3462
3458 Test startswith
3463 Test startswith
3459 $ hg log -Gv -R a --template "{startswith(desc)}"
3464 $ hg log -Gv -R a --template "{startswith(desc)}"
3460 hg: parse error: startswith expects two arguments
3465 hg: parse error: startswith expects two arguments
3461 [255]
3466 [255]
3462
3467
3463 $ hg log -Gv -R a --template "{startswith('line', desc)}"
3468 $ hg log -Gv -R a --template "{startswith('line', desc)}"
3464 @
3469 @
3465 |
3470 |
3466 o
3471 o
3467 |
3472 |
3468 o
3473 o
3469 |
3474 |
3470 o
3475 o
3471
3476
3472 o
3477 o
3473 |\
3478 |\
3474 | o
3479 | o
3475 | |
3480 | |
3476 o |
3481 o |
3477 |/
3482 |/
3478 o
3483 o
3479 |
3484 |
3480 o
3485 o
3481 |
3486 |
3482 o
3487 o
3483 |
3488 |
3484 o line 1
3489 o line 1
3485 line 2
3490 line 2
3486
3491
3487 Test bad template with better error message
3492 Test bad template with better error message
3488
3493
3489 $ hg log -Gv -R a --template '{desc|user()}'
3494 $ hg log -Gv -R a --template '{desc|user()}'
3490 hg: parse error: expected a symbol, got 'func'
3495 hg: parse error: expected a symbol, got 'func'
3491 [255]
3496 [255]
3492
3497
3493 Test word function (including index out of bounds graceful failure)
3498 Test word function (including index out of bounds graceful failure)
3494
3499
3495 $ hg log -Gv -R a --template "{word('1', desc)}"
3500 $ hg log -Gv -R a --template "{word('1', desc)}"
3496 @ add,
3501 @ add,
3497 |
3502 |
3498 o
3503 o
3499 |
3504 |
3500 o
3505 o
3501 |
3506 |
3502 o
3507 o
3503
3508
3504 o
3509 o
3505 |\
3510 |\
3506 | o head
3511 | o head
3507 | |
3512 | |
3508 o | branch
3513 o | branch
3509 |/
3514 |/
3510 o user,
3515 o user,
3511 |
3516 |
3512 o person
3517 o person
3513 |
3518 |
3514 o 1
3519 o 1
3515 |
3520 |
3516 o 1
3521 o 1
3517
3522
3518
3523
3519 Test word third parameter used as splitter
3524 Test word third parameter used as splitter
3520
3525
3521 $ hg log -Gv -R a --template "{word('0', desc, 'o')}"
3526 $ hg log -Gv -R a --template "{word('0', desc, 'o')}"
3522 @ M
3527 @ M
3523 |
3528 |
3524 o future
3529 o future
3525 |
3530 |
3526 o third
3531 o third
3527 |
3532 |
3528 o sec
3533 o sec
3529
3534
3530 o merge
3535 o merge
3531 |\
3536 |\
3532 | o new head
3537 | o new head
3533 | |
3538 | |
3534 o | new branch
3539 o | new branch
3535 |/
3540 |/
3536 o n
3541 o n
3537 |
3542 |
3538 o n
3543 o n
3539 |
3544 |
3540 o
3545 o
3541 |
3546 |
3542 o line 1
3547 o line 1
3543 line 2
3548 line 2
3544
3549
3545 Test word error messages for not enough and too many arguments
3550 Test word error messages for not enough and too many arguments
3546
3551
3547 $ hg log -Gv -R a --template "{word('0')}"
3552 $ hg log -Gv -R a --template "{word('0')}"
3548 hg: parse error: word expects two or three arguments, got 1
3553 hg: parse error: word expects two or three arguments, got 1
3549 [255]
3554 [255]
3550
3555
3551 $ hg log -Gv -R a --template "{word('0', desc, 'o', 'h', 'b', 'o', 'y')}"
3556 $ hg log -Gv -R a --template "{word('0', desc, 'o', 'h', 'b', 'o', 'y')}"
3552 hg: parse error: word expects two or three arguments, got 7
3557 hg: parse error: word expects two or three arguments, got 7
3553 [255]
3558 [255]
3554
3559
3555 Test word for integer literal
3560 Test word for integer literal
3556
3561
3557 $ hg log -R a --template "{word(2, desc)}\n" -r0
3562 $ hg log -R a --template "{word(2, desc)}\n" -r0
3558 line
3563 line
3559
3564
3560 Test word for invalid numbers
3565 Test word for invalid numbers
3561
3566
3562 $ hg log -Gv -R a --template "{word('a', desc)}"
3567 $ hg log -Gv -R a --template "{word('a', desc)}"
3563 hg: parse error: word expects an integer index
3568 hg: parse error: word expects an integer index
3564 [255]
3569 [255]
3565
3570
3566 Test word for out of range
3571 Test word for out of range
3567
3572
3568 $ hg log -R a --template "{word(10000, desc)}"
3573 $ hg log -R a --template "{word(10000, desc)}"
3569 $ hg log -R a --template "{word(-10000, desc)}"
3574 $ hg log -R a --template "{word(-10000, desc)}"
3570
3575
3571 Test indent and not adding to empty lines
3576 Test indent and not adding to empty lines
3572
3577
3573 $ hg log -T "-----\n{indent(desc, '>> ', ' > ')}\n" -r 0:1 -R a
3578 $ hg log -T "-----\n{indent(desc, '>> ', ' > ')}\n" -r 0:1 -R a
3574 -----
3579 -----
3575 > line 1
3580 > line 1
3576 >> line 2
3581 >> line 2
3577 -----
3582 -----
3578 > other 1
3583 > other 1
3579 >> other 2
3584 >> other 2
3580
3585
3581 >> other 3
3586 >> other 3
3582
3587
3583 Test with non-strings like dates
3588 Test with non-strings like dates
3584
3589
3585 $ hg log -T "{indent(date, ' ')}\n" -r 2:3 -R a
3590 $ hg log -T "{indent(date, ' ')}\n" -r 2:3 -R a
3586 1200000.00
3591 1200000.00
3587 1300000.00
3592 1300000.00
3588
3593
3589 Test broken string escapes:
3594 Test broken string escapes:
3590
3595
3591 $ hg log -T "bogus\\" -R a
3596 $ hg log -T "bogus\\" -R a
3592 hg: parse error: trailing \ in string
3597 hg: parse error: trailing \ in string
3593 [255]
3598 [255]
3594 $ hg log -T "\\xy" -R a
3599 $ hg log -T "\\xy" -R a
3595 hg: parse error: invalid \x escape
3600 hg: parse error: invalid \x escape
3596 [255]
3601 [255]
3597
3602
3598 json filter should escape HTML tags so that the output can be embedded in hgweb:
3603 json filter should escape HTML tags so that the output can be embedded in hgweb:
3599
3604
3600 $ hg log -T "{'<foo@example.org>'|json}\n" -R a -l1
3605 $ hg log -T "{'<foo@example.org>'|json}\n" -R a -l1
3601 "\u003cfoo@example.org\u003e"
3606 "\u003cfoo@example.org\u003e"
3602
3607
3603 Set up repository for non-ascii encoding tests:
3608 Set up repository for non-ascii encoding tests:
3604
3609
3605 $ hg init nonascii
3610 $ hg init nonascii
3606 $ cd nonascii
3611 $ cd nonascii
3607 $ python <<EOF
3612 $ python <<EOF
3608 > open('latin1', 'w').write('\xe9')
3613 > open('latin1', 'w').write('\xe9')
3609 > open('utf-8', 'w').write('\xc3\xa9')
3614 > open('utf-8', 'w').write('\xc3\xa9')
3610 > EOF
3615 > EOF
3611 $ HGENCODING=utf-8 hg branch -q `cat utf-8`
3616 $ HGENCODING=utf-8 hg branch -q `cat utf-8`
3612 $ HGENCODING=utf-8 hg ci -qAm "non-ascii branch: `cat utf-8`" utf-8
3617 $ HGENCODING=utf-8 hg ci -qAm "non-ascii branch: `cat utf-8`" utf-8
3613
3618
3614 json filter should try round-trip conversion to utf-8:
3619 json filter should try round-trip conversion to utf-8:
3615
3620
3616 $ HGENCODING=ascii hg log -T "{branch|json}\n" -r0
3621 $ HGENCODING=ascii hg log -T "{branch|json}\n" -r0
3617 "\u00e9"
3622 "\u00e9"
3618 $ HGENCODING=ascii hg log -T "{desc|json}\n" -r0
3623 $ HGENCODING=ascii hg log -T "{desc|json}\n" -r0
3619 "non-ascii branch: \u00e9"
3624 "non-ascii branch: \u00e9"
3620
3625
3621 json filter takes input as utf-8b:
3626 json filter takes input as utf-8b:
3622
3627
3623 $ HGENCODING=ascii hg log -T "{'`cat utf-8`'|json}\n" -l1
3628 $ HGENCODING=ascii hg log -T "{'`cat utf-8`'|json}\n" -l1
3624 "\u00e9"
3629 "\u00e9"
3625 $ HGENCODING=ascii hg log -T "{'`cat latin1`'|json}\n" -l1
3630 $ HGENCODING=ascii hg log -T "{'`cat latin1`'|json}\n" -l1
3626 "\udce9"
3631 "\udce9"
3627
3632
3628 utf8 filter:
3633 utf8 filter:
3629
3634
3630 $ HGENCODING=ascii hg log -T "round-trip: {branch|utf8|hex}\n" -r0
3635 $ HGENCODING=ascii hg log -T "round-trip: {branch|utf8|hex}\n" -r0
3631 round-trip: c3a9
3636 round-trip: c3a9
3632 $ HGENCODING=latin1 hg log -T "decoded: {'`cat latin1`'|utf8|hex}\n" -l1
3637 $ HGENCODING=latin1 hg log -T "decoded: {'`cat latin1`'|utf8|hex}\n" -l1
3633 decoded: c3a9
3638 decoded: c3a9
3634 $ HGENCODING=ascii hg log -T "replaced: {'`cat latin1`'|utf8|hex}\n" -l1
3639 $ HGENCODING=ascii hg log -T "replaced: {'`cat latin1`'|utf8|hex}\n" -l1
3635 abort: decoding near * (glob)
3640 abort: decoding near * (glob)
3636 [255]
3641 [255]
3637 $ hg log -T "invalid type: {rev|utf8}\n" -r0
3642 $ hg log -T "invalid type: {rev|utf8}\n" -r0
3638 abort: template filter 'utf8' is not compatible with keyword 'rev'
3643 abort: template filter 'utf8' is not compatible with keyword 'rev'
3639 [255]
3644 [255]
3640
3645
3641 $ cd ..
3646 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now