Commits

blackbird  committed fba3713

[svn] added experimental (untested) plugin support. i'll try writing some plugins tomorrow when i've more time ;)

  • Participants
  • Parent commits b0ea883
  • Branches trunk

Comments (0)

Files changed (6)

File docs/src/index.txt

 
   - `Write your own formatter <formatterdev.txt>`_
 
+  - `Register Plugins <plugins.txt>`_
+
 - Hints and Tricks
 
   - `Using Pygments in ReST documents <rstdirective.txt>`_

File docs/src/plugins.txt

+================
+Register Plugins
+================
+
+If you want to extend pygments without hacking in the sources but want to
+use the lexer/formatter/style resolve functions you can use setuptools
+entrypoints to add new lexers, formatters or styles to the pygments core.
+
+That means you can use your highlighter also with the ``pygmentize`` script.
+
+
+Entrypoints
+===========
+
+Here a list of setuptools entrypoints pygments understands:
+
+`pygments.lexers`
+
+    This entrypoint is used for adding new lexers to the pygments core.
+    The name of entrypoint values doesn't really matter, pygements extract
+    required informations from the class definition:
+
+    .. sourcecode:: ini
+
+        [pygments.lexers]
+        yourlexer = yourmodule:YourLexer
+
+    Note that you have to
+    defined a ``name``, ``aliases`` and ``filename`` patterns so that you
+    can use the highlighter from the command line:
+
+    .. sourcecode:: python
+
+        class YourLexer(...):
+            name = 'Name Of Your Lexer'
+            aliases = ['alias']
+            filenames = ['*.ext']
+
+
+`pygments.formatters`
+
+    You can use this entrypoint to add new formatters to pygments. The
+    name of an entrypoint item is the name of the formatter. If you
+    prefix the name with a slash it's used for the filename pattern:
+
+    .. sourcecode:: ini
+
+        [pygments.formatters]
+        yourformatter = yourmodule:YourFormatter
+        /.ext = yourmodule:YourFormatter
+
+
+`pygments.styles`
+
+    To add a new style you can use this entrypoint. The name of the entrypoint
+    is the name of the style:
+
+    .. sourcecode:: ini
+
+        [pygments.styles]
+        yourstyle = yourmodule:YourStyle
+
+
+How To Use Entrypoints
+======================
+
+This documentation doesn't explain how to use those entrypoints because this is
+covered in the `setuptools documentation`_. That page should cover everything
+you need to write a plugin. Also `this blog entry`_ might be interesting.
+
+.. _setuptools documentation: http://peak.telecommunity.com/DevCenter/setuptools
+.. _this blog entry: http://lucumr.pocoo.org/entry/setuptools-plugins/

File pygments/formatters/__init__.py

 # -*- coding: utf-8 -*-
 """
     pygments.formatters
-    ~~~~~~~~~~~~~~~~~~
+    ~~~~~~~~~~~~~~~~~~~
 
     Pygments formatters.
 
 from pygments.formatters.latex import LatexFormatter
 from pygments.formatters.bbcode import BBCodeFormatter
 from pygments.formatters.other import NullFormatter, RawTokenFormatter
+from pygments.plugin import find_plugin_formatters
 
 
 def _doc_desc(obj):
 _formatter_cache = {}
 
 def _init_formatter_cache():
-    if _formatter_cache: return
+    if _formatter_cache:
+        return
     for cls, info in FORMATTERS.iteritems():
         for alias in info[1]:
             _formatter_cache[alias] = cls
         for ext in info[2]:
             _formatter_cache["/"+ext] = cls
+    for name, cls in find_plugin_formatters():
+        _formatter_cache[name] = cls
 
 
 def get_formatter_by_name(name, **options):

File pygments/lexers/__init__.py

 # -*- coding: utf-8 -*-
 """
     pygments.lexers
-    ~~~~~~~~~~~~~~
+    ~~~~~~~~~~~~~~~
 
     Pygments lexers.
 
 from os.path import basename
 
 from pygments.lexers._mapping import LEXERS
