* NF: adding an example of use of simple filter @simplefilter is great, but also not very intuitive. Indeeds, the syntax seems to indicate that you define a function with four arguments while in reality you define a class whose constructor takes arbitrary keyword arguments. I believe in this case an example to show how to instantiate this filter is really necessary. Regarding simplefilter, I also believe that it could be improved in two simple ways: * accepting any method which takes lexer and stream as a filter. That would be sufficient as long as there is no option * the @simplefilter decorator could deal with `self` so that the user do not have to add it themselves. Probably not worth doing it no, as it would break compatibility with current version, but would be even simpler to use * NF: clarifying get_..._options get_bool_opt's documentation seems to indicate that the key is interpreted as a Boolean. While a quick look at the code shows clearly that the value associated to the key is what is interpreted as a Boolean. I hope I made the code clearer to any people who know python by indicating that it is essentially `.get` but with extra features * NF: clarifying Filter `filter` has already a specific behavior in general python, or for any people used to functional programing (and even if some dom processor). So indicating that a filter is not something that remove some tokens seems really useful to try to explain what is going on. * NF: adding details regarding states in lexer I found the state explanation confusing. I do know what a state machine is. However, reading the code, I first thought that there were two distinct variables: * the current state * the stack that are somehow related but distinct. Explaining that the current state is the top of the stack was lacking in my opinion. That also help explain #push. In particular that if you define in state "s" an operation whose new state is "#push", the behavior can be quite different than if the new state was "s".
75 lines
2.6 KiB
ReStructuredText
75 lines
2.6 KiB
ReStructuredText
.. -*- mode: rst -*-
|
|
|
|
=====================
|
|
Write your own filter
|
|
=====================
|
|
|
|
.. versionadded:: 0.7
|
|
|
|
Writing own filters is very easy. All you have to do is to subclass
|
|
the `Filter` class and override the `filter` method. Additionally a
|
|
filter is instantiated with some keyword arguments you can use to
|
|
adjust the behavior of your filter.
|
|
|
|
|
|
Subclassing Filters
|
|
===================
|
|
|
|
As an example, we write a filter that converts all `Name.Function` tokens
|
|
to normal `Name` tokens to make the output less colorful.
|
|
|
|
.. sourcecode:: python
|
|
|
|
from pygments.util import get_bool_opt
|
|
from pygments.token import Name
|
|
from pygments.filter import Filter
|
|
|
|
class UncolorFilter(Filter):
|
|
|
|
def __init__(self, **options):
|
|
Filter.__init__(self, **options)
|
|
self.class_too = get_bool_opt(options, 'classtoo')
|
|
|
|
def filter(self, lexer, stream):
|
|
for ttype, value in stream:
|
|
if ttype is Name.Function or (self.class_too and
|
|
ttype is Name.Class):
|
|
ttype = Name
|
|
yield ttype, value
|
|
|
|
Some notes on the `lexer` argument: that can be quite confusing since it doesn't
|
|
need to be a lexer instance. If a filter was added by using the `add_filter()`
|
|
function of lexers, that lexer is registered for the filter. In that case
|
|
`lexer` will refer to the lexer that has registered the filter. It *can* be used
|
|
to access options passed to a lexer. Because it could be `None` you always have
|
|
to check for that case if you access it.
|
|
|
|
|
|
Using a decorator
|
|
=================
|
|
|
|
You can also use the `simplefilter` decorator from the `pygments.filter` module:
|
|
|
|
.. sourcecode:: python
|
|
|
|
from pygments.util import get_bool_opt
|
|
from pygments.token import Name
|
|
from pygments.filter import simplefilter
|
|
|
|
|
|
@simplefilter
|
|
def uncolor(self, lexer, stream, options):
|
|
class_too = get_bool_opt(options, 'classtoo')
|
|
for ttype, value in stream:
|
|
if ttype is Name.Function or (class_too and
|
|
ttype is Name.Class):
|
|
ttype = Name
|
|
yield ttype, value
|
|
|
|
|
|
You can instantiate this filter by calling `uncolor(classtoo=True)`, the same
|
|
way that you would have instantiated the previous filter by calling
|
|
`UncolorFilter(classtoo=True)`. Indeed, The decorator automatically ensures that
|
|
`uncolor` is a class which subclasses an internal filter class. The class
|
|
`uncolo` uses the decorated function as a method for filtering. (That's why
|
|
there is a `self` argument that you probably won't end up using in the method.)
|