|
1 # -*- coding: utf-8 -*- |
|
2 """ |
|
3 pygments.formatters.terminal |
|
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
5 |
|
6 Formatter for terminal output with ANSI sequences. |
|
7 |
|
8 :copyright: Copyright 2006-2009 by the Pygments team, see AUTHORS. |
|
9 :license: BSD, see LICENSE for details. |
|
10 """ |
|
11 |
|
12 from pygments.formatter import Formatter |
|
13 from pygments.token import Keyword, Name, Comment, String, Error, \ |
|
14 Number, Operator, Generic, Token, Whitespace |
|
15 from pygments.console import ansiformat |
|
16 from pygments.util import get_choice_opt |
|
17 |
|
18 |
|
19 __all__ = ['TerminalFormatter'] |
|
20 |
|
21 |
|
22 #: Map token types to a tuple of color values for light and dark |
|
23 #: backgrounds. |
|
24 TERMINAL_COLORS = { |
|
25 Token: ('', ''), |
|
26 |
|
27 Whitespace: ('lightgray', 'darkgray'), |
|
28 Comment: ('lightgray', 'darkgray'), |
|
29 Comment.Preproc: ('teal', 'turquoise'), |
|
30 Keyword: ('darkblue', 'blue'), |
|
31 Keyword.Type: ('teal', 'turquoise'), |
|
32 Operator.Word: ('purple', 'fuchsia'), |
|
33 Name.Builtin: ('teal', 'turquoise'), |
|
34 Name.Function: ('darkgreen', 'green'), |
|
35 Name.Namespace: ('_teal_', '_turquoise_'), |
|
36 Name.Class: ('_darkgreen_', '_green_'), |
|
37 Name.Exception: ('teal', 'turquoise'), |
|
38 Name.Decorator: ('darkgray', 'lightgray'), |
|
39 Name.Variable: ('darkred', 'red'), |
|
40 Name.Constant: ('darkred', 'red'), |
|
41 Name.Attribute: ('teal', 'turquoise'), |
|
42 Name.Tag: ('blue', 'blue'), |
|
43 String: ('brown', 'brown'), |
|
44 Number: ('darkblue', 'blue'), |
|
45 |
|
46 Generic.Deleted: ('red', 'red'), |
|
47 Generic.Inserted: ('darkgreen', 'green'), |
|
48 Generic.Heading: ('**', '**'), |
|
49 Generic.Subheading: ('*purple*', '*fuchsia*'), |
|
50 Generic.Error: ('red', 'red'), |
|
51 |
|
52 Error: ('_red_', '_red_'), |
|
53 } |
|
54 |
|
55 |
|
56 class TerminalFormatter(Formatter): |
|
57 r""" |
|
58 Format tokens with ANSI color sequences, for output in a text console. |
|
59 Color sequences are terminated at newlines, so that paging the output |
|
60 works correctly. |
|
61 |
|
62 The `get_style_defs()` method doesn't do anything special since there is |
|
63 no support for common styles. |
|
64 |
|
65 Options accepted: |
|
66 |
|
67 `bg` |
|
68 Set to ``"light"`` or ``"dark"`` depending on the terminal's background |
|
69 (default: ``"light"``). |
|
70 |
|
71 `colorscheme` |
|
72 A dictionary mapping token types to (lightbg, darkbg) color names or |
|
73 ``None`` (default: ``None`` = use builtin colorscheme). |
|
74 """ |
|
75 name = 'Terminal' |
|
76 aliases = ['terminal', 'console'] |
|
77 filenames = [] |
|
78 |
|
79 def __init__(self, **options): |
|
80 Formatter.__init__(self, **options) |
|
81 self.darkbg = get_choice_opt(options, 'bg', |
|
82 ['light', 'dark'], 'light') == 'dark' |
|
83 self.colorscheme = options.get('colorscheme', None) or TERMINAL_COLORS |
|
84 |
|
85 def format(self, tokensource, outfile): |
|
86 # hack: if the output is a terminal and has an encoding set, |
|
87 # use that to avoid unicode encode problems |
|
88 if not self.encoding and hasattr(outfile, "encoding") and \ |
|
89 hasattr(outfile, "isatty") and outfile.isatty(): |
|
90 self.encoding = outfile.encoding |
|
91 return Formatter.format(self, tokensource, outfile) |
|
92 |
|
93 def format_unencoded(self, tokensource, outfile): |
|
94 for ttype, value in tokensource: |
|
95 color = self.colorscheme.get(ttype) |
|
96 while color is None: |
|
97 ttype = ttype[:-1] |
|
98 color = self.colorscheme.get(ttype) |
|
99 if color: |
|
100 color = color[self.darkbg] |
|
101 spl = value.split('\n') |
|
102 for line in spl[:-1]: |
|
103 if line: |
|
104 outfile.write(ansiformat(color, line)) |
|
105 outfile.write('\n') |
|
106 if spl[-1]: |
|
107 outfile.write(ansiformat(color, spl[-1])) |
|
108 else: |
|
109 outfile.write(value) |