2 # |
2 # |
3 # Copyright 2012 Matt Mackall <mpm@selenic.com> |
3 # Copyright 2012 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 |
|
8 """Generic output formatting for Mercurial |
|
9 |
|
10 The formatter provides API to show data in various ways. The following |
|
11 functions should be used in place of ui.write(): |
|
12 |
|
13 - fm.write() for unconditional output |
|
14 - fm.condwrite() to show some extra data conditionally in plain output |
|
15 - fm.data() to provide extra data to JSON or template output |
|
16 - fm.plain() to show raw text that isn't provided to JSON or template output |
|
17 |
|
18 To show structured data (e.g. date tuples, dicts, lists), apply fm.format*() |
|
19 beforehand so the data is converted to the appropriate data type. Use |
|
20 fm.isplain() if you need to convert or format data conditionally which isn't |
|
21 supported by the formatter API. |
|
22 |
|
23 To build nested structure (i.e. a list of dicts), use fm.nested(). |
|
24 |
|
25 See also https://www.mercurial-scm.org/wiki/GenericTemplatingPlan |
|
26 |
|
27 fm.condwrite() vs 'if cond:': |
|
28 |
|
29 In most cases, use fm.condwrite() so users can selectively show the data |
|
30 in template output. If it's costly to build data, use plain 'if cond:' with |
|
31 fm.write(). |
|
32 |
|
33 fm.nested() vs fm.formatdict() (or fm.formatlist()): |
|
34 |
|
35 fm.nested() should be used to form a tree structure (a list of dicts of |
|
36 lists of dicts...) which can be accessed through template keywords, e.g. |
|
37 "{foo % "{bar % {...}} {baz % {...}}"}". On the other hand, fm.formatdict() |
|
38 exports a dict-type object to template, which can be accessed by e.g. |
|
39 "{get(foo, key)}" function. |
|
40 |
|
41 Doctest helper: |
|
42 |
|
43 >>> def show(fn, verbose=False, **opts): |
|
44 ... import sys |
|
45 ... from . import ui as uimod |
|
46 ... ui = uimod.ui() |
|
47 ... ui.fout = sys.stdout # redirect to doctest |
|
48 ... ui.verbose = verbose |
|
49 ... return fn(ui, ui.formatter(fn.__name__, opts)) |
|
50 |
|
51 Basic example: |
|
52 |
|
53 >>> def files(ui, fm): |
|
54 ... files = [('foo', 123, (0, 0)), ('bar', 456, (1, 0))] |
|
55 ... for f in files: |
|
56 ... fm.startitem() |
|
57 ... fm.write('path', '%s', f[0]) |
|
58 ... fm.condwrite(ui.verbose, 'date', ' %s', |
|
59 ... fm.formatdate(f[2], '%Y-%m-%d %H:%M:%S')) |
|
60 ... fm.data(size=f[1]) |
|
61 ... fm.plain('\\n') |
|
62 ... fm.end() |
|
63 >>> show(files) |
|
64 foo |
|
65 bar |
|
66 >>> show(files, verbose=True) |
|
67 foo 1970-01-01 00:00:00 |
|
68 bar 1970-01-01 00:00:01 |
|
69 >>> show(files, template='json') |
|
70 [ |
|
71 { |
|
72 "date": [0, 0], |
|
73 "path": "foo", |
|
74 "size": 123 |
|
75 }, |
|
76 { |
|
77 "date": [1, 0], |
|
78 "path": "bar", |
|
79 "size": 456 |
|
80 } |
|
81 ] |
|
82 >>> show(files, template='path: {path}\\ndate: {date|rfc3339date}\\n') |
|
83 path: foo |
|
84 date: 1970-01-01T00:00:00+00:00 |
|
85 path: bar |
|
86 date: 1970-01-01T00:00:01+00:00 |
|
87 |
|
88 Nested example: |
|
89 |
|
90 >>> def subrepos(ui, fm): |
|
91 ... fm.startitem() |
|
92 ... fm.write('repo', '[%s]\\n', 'baz') |
|
93 ... files(ui, fm.nested('files')) |
|
94 ... fm.end() |
|
95 >>> show(subrepos) |
|
96 [baz] |
|
97 foo |
|
98 bar |
|
99 >>> show(subrepos, template='{repo}: {join(files % "{path}", ", ")}\\n') |
|
100 baz: foo, bar |
|
101 """ |
7 |
102 |
8 from __future__ import absolute_import |
103 from __future__ import absolute_import |
9 |
104 |
10 import os |
105 import os |
11 |
106 |