summaryrefslogtreecommitdiff
path: root/pygments/filters/__init__.py
blob: be52a01bd135f991bf3b44eee43fa7928b89e2ee (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# -*- coding: utf-8 -*-
"""
    pygments.filters
    ~~~~~~~~~~~~~~~~

    Module containing filter lookup functions and default
    filters.

    :copyright: 2006 by Armin Ronacher.
    :license: BSD, see LICENSE for more details.
"""
try:
    set
except NameError:
    from sets import Set as set

import re
from pygments.token import String, Comment, Keyword, Name, string_to_tokentype
from pygments.filter import Filter
from pygments.util import get_list_opt
from pygments.plugin import find_plugin_filters


def find_filter(filter, **options):
    """
    Lookup a builtin filter. Options are passed to the
    filter initialization if wanted.
    """
    if filter in FILTERS:
        return FILTERS[filter](**options)
    for name, cls in find_plugin_filters():
        if name == filter:
            return cls(**options)
    raise ValueError('filter %r not found' % filter)


def get_all_filters():
    """
    Return a generator for all filters by name.
    """
    for name in FILTERS:
        yield name
    for name, _ in find_plugin_filters():
        yield name


class CodeTagFilter(Filter):
    """
    Highlights special code tags in comments and docstrings. Per default, the
    list of highlighted tags is ``XXX``, ``TODO``, ``BUG`` and ``NOTE``. You can
    override this list by specifying a `codetags` parameter that takes a list of
    words.
    """
    def __init__(self, **options):
        Filter.__init__(self)
        tags = get_list_opt(options, 'codetags',
                            ['XXX', 'TODO', 'BUG', 'NOTE'])
        self.tag_re = re.compile(r'(%s)' % '|'.join([
            re.escape(tag) for tag in tags if tag
        ]))

    def filter(self, lexer, stream):
        for ttype, value in stream:
            if ttype in String.Doc or \
               ttype in Comment and \
               ttype not in Comment.Preproc:
                last = 0
                for match in self.tag_re.finditer(value):
                    start = match.start()
                    end = match.end()
                    if start != last:
                        yield ttype, value[last:start]
                    yield Comment.Special, value[start:end]
                    last = end
                if last != len(value):
                    yield ttype, value[last:]
                continue
            yield ttype, value


class KeywordCaseFilter(Filter):
    """
    Converts keywords to ``lower``, ``upper`` or ``capitalize`` which means
    first letter uppercase, rest lowercase. This can be useful e.g. if you
    highlight Pascal code and want to adapt the code to your styleguide. The
    default is ``lower``, override that by providing the `keywordcase`
    parameter.
    """

    def __init__(self, **options):
        Filter.__init__(self, **options)
        case = options.get('keywordcase', 'lower')
        if case not in ('lower', 'upper', 'capitalize'):
            raise TypeError('unknown conversion method %r' % case)
        self.convert = getattr(unicode, case)

    def filter(self, lexer, stream):
        for ttype, value in stream:
            if ttype in Keyword:
                yield ttype, self.convert(value)
            else:
                yield ttype, value


class NameHighlightFilter(Filter):
    """
    Highlight normal name token with a different one::

        filter = NameHighlightFilter(
            highlight=['foo', 'bar', 'baz'],
            highlight_token=Name.Function
        )

    This would highlight the names "foo", "bar" and "baz"
    as functions. `Name.Function` is the token default.
    """

    def __init__(self, **options):
        self.words = set(get_list_opt(options, 'highlight', []))
        highlight_token = options.get('highlight_token')
        if highlight_token:
            self.highlight_token = string_to_tokentype(highlight_token)
        else:
            self.highlight_token = Name.Function

    def filter(self, lexer, stream):
        for ttype, value in stream:
            if ttype is Name and value in self.words:
                yield self.highlight_token, value
            else:
                yield ttype, value


FILTERS = {
    'codetagify':           CodeTagFilter,
    'keywordcase':          KeywordCaseFilter,
    'highlight':            NameHighlightFilter
}