We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add support for acronym/abbr
Like in Sphinx, for example:

https://bitbucket.org/birkenfeld/sphinx/changeset/f69ec6dd2c54

Docutils has this in the To Do List, but I like Georg's syntax better.

http://docutils.sourceforge.net/docs/dev/todo.html


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pelican/readers.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 try:
3     import docutils
4     import docutils.core
5     import docutils.io
6     from docutils.writers.html4css1 import HTMLTranslator
7 
8     # import the directives to have pygments support
9     from pelican import rstdirectives  # NOQA
10 except ImportError:
11     core = False
12 try:
13     from markdown import Markdown
14 except ImportError:
15     Markdown = False  # NOQA
16 import re
17 
18 from pelican.contents import Category, Tag, Author
19 from pelican.utils import get_date, open
20 
21 
22 _METADATA_PROCESSORS = {
23     'tags': lambda x, y: [Tag(tag, y) for tag in unicode(x).split(',')],
24     'date': lambda x, y: get_date(x),
25     'status': lambda x, y: unicode.strip(x),
26     'category': Category,
27     'author': Author,
28 }
29 
30 
31 class Reader(object):
32     enabled = True
33     extensions = None
34 
35     def __init__(self, settings):
36         self.settings = settings
37 
38     def process_metadata(self, name, value):
39         if name in _METADATA_PROCESSORS:
40             return _METADATA_PROCESSORS[name](value, self.settings)
41         return value
42 
43 
44 class _FieldBodyTranslator(HTMLTranslator):
45 
46     def __init__(self, document):
47         HTMLTranslator.__init__(self, document)
48         self.compact_p = None
49 
50     def astext(self):
51         return ''.join(self.body)
52 
53     def visit_field_body(self, node):
54         pass
55 
56     def depart_field_body(self, node):
57         pass
58 
59 
60 def render_node_to_html(document, node):
61     visitor = _FieldBodyTranslator(document)
62     node.walkabout(visitor)
63     return visitor.astext()
64 
65 
66 class RstReader(Reader):
67     enabled = bool(docutils)
68     file_extensions = ['rst']
69 
70     def _parse_metadata(self, document):
71         """Return the dict containing document metadata"""
72         output = {}
73         for docinfo in document.traverse(docutils.nodes.docinfo):
74             for element in docinfo.children:
75                 if element.tagname == 'field':  # custom fields (e.g. summary)
76                     name_elem, body_elem = element.children
77                     name = name_elem.astext()
78                     if name == 'summary':
79                         value = render_node_to_html(document, body_elem)
80                     else:
81                         value = body_elem.astext()
82                 else:  # standard fields (e.g. address)
83                     name = element.tagname
84                     value = element.astext()
85                 name = name.lower()
86 
87                 output[name] = self.process_metadata(name, value)
88         return output
89 
90     def _get_publisher(self, filename):
91         extra_params = {'initial_header_level': '2'}
92         pub = docutils.core.Publisher(
93                 destination_class=docutils.io.StringOutput)
94         pub.set_components('standalone', 'restructuredtext', 'html')
95         pub.process_programmatic_settings(None, extra_params, None)
96         pub.set_source(source_path=filename)
97         pub.publish()
98         return pub
99 
100     def read(self, filename):
101         """Parses restructured text"""
102         pub = self._get_publisher(filename)
103         parts = pub.writer.parts
104         content = parts.get('body')
105 
106         metadata = self._parse_metadata(pub.document)
107         metadata.setdefault('title', parts.get('title'))
108 
109         return content, metadata
110 
111 
112 class MarkdownReader(Reader):
113     enabled = bool(Markdown)
114     file_extensions = ['md', 'markdown', 'mkd']
115     extensions = ['codehilite', 'extra']
116 
117     def read(self, filename):
118         """Parse content and metadata of markdown files"""
119         text = open(filename)
120         md = Markdown(extensions=set(self.extensions + ['meta']))
121         content = md.convert(text)
122 
123         metadata = {}
124         for name, value in md.Meta.items():
125             name = name.lower()
126             metadata[name] = self.process_metadata(name, value[0])
127         return content, metadata
128 
129 
130 class HtmlReader(Reader):
131     file_extensions = ['html', 'htm']
132     _re = re.compile('\<\!\-\-\#\s?[A-z0-9_-]*\s?\:s?[A-z0-9\s_-]*\s?\-\-\>')
133 
134     def read(self, filename):
135         """Parse content and metadata of (x)HTML files"""
136         with open(filename) as content:
137             metadata = {'title': 'unnamed'}
138             for i in self._re.findall(content):
139                 key = i.split(':')[0][5:].strip()
140                 value = i.split(':')[-1][:-3].strip()
141                 name = key.lower()
142                 metadata[name] = self.process_metadata(name, value)
143 
144             return content, metadata
145 
146 
147 _EXTENSIONS = {}
148 
149 for cls in Reader.__subclasses__():
150     for ext in cls.file_extensions:
151         _EXTENSIONS[ext] = cls
152 
153 
154 def read_file(filename, fmt=None, settings=None):
155     """Return a reader object using the given format."""
156     if not fmt:
157         fmt = filename.split('.')[-1]
158 
159     if fmt not in _EXTENSIONS:
160         raise TypeError('Pelican does not know how to parse %s' % filename)
161 
162     reader = _EXTENSIONS[fmt](settings)
163     settings_key = '%s_EXTENSIONS' % fmt.upper()
164 
165     if settings and settings_key in settings:
166         reader.extensions = settings[settings_key]
167 
168     if not reader.enabled:
169         raise ValueError("Missing dependencies for %s" % fmt)
170 
171     content, metadata = reader.read(filename)
172 
173     # eventually filter the content with typogrify if asked so
174     if settings and settings['TYPOGRIFY']:
175         from typogrify import Typogrify
176         content = Typogrify.typogrify(content)
177         metadata['title'] = Typogrify.typogrify(metadata['title'])
178 
179     return content, metadata
180
```

Path: `pelican/rstdirectives.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 from docutils import nodes
3 from docutils.parsers.rst import directives, Directive
4 from pygments.formatters import HtmlFormatter
5 from pygments import highlight
6 from pygments.lexers import get_lexer_by_name, TextLexer
7 
8 INLINESTYLES = False
9 DEFAULT = HtmlFormatter(noclasses=INLINESTYLES)
10 VARIANTS = {
11     'linenos': HtmlFormatter(noclasses=INLINESTYLES, linenos=True),
12 }
13 
14 
15 class Pygments(Directive):
16     """ Source code syntax hightlighting.
17     """
18     required_arguments = 1
19     optional_arguments = 0
20     final_argument_whitespace = True
21     option_spec = dict([(key, directives.flag) for key in VARIANTS])
22     has_content = True
23 
24     def run(self):
25         self.assert_has_content()
26         try:
27             lexer = get_lexer_by_name(self.arguments[0])
28         except ValueError:
29             # no lexer found - use the text one instead of an exception
30             lexer = TextLexer()
31         # take an arbitrary option if more than one is given
32         formatter = self.options and VARIANTS[self.options.keys()[0]] \
33                     or DEFAULT
34         parsed = highlight(u'\n'.join(self.content), lexer, formatter)
35         return [nodes.raw('', parsed, format='html')]
36 
37 directives.register_directive('code-block', Pygments)
38 directives.register_directive('sourcecode', Pygments)
39 
40 
41 class YouTube(Directive):
42     """ Embed YouTube video in posts.
43 
44     Courtesy of Brian Hsu: https://gist.github.com/1422773
45 
46     VIDEO_ID is required, with / height are optional integer,
47     and align could be left / center / right.
48 
49     Usage:
50     .. youtube:: VIDEO_ID
51         :width: 640
52         :height: 480
53         :align: center
54     """
55 
56     def align(argument):
57         """Conversion function for the "align" option."""
58         return directives.choice(argument, ('left', 'center', 'right'))
59 
60     required_arguments = 1
61     optional_arguments = 2
62     option_spec = {
63         'width': directives.positive_int,
64         'height': directives.positive_int,
65         'align': align
66     }
67 
68     final_argument_whitespace = False
69     has_content = False
70 
71     def run(self):
72         videoID = self.arguments[0].strip()
73         width = 420
74         height = 315
75         align = 'left'
76 
77         if 'width' in self.options:
78             width = self.options['width']
79 
80         if 'height' in self.options:
81             height = self.options['height']
82 
83         if 'align' in self.options:
84             align = self.options['align']
85 
86         url = 'http://www.youtube.com/embed/%s' % videoID
87         div_block = '<div class="youtube" align="%s">' % align
88         embed_block = '<iframe width="%s" height="%s" src="%s" '\
89                       'frameborder="0"></iframe>' % (width, height, url)
90 
91         return [
92             nodes.raw('', div_block, format='html'),
93             nodes.raw('', embed_block, format='html'),
94             nodes.raw('', '</div>', format='html')]
95 
96 directives.register_directive('youtube', YouTube)
97
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pelican/readers.py b/pelican/readers.py
--- a/pelican/readers.py
+++ b/pelican/readers.py
@@ -63,6 +63,18 @@
     return visitor.astext()
 
 
