diff --git a/docs/changelog.rst b/docs/changelog.rst index aa594a2c..60198c08 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -5,6 +5,7 @@ Next release ============ * New signal: ``feed_generated`` +* New setting: ``GENERATE_CTAGS`` to generate a "tags" file following the CTags format and containing all articles tags. 3.7.1 (2017-01-10) ================== diff --git a/docs/settings.rst b/docs/settings.rst index 0ae26ca4..01638b72 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -328,6 +328,9 @@ Basic settings A list of metadata fields containing reST/Markdown content to be parsed and translated to HTML. +.. data:: GENERATE_CTAGS = False + + Whether to generate a "tags" file following the CTags format and containing all articles tags. URL settings ============ diff --git a/pelican/generators.py b/pelican/generators.py index 069da0c1..53d5ffc5 100644 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -26,6 +26,15 @@ from pelican.utils import (DateFormatter, copy, mkdir_p, order_content, python_2_unicode_compatible) +# Format spec: http://ctags.sourceforge.net/FORMAT +CTAGS_TEMPLATE = '''{% for tag, articles in tags_articles %} +{% for article in articles %} +{{tag}}\t{{article}}\t0;"\ttag +{% endfor %} +{% endfor %} +''' + + logger = logging.getLogger(__name__) @@ -506,6 +515,19 @@ class ArticlesGenerator(CachingGenerator): self.context, blog=True, paginated=paginated, page_name=os.path.splitext(save_as)[0], url=url) + def generate_ctags(self, writer): + """Generate CTags tags file in source content directory.""" + if not self.settings.get('GENERATE_CTAGS'): + return + tags_file_path = os.path.join(self.path, 'tags') + self.settings.setdefault('WRITE_SELECTED', []).append(tags_file_path) + writer.output_path = self.path + try: + writer.write_file('tags', self.env.from_string(CTAGS_TEMPLATE), self.context, + tags_articles=sorted(self.tags.items())) + finally: + writer.output_path = self.output_path + def generate_tags(self, write): """Generate Tags pages.""" tag_template = self.get_template('tag') @@ -554,6 +576,7 @@ class ArticlesGenerator(CachingGenerator): self.generate_articles(write) self.generate_period_archives(write) self.generate_direct_templates(write) + self.generate_ctags(writer) # and subfolders after that self.generate_tags(write) diff --git a/pelican/settings.py b/pelican/settings.py index eac6ff19..0759e4c4 100644 --- a/pelican/settings.py +++ b/pelican/settings.py @@ -150,6 +150,7 @@ DEFAULT_CONFIG = { 'LOAD_CONTENT_CACHE': False, 'WRITE_SELECTED': [], 'FORMATTED_FIELDS': ['summary'], + 'GENERATE_CTAGS': False } PYGMENTS_RST_OPTIONS = None diff --git a/pelican/tests/test_generators.py b/pelican/tests/test_generators.py index c1899ab8..f58356e7 100644 --- a/pelican/tests/test_generators.py +++ b/pelican/tests/test_generators.py @@ -573,6 +573,34 @@ class TestArticlesGenerator(unittest.TestCase): articles = [article.title for article in generator.articles] self.assertEqual(articles, list(reversed(expected))) + def test_generate_ctags(self): + settings = get_settings(filenames={}) + settings['GENERATE_CTAGS'] = True + + generator = ArticlesGenerator( + context=settings.copy(), settings=settings, + path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + generator.generate_context() + + writer = Writer(None, settings=settings) + generator.generate_ctags(writer) + + output_path = os.path.join(CONTENT_DIR, 'tags') + self.assertTrue(os.path.exists(output_path)) + + try: + # output content is correct + with open(output_path, 'r') as output_file: + ctags = [l.split('\t')[0] for l in output_file.readlines()] + self.assertEqual([ + 'bar', 'bar', 'bar', 'bar', 'bar', + 'foo', 'foo', 'foo', 'foo', 'foo', + 'foobar', 'foobar', 'foobar', 'foobar', 'foobar', + 'マック', 'パイソン' + ], ctags) + finally: + os.remove(output_path) + class TestPageGenerator(unittest.TestCase): # Note: Every time you want to test for a new field; Make sure the test