+from pygments.plugin import find_plugin_lexers
 
 
 __all__ = ['get_lexer_by_name', 'get_lexer_for_filename'] + LEXERS.keys()
     """
     Get a lexer by an alias
     """
+    # lookup builtin lexers
     for module_name, name, aliases, _ in LEXERS.itervalues():
         if alias in aliases:
             if name not in _lexer_cache:
                 _load_lexers(module_name)
             return _lexer_cache[name](**options)
+    # continue with lexers from setuptools entrypoints
+    for cls in find_plugin_lexers():
+        if alias in cls.aliases:
+            return cls(**options)
     raise ValueError('no lexer for alias %r found' % alias)
 
 
     Guess a lexer by a filename
     """
     fn = basename(fn)
+    # lookup builtin lexers
     for module_name, name, _, filenames in LEXERS.itervalues():
         for filename in filenames:
             if fnmatch.fnmatch(fn, filename):
                 if name not in _lexer_cache:
                     _load_lexers(module_name)
                 return _lexer_cache[name](**options)
+    # continue with lexers from setuptools entrypoints
+    for cls in find_plugin_lexers():
+        for filename in cls.filenames:
+            if fnmatch.fnmatch(fn, filename):
+                return cls(**options)
     raise ValueError('no lexer for filename %r found' % fn)
 
 

File pygments/plugin.py

+# -*- coding: utf-8 -*-
+"""
+    pygments.plugin
+    ~~~~~~~~~~~~~~~
+
+    Pygments setuptools plugin interface. The methods defined
+    here also work if setuptools isn't installed but they just
+    return nothing.
+
+    lexer plugins::
+
+        [pygments.lexers]
+        yourlexer = yourmodule:YourLexer
+
+    formatter plugins::
+
+        [pygments.formatters]
+        yourformatter = yourformatter:YourFormatter
+        /.ext = yourformatter:YourFormatter
+
+    As you can see, you can define extensions for the formatter
+    with a leading slash.
+
+    syntax plugins::
+
+        [pygments.styles]
+        yourstyle = yourstyle:YourStyle
+
+
+    :coypright: 2006 by Armin Ronacher.
+    :license: GNU LGPG; see LICENSE for more details.
+"""
+try:
+    import pkg_resources
+except ImportError:
+    pkg_resources = None
+
+LEXER_ENTRY_POINT = 'pygments.lexers'
+FORMATTER_ENTRY_POINT = 'pygments.formatters'
+STYLE_ENTRY_POINT = 'pygments.styles'
+
+
+def find_plugin_lexers():
+    if pkg_resources is None:
+        return
+    for entrypoint in pkg_resources.iter_entry_points(LEXER_ENTRY_POINT):
+        yield entrypoint.load()
+
+
+def find_plugin_formatters():
+    if pkg_resources is None:
+        return
+    for entrypoint in pkg_resources.iter_entry_points(FORMATTER_ENTRY_POINT):
+        yield entrypoint.name, entrypoint.load()
+
+
+def find_plugin_styles():
+    if pkg_resources is None:
+        return
+    for entrypoint in pkg_resources.iter_entry_points(STYLE_ENTRY_POINT):
+        yield entrypoint.name, entrypoint.load()

File pygments/styles/__init__.py

 # -*- coding: utf-8 -*-
 """
     pygments.styles
-    ~~~~~~~~~~~~~~
+    ~~~~~~~~~~~~~~~
 
     Contains built-in styles.
 
     :copyright: 2006 by Georg Brandl.
     :license: GNU LGPL, see LICENSE for more details.
 """
+from pygments.plugin import find_plugin_styles
+
 
 #: Maps style names to 'submodule::classname'.
 STYLE_MAP = {
 
 def get_style_by_name(name):
     if name not in STYLE_MAP:
+        for found_name, style in find_plugin_styles():
+            if name == found_name:
+                return style
         raise ValueError("Style %r not found" % name)
 
     mod, cls = STYLE_MAP[name].split('::')
-
     mod = __import__('pygments.styles.' + mod, None, None, [cls])
     return getattr(mod, cls)