+class PelicanHTMLTranslator(HTMLTranslator):
+
+    def visit_abbreviation(self, node):
+        attrs = {}
+        if node.hasattr('explanation'):
+            attrs['title'] = node['explanation']
+        self.body.append(self.starttag(node, 'abbr', '', **attrs))
+
+    def depart_abbreviation(self, node):
+        self.body.append('</abbr>')
+
+
 class RstReader(Reader):
     enabled = bool(docutils)
     file_extensions = ['rst']
@@ -92,6 +104,7 @@
         pub = docutils.core.Publisher(
                 destination_class=docutils.io.StringOutput)
         pub.set_components('standalone', 'restructuredtext', 'html')
+        pub.writer.translator_class = PelicanHTMLTranslator
         pub.process_programmatic_settings(None, extra_params, None)
         pub.set_source(source_path=filename)
         pub.publish()
diff --git a/pelican/rstdirectives.py b/pelican/rstdirectives.py
--- a/pelican/rstdirectives.py
+++ b/pelican/rstdirectives.py
@@ -1,9 +1,10 @@
 # -*- coding: utf-8 -*-
-from docutils import nodes
-from docutils.parsers.rst import directives, Directive
+from docutils import nodes, utils
+from docutils.parsers.rst import directives, roles, Directive
 from pygments.formatters import HtmlFormatter
 from pygments import highlight
 from pygments.lexers import get_lexer_by_name, TextLexer
+import re
 
 INLINESTYLES = False
 DEFAULT = HtmlFormatter(noclasses=INLINESTYLES)
@@ -94,3 +95,18 @@
             nodes.raw('', '</div>', format='html')]
 
 directives.register_directive('youtube', YouTube)
+
+_abbr_re = re.compile('\((.*)\)$')
+
+class abbreviation(nodes.Inline, nodes.TextElement): pass
+
+def abbr_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
+	text = utils.unescape(text)
+	m = _abbr_re.search(text)
+	if m is None:
+		return [abbreviation(text, text)], []
+	abbr = text[:m.start()].strip()
+	expl = m.group(1)
+	return [abbreviation(abbr, abbr, explanation=expl)], []
+
+roles.register_local_role('abbr', abbr_role)

{"golden_diff": "diff --git a/pelican/readers.py b/pelican/readers.py\n--- a/pelican/readers.py\n+++ b/pelican/readers.py\n@@ -63,6 +63,18 @@\n     return visitor.astext()\n \n \n+class PelicanHTMLTranslator(HTMLTranslator):\n+\n+    def visit_abbreviation(self, node):\n+        attrs = {}\n+        if node.hasattr('explanation'):\n+            attrs['title'] = node['explanation']\n+        self.body.append(self.starttag(node, 'abbr', '', **attrs))\n+\n+    def depart_abbreviation(self, node):\n+        self.body.append('</abbr>')\n+\n+\n class RstReader(Reader):\n     enabled = bool(docutils)\n     file_extensions = ['rst']\n@@ -92,6 +104,7 @@\n         pub = docutils.core.Publisher(\n                 destination_class=docutils.io.StringOutput)\n         pub.set_components('standalone', 'restructuredtext', 'html')\n+        pub.writer.translator_class = PelicanHTMLTranslator\n         pub.process_programmatic_settings(None, extra_params, None)\n         pub.set_source(source_path=filename)\n         pub.publish()\ndiff --git a/pelican/rstdirectives.py b/pelican/rstdirectives.py\n--- a/pelican/rstdirectives.py\n+++ b/pelican/rstdirectives.py\n@@ -1,9 +1,10 @@\n # -*- coding: utf-8 -*-\n-from docutils import nodes\n-from docutils.parsers.rst import directives, Directive\n+from docutils import nodes, utils\n+from docutils.parsers.rst import directives, roles, Directive\n from pygments.formatters import HtmlFormatter\n from pygments import highlight\n from pygments.lexers import get_lexer_by_name, TextLexer\n+import re\n \n INLINESTYLES = False\n DEFAULT = HtmlFormatter(noclasses=INLINESTYLES)\n@@ -94,3 +95,18 @@\n             nodes.raw('', '</div>', format='html')]\n \n directives.register_directive('youtube', YouTube)\n+\n+_abbr_re = re.compile('\\((.*)\\)$')\n+\n+class abbreviation(nodes.Inline, nodes.TextElement): pass\n+\n+def abbr_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):\n+\ttext = utils.unescape(text)\n+\tm = _abbr_re.search(text)\n+\tif m is None:\n+\t\treturn [abbreviation(text, text)], []\n+\tabbr = text[:m.start()].strip()\n+\texpl = m.group(1)\n+\treturn [abbreviation(abbr, abbr, explanation=expl)], []\n+\n+roles.register_local_role('abbr', abbr_role)\n", "issue": "Add support for acronym/abbr\nLike in Sphinx, for example:\n\nhttps://bitbucket.org/birkenfeld/sphinx/changeset/f69ec6dd2c54\n\nDocutils has this in the To Do List, but I like Georg's syntax better.\n\nhttp://docutils.sourceforge.net/docs/dev/todo.html\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\ntry:\n    import docutils\n    import docutils.core\n    import docutils.io\n    from docutils.writers.html4css1 import HTMLTranslator\n\n    # import the directives to have pygments support\n    from pelican import rstdirectives  # NOQA\nexcept ImportError:\n    core = False\ntry:\n    from markdown import Markdown\nexcept ImportError:\n    Markdown = False  # NOQA\nimport re\n\nfrom pelican.contents import Category, Tag, Author\nfrom pelican.utils import get_date, open\n\n\n_METADATA_PROCESSORS = {\n    'tags': lambda x, y: [Tag(tag, y) for tag in unicode(x).split(',')],\n    'date': lambda x, y: get_date(x),\n    'status': lambda x, y: unicode.strip(x),\n    'category': Category,\n    'author': Author,\n}\n\n\nclass Reader(object):\n    enabled = True\n    extensions = None\n\n    def __init__(self, settings):\n        self.settings = settings\n\n    def process_metadata(self, name, value):\n        if name in _METADATA_PROCESSORS:\n            return _METADATA_PROCESSORS[name](value, self.settings)\n        return value\n\n\nclass _FieldBodyTranslator(HTMLTranslator):\n\n    def __init__(self, document):\n        HTMLTranslator.__init__(self, document)\n        self.compact_p = None\n\n    def astext(self):\n        return ''.join(self.body)\n\n    def visit_field_body(self, node):\n        pass\n\n    def depart_field_body(self, node):\n        pass\n\n\ndef render_node_to_html(document, node):\n    visitor = _FieldBodyTranslator(document)\n    node.walkabout(visitor)\n    return visitor.astext()\n\n\nclass RstReader(Reader):\n    enabled = bool(docutils)\n    file_extensions = ['rst']\n\n    def _parse_metadata(self, document):\n        \"\"\"Return the dict containing document metadata\"\"\"\n        output = {}\n        for docinfo in document.traverse(docutils.nodes.docinfo):\n            for element in docinfo.children:\n                if element.tagname == 'field':  # custom fields (e.g. summary)\n                    name_elem, body_elem = element.children\n                    name = name_elem.astext()\n                    if name == 'summary':\n                        value = render_node_to_html(document, body_elem)\n                    else:\n                        value = body_elem.astext()\n                else:  # standard fields (e.g. address)\n                    name = element.tagname\n                    value = element.astext()\n                name = name.lower()\n\n                output[name] = self.process_metadata(name, value)\n        return output\n\n    def _get_publisher(self, filename):\n        extra_params = {'initial_header_level': '2'}\n        pub = docutils.core.Publisher(\n                destination_class=docutils.io.StringOutput)\n        pub.set_components('standalone', 'restructuredtext', 'html')\n        pub.process_programmatic_settings(None, extra_params, None)\n        pub.set_source(source_path=filename)\n        pub.publish()\n        return pub\n\n    def read(self, filename):\n        \"\"\"Parses restructured text\"\"\"\n        pub = self._get_publisher(filename)\n        parts = pub.writer.parts\n        content = parts.get('body')\n\n        metadata = self._parse_metadata(pub.document)\n        metadata.setdefault('title', parts.get('title'))\n\n        return content, metadata\n\n\nclass MarkdownReader(Reader):\n    enabled = bool(Markdown)\n    file_extensions = ['md', 'markdown', 'mkd']\n    extensions = ['codehilite', 'extra']\n\n    def read(self, filename):\n        \"\"\"Parse content and metadata of markdown files\"\"\"\n        text = open(filename)\n        md = Markdown(extensions=set(self.extensions + ['meta']))\n        content = md.convert(text)\n\n        metadata = {}\n        for name, value in md.Meta.items():\n            name = name.lower()\n            metadata[name] = self.process_metadata(name, value[0])\n        return content, metadata\n\n\nclass HtmlReader(Reader):\n    file_extensions = ['html', 'htm']\n    _re = re.compile('\\<\\!\\-\\-\\#\\s?[A-z0-9_-]*\\s?\\:s?[A-z0-9\\s_-]*\\s?\\-\\-\\>')\n\n    def read(self, filename):\n        \"\"\"Parse content and metadata of (x)HTML files\"\"\"\n        with open(filename) as content:\n            metadata = {'title': 'unnamed'}\n            for i in self._re.findall(content):\n                key = i.split(':')[0][5:].strip()\n                value = i.split(':')[-1][:-3].strip()\n                name = key.lower()\n                metadata[name] = self.process_metadata(name, value)\n\n            return content, metadata\n\n\n_EXTENSIONS = {}\n\nfor cls in Reader.__subclasses__():\n    for ext in cls.file_extensions:\n        _EXTENSIONS[ext] = cls\n\n\ndef read_file(filename, fmt=None, settings=None):\n    \"\"\"Return a reader object using the given format.\"\"\"\n    if not fmt:\n        fmt = filename.split('.')[-1]\n\n    if fmt not in _EXTENSIONS:\n        raise TypeError('Pelican does not know how to parse %s' % filename)\n\n    reader = _EXTENSIONS[fmt](settings)\n    settings_key = '%s_EXTENSIONS' % fmt.upper()\n\n    if settings and settings_key in settings:\n        reader.extensions = settings[settings_key]\n\n    if not reader.enabled:\n        raise ValueError(\"Missing dependencies for %s\" % fmt)\n\n    content, metadata = reader.read(filename)\n\n    # eventually filter the content with typogrify if asked so\n    if settings and settings['TYPOGRIFY']:\n        from typogrify import Typogrify\n        content = Typogrify.typogrify(content)\n        metadata['title'] = Typogrify.typogrify(metadata['title'])\n\n    return content, metadata\n", "path": "pelican/readers.py"}, {"content": "# -*- coding: utf-8 -*-\nfrom docutils import nodes\nfrom docutils.parsers.rst import directives, Directive\nfrom pygments.formatters import HtmlFormatter\nfrom pygments import highlight\nfrom pygments.lexers import get_lexer_by_name, TextLexer\n\nINLINESTYLES = False\nDEFAULT = HtmlFormatter(noclasses=INLINESTYLES)\nVARIANTS = {\n    'linenos': HtmlFormatter(noclasses=INLINESTYLES, linenos=True),\n}\n\n\nclass Pygments(Directive):\n    \"\"\" Source code syntax hightlighting.\n    \"\"\"\n    required_arguments = 1\n    optional_arguments = 0\n    final_argument_whitespace = True\n    option_spec = dict([(key, directives.flag) for key in VARIANTS])\n    has_content = True\n\n    def run(self):\n        self.assert_has_content()\n        try:\n            lexer = get_lexer_by_name(self.arguments[0])\n        except ValueError:\n            # no lexer found - use the text one instead of an exception\n            lexer = TextLexer()\n        # take an arbitrary option if more than one is given\n        formatter = self.options and VARIANTS[self.options.keys()[0]] \\\n                    or DEFAULT\n        parsed = highlight(u'\\n'.join(self.content), lexer, formatter)\n        return [nodes.raw('', parsed, format='html')]\n\ndirectives.register_directive('code-block', Pygments)\ndirectives.register_directive('sourcecode', Pygments)\n\n\nclass YouTube(Directive):\n    \"\"\" Embed YouTube video in posts.\n\n    Courtesy of Brian Hsu: https://gist.github.com/1422773\n\n    VIDEO_ID is required, with / height are optional integer,\n    and align could be left / center / right.\n\n    Usage:\n    .. youtube:: VIDEO_ID\n        :width: 640\n        :height: 480\n        :align: center\n    \"\"\"\n\n    def align(argument):\n        \"\"\"Conversion function for the \"align\" option.\"\"\"\n        return directives.choice(argument, ('left', 'center', 'right'))\n\n    required_arguments = 1\n    optional_arguments = 2\n    option_spec = {\n        'width': directives.positive_int,\n        'height': directives.positive_int,\n        'align': align\n    }\n\n    final_argument_whitespace = False\n    has_content = False\n\n    def run(self):\n        videoID = self.arguments[0].strip()\n        width = 420\n        height = 315\n        align = 'left'\n\n        if 'width' in self.options:\n            width = self.options['width']\n\n        if 'height' in self.options:\n            height = self.options['height']\n\n        if 'align' in self.options:\n            align = self.options['align']\n\n        url = 'http://www.youtube.com/embed/%s' % videoID\n        div_block = '<div class=\"youtube\" align=\"%s\">' % align\n        embed_block = '<iframe width=\"%s\" height=\"%s\" src=\"%s\" '\\\n                      'frameborder=\"0\"></iframe>' % (width, height, url)\n\n        return [\n            nodes.raw('', div_block, format='html'),\n            nodes.raw('', embed_block, format='html'),\n            nodes.raw('', '</div>', format='html')]\n\ndirectives.register_directive('youtube', YouTube)\n", "path": "pelican/rstdirectives.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\ntry:\n    import docutils\n    import docutils.core\n    import docutils.io\n    from docutils.writers.html4css1 import HTMLTranslator\n\n    # import the directives to have pygments support\n    from pelican import rstdirectives  # NOQA\nexcept ImportError:\n    core = False\ntry:\n    from markdown import Markdown\nexcept ImportError:\n    Markdown = False  # NOQA\nimport re\n\nfrom pelican.contents import Category, Tag, Author\nfrom pelican.utils import get_date, open\n\n\n_METADATA_PROCESSORS = {\n    'tags': lambda x, y: [Tag(tag, y) for tag in unicode(x).split(',')],\n    'date': lambda x, y: get_date(x),\n    'status': lambda x, y: unicode.strip(x),\n    'category': Category,\n    'author': Author,\n}\n\n\nclass Reader(object):\n    enabled = True\n    extensions = None\n\n    def __init__(self, settings):\n        self.settings = settings\n\n    def process_metadata(self, name, value):\n        if name in _METADATA_PROCESSORS:\n            return _METADATA_PROCESSORS[name](value, self.settings)\n        return value\n\n\nclass _FieldBodyTranslator(HTMLTranslator):\n\n    def __init__(self, document):\n        HTMLTranslator.__init__(self, document)\n        self.compact_p = None\n\n    def astext(self):\n        return ''.join(self.body)\n\n    def visit_field_body(self, node):\n        pass\n\n    def depart_field_body(self, node):\n        pass\n\n\ndef render_node_to_html(document, node):\n    visitor = _FieldBodyTranslator(document)\n    node.walkabout(visitor)\n    return visitor.astext()\n\n\nclass PelicanHTMLTranslator(HTMLTranslator):\n\n    def visit_abbreviation(self, node):\n        attrs = {}\n        if node.hasattr('explanation'):\n            attrs['title'] = node['explanation']\n        self.body.append(self.starttag(node, 'abbr', '', **attrs))\n\n    def depart_abbreviation(self, node):\n        self.body.append('</abbr>')\n\n\nclass RstReader(Reader):\n    enabled = bool(docutils)\n    file_extensions = ['rst']\n\n    def _parse_metadata(self, document):\n        \"\"\"Return the dict containing document metadata\"\"\"\n        output = {}\n        for docinfo in document.traverse(docutils.nodes.docinfo):\n            for element in docinfo.children:\n                if element.tagname == 'field':  # custom fields (e.g. summary)\n                    name_elem, body_elem = element.children\n                    name = name_elem.astext()\n                    if name == 'summary':\n                        value = render_node_to_html(document, body_elem)\n                    else:\n                        value = body_elem.astext()\n                else:  # standard fields (e.g. address)\n                    name = element.tagname\n                    value = element.astext()\n                name = name.lower()\n\n                output[name] = self.process_metadata(name, value)\n        return output\n\n    def _get_publisher(self, filename):\n        extra_params = {'initial_header_level': '2'}\n        pub = docutils.core.Publisher(\n                destination_class=docutils.io.StringOutput)\n        pub.set_components('standalone', 'restructuredtext', 'html')\n        pub.writer.translator_class = PelicanHTMLTranslator\n        pub.process_programmatic_settings(None, extra_params, None)\n        pub.set_source(source_path=filename)\n        pub.publish()\n        return pub\n\n    def read(self, filename):\n        \"\"\"Parses restructured text\"\"\"\n        pub = self._get_publisher(filename)\n        parts = pub.writer.parts\n        content = parts.get('body')\n\n        metadata = self._parse_metadata(pub.document)\n        metadata.setdefault('title', parts.get('title'))\n\n        return content, metadata\n\n\nclass MarkdownReader(Reader):\n    enabled = bool(Markdown)\n    file_extensions = ['md', 'markdown', 'mkd']\n    extensions = ['codehilite', 'extra']\n\n    def read(self, filename):\n        \"\"\"Parse content and metadata of markdown files\"\"\"\n        text = open(filename)\n        md = Markdown(extensions=set(self.extensions + ['meta']))\n        content = md.convert(text)\n\n        metadata = {}\n        for name, value in md.Meta.items():\n            name = name.lower()\n            metadata[name] = self.process_metadata(name, value[0])\n        return content, metadata\n\n\nclass HtmlReader(Reader):\n    file_extensions = ['html', 'htm']\n    _re = re.compile('\\<\\!\\-\\-\\#\\s?[A-z0-9_-]*\\s?\\:s?[A-z0-9\\s_-]*\\s?\\-\\-\\>')\n\n    def read(self, filename):\n        \"\"\"Parse content and metadata of (x)HTML files\"\"\"\n        with open(filename) as content:\n            metadata = {'title': 'unnamed'}\n            for i in self._re.findall(content):\n                key = i.split(':')[0][5:].strip()\n                value = i.split(':')[-1][:-3].strip()\n                name = key.lower()\n                metadata[name] = self.process_metadata(name, value)\n\n            return content, metadata\n\n\n_EXTENSIONS = {}\n\nfor cls in Reader.__subclasses__():\n    for ext in cls.file_extensions:\n        _EXTENSIONS[ext] = cls\n\n\ndef read_file(filename, fmt=None, settings=None):\n    \"\"\"Return a reader object using the given format.\"\"\"\n    if not fmt:\n        fmt = filename.split('.')[-1]\n\n    if fmt not in _EXTENSIONS:\n        raise TypeError('Pelican does not know how to parse %s' % filename)\n\n    reader = _EXTENSIONS[fmt](settings)\n    settings_key = '%s_EXTENSIONS' % fmt.upper()\n\n    if settings and settings_key in settings:\n        reader.extensions = settings[settings_key]\n\n    if not reader.enabled:\n        raise ValueError(\"Missing dependencies for %s\" % fmt)\n\n    content, metadata = reader.read(filename)\n\n    # eventually filter the content with typogrify if asked so\n    if settings and settings['TYPOGRIFY']:\n        from typogrify import Typogrify\n        content = Typogrify.typogrify(content)\n        metadata['title'] = Typogrify.typogrify(metadata['title'])\n\n    return content, metadata\n", "path": "pelican/readers.py"}, {"content": "# -*- coding: utf-8 -*-\nfrom docutils import nodes, utils\nfrom docutils.parsers.rst import directives, roles, Directive\nfrom pygments.formatters import HtmlFormatter\nfrom pygments import highlight\nfrom pygments.lexers import get_lexer_by_name, TextLexer\nimport re\n\nINLINESTYLES = False\nDEFAULT = HtmlFormatter(noclasses=INLINESTYLES)\nVARIANTS = {\n    'linenos': HtmlFormatter(noclasses=INLINESTYLES, linenos=True),\n}\n\n\nclass Pygments(Directive):\n    \"\"\" Source code syntax hightlighting.\n    \"\"\"\n    required_arguments = 1\n    optional_arguments = 0\n    final_argument_whitespace = True\n    option_spec = dict([(key, directives.flag) for key in VARIANTS])\n    has_content = True\n\n    def run(self):\n        self.assert_has_content()\n        try:\n            lexer = get_lexer_by_name(self.arguments[0])\n        except ValueError:\n            # no lexer found - use the text one instead of an exception\n            lexer = TextLexer()\n        # take an arbitrary option if more than one is given\n        formatter = self.options and VARIANTS[self.options.keys()[0]] \\\n                    or DEFAULT\n        parsed = highlight(u'\\n'.join(self.content), lexer, formatter)\n        return [nodes.raw('', parsed, format='html')]\n\ndirectives.register_directive('code-block', Pygments)\ndirectives.register_directive('sourcecode', Pygments)\n\n\nclass YouTube(Directive):\n    \"\"\" Embed YouTube video in posts.\n\n    Courtesy of Brian Hsu: https://gist.github.com/1422773\n\n    VIDEO_ID is required, with / height are optional integer,\n    and align could be left / center / right.\n\n    Usage:\n    .. youtube:: VIDEO_ID\n        :width: 640\n        :height: 480\n        :align: center\n    \"\"\"\n\n    def align(argument):\n        \"\"\"Conversion function for the \"align\" option.\"\"\"\n        return directives.choice(argument, ('left', 'center', 'right'))\n\n    required_arguments = 1\n    optional_arguments = 2\n    option_spec = {\n        'width': directives.positive_int,\n        'height': directives.positive_int,\n        'align': align\n    }\n\n    final_argument_whitespace = False\n    has_content = False\n\n    def run(self):\n        videoID = self.arguments[0].strip()\n        width = 420\n        height = 315\n        align = 'left'\n\n        if 'width' in self.options:\n            width = self.options['width']\n\n        if 'height' in self.options:\n            height = self.options['height']\n\n        if 'align' in self.options:\n            align = self.options['align']\n\n        url = 'http://www.youtube.com/embed/%s' % videoID\n        div_block = '<div class=\"youtube\" align=\"%s\">' % align\n        embed_block = '<iframe width=\"%s\" height=\"%s\" src=\"%s\" '\\\n                      'frameborder=\"0\"></iframe>' % (width, height, url)\n\n        return [\n            nodes.raw('', div_block, format='html'),\n            nodes.raw('', embed_block, format='html'),\n            nodes.raw('', '</div>', format='html')]\n\ndirectives.register_directive('youtube', YouTube)\n\n_abbr_re = re.compile('\\((.*)\\)$')\n\nclass abbreviation(nodes.Inline, nodes.TextElement): pass\n\ndef abbr_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):\n\ttext = utils.unescape(text)\n\tm = _abbr_re.search(text)\n\tif m is None:\n\t\treturn [abbreviation(text, text)], []\n\tabbr = text[:m.start()].strip()\n\texpl = m.group(1)\n\treturn [abbreviation(abbr, abbr, explanation=expl)], []\n\nroles.register_local_role('abbr', abbr_role)\n", "path": "pelican/rstdirectives.py"}]}