| 1 | # -*- coding: iso-8859-1 -*- |
|---|
| 2 | # |
|---|
| 3 | # Copyright (C) 2011 Mikael Relbe <mikael@relbe.se> |
|---|
| 4 | # All rights reserved. |
|---|
| 5 | # |
|---|
| 6 | # This software is licensed as described in the file COPYING, which |
|---|
| 7 | # you should have received as part of this distribution. The terms |
|---|
| 8 | # are also available at http://trac.edgewall.com/license.html. |
|---|
| 9 | # |
|---|
| 10 | # Author: Mikael Relbe <mikael@relbe.se> |
|---|
| 11 | |
|---|
| 12 | """Highlight attentional phrases. |
|---|
| 13 | |
|---|
| 14 | Typical attentional phrases are `FIXME` and `TODO`. |
|---|
| 15 | |
|---|
| 16 | Any delimiter `():<>` adjacent to a phrase will not be presented. This makes it |
|---|
| 17 | possible to naturally write, for example, `FIXME:` in a wiki text, but view the |
|---|
| 18 | phrase highlighted without the colon (`:`) which would not look natural. |
|---|
| 19 | |
|---|
| 20 | Activate this component to highlight this: FIXME |
|---|
| 21 | """ |
|---|
| 22 | |
|---|
| 23 | from pkg_resources import resource_filename |
|---|
| 24 | |
|---|
| 25 | from trac.util.html import Markup, html as tag |
|---|
| 26 | |
|---|
| 27 | from trac.config import ListOption, ConfigSection |
|---|
| 28 | from trac.core import implements, Component |
|---|
| 29 | from trac.util.compat import cleandoc |
|---|
| 30 | from trac.web.api import IRequestFilter |
|---|
| 31 | from trac.web.chrome import ITemplateProvider, add_stylesheet |
|---|
| 32 | from trac.wiki import IWikiSyntaxProvider, IWikiMacroProvider, format_to_html |
|---|
| 33 | |
|---|
| 34 | from tracwikiextras.util import prepare_regexp, render_table |
|---|
| 35 | |
|---|
| 36 | |
|---|
| 37 | class Phrases(Component): |
|---|
| 38 | """Highlight attentional phrases like `FIXME`. |
|---|
| 39 | |
|---|
| 40 | Phrases that are highlighted are defined in the `[wikiextras]` section in |
|---|
| 41 | `trac.ini`. Use the `ShowPhrases` macro to show a list of currently defined |
|---|
| 42 | phrases. |
|---|
| 43 | """ |
|---|
| 44 | |
|---|
| 45 | implements(IRequestFilter, ITemplateProvider, IWikiSyntaxProvider, |
|---|
| 46 | IWikiMacroProvider) |
|---|
| 47 | |
|---|
| 48 | fixme_phrases = ListOption('wikiextras', 'fixme_phrases', 'BUG, FIXME', |
|---|
| 49 | doc= |
|---|
| 50 | """A list of attentional phrases or single words, separated by comma |
|---|
| 51 | (`,`) that will be highlighted to catch attention. Any delimiter |
|---|
| 52 | `():<>` adjacent to a phrase will not be presented. (i.e. do not |
|---|
| 53 | include any of these delimiters in this list). This makes it possible |
|---|
| 54 | to naturally write, for example, `FIXME:` in a wiki text, but view the |
|---|
| 55 | phrase highlighted without the colon (`:`) which would not look |
|---|
| 56 | natural. Use the `ShowPhrases` macro to show a list of currently |
|---|
| 57 | defined phrases.""") |
|---|
| 58 | |
|---|
| 59 | todo_phrases = ListOption('wikiextras', 'todo_phrases', 'REVIEW, TODO', |
|---|
| 60 | doc="Analogous to `FIXME`-phrases, but " |
|---|
| 61 | "presentation is less eye-catching.") |
|---|
| 62 | |
|---|
| 63 | done_phrases = ListOption('wikiextras', 'done_phrases', |
|---|
| 64 | 'DONE, DEBUGGED, FIXED, REVIEWED', |
|---|
| 65 | doc="Analogous to `FIXME`-phrases, but " |
|---|
| 66 | "presentation is less eye-catching.") |
|---|
| 67 | |
|---|
| 68 | custom_phrases_section = ConfigSection('wikiextras-custom-phrases', |
|---|
| 69 | """Custom phrases are configurable by providing associations |
|---|
| 70 | between a CSS class and the list of phrases separated by comma. |
|---|
| 71 | |
|---|
| 72 | Example: |
|---|
| 73 | {{{#!ini |
|---|
| 74 | [wikiextras-custom-phrases] |
|---|
| 75 | nice = NICE, COOL |
|---|
| 76 | }}} |
|---|
| 77 | """) |
|---|
| 78 | |
|---|
| 79 | def __init__(self): |
|---|
| 80 | self.text = {} |
|---|
| 81 | #noinspection PyArgumentList |
|---|
| 82 | html_form = '<span class="wikiextras phrase %s">%s</span>' |
|---|
| 83 | |
|---|
| 84 | def add_style(style, phrases): |
|---|
| 85 | for phrase in phrases: |
|---|
| 86 | html = html_form % (style, phrase) |
|---|
| 87 | self.text[phrase] = html |
|---|
| 88 | for (d1, d2) in [(':', ':'), ('<', '>'), ('(', ')')]: |
|---|
| 89 | self.text['%s%s%s' % (d1, phrase, d2)] = html |
|---|
| 90 | for d2 in [':']: |
|---|
| 91 | self.text['%s%s' % (phrase, d2)] = html |
|---|
| 92 | |
|---|
| 93 | for style, phrases in [('fixme', self.fixme_phrases), |
|---|
| 94 | ('todo', self.todo_phrases), |
|---|
| 95 | ('done', self.done_phrases)]: |
|---|
| 96 | add_style(style, phrases) |
|---|
| 97 | |
|---|
| 98 | for style, phrases in self.custom_phrases_section.options(): |
|---|
| 99 | add_style(style, phrases.split(',')) |
|---|
| 100 | |
|---|
| 101 | # IRequestFilter methods |
|---|
| 102 | |
|---|
| 103 | #noinspection PyUnusedLocal |
|---|
| 104 | def pre_process_request(self, req, handler): |
|---|
| 105 | return handler |
|---|
| 106 | |
|---|
| 107 | def post_process_request(self, req, template, data, content_type): |
|---|
| 108 | add_stylesheet(req, 'wikiextras/css/phrases.css') |
|---|
| 109 | return template, data, content_type |
|---|
| 110 | |
|---|
| 111 | # ITemplateProvider methods |
|---|
| 112 | |
|---|
| 113 | def get_htdocs_dirs(self): |
|---|
| 114 | return [('wikiextras', resource_filename(__name__, 'htdocs'))] |
|---|
| 115 | |
|---|
| 116 | def get_templates_dirs(self): |
|---|
| 117 | return [] |
|---|
| 118 | |
|---|
| 119 | # IWikiSyntaxProvider methods |
|---|
| 120 | |
|---|
| 121 | def get_wiki_syntax(self): |
|---|
| 122 | yield ('!?(?:%s)' % prepare_regexp(self.text), self._format_phrase) |
|---|
| 123 | |
|---|
| 124 | def get_link_resolvers(self): |
|---|
| 125 | return [] |
|---|
| 126 | |
|---|
| 127 | #noinspection PyUnusedLocal |
|---|
| 128 | def _format_phrase(self, formatter, match, fullmatch): |
|---|
| 129 | return Markup(self.text[match]) |
|---|
| 130 | |
|---|
| 131 | # IWikiMacroProvider methods |
|---|
| 132 | |
|---|
| 133 | def get_macros(self): |
|---|
| 134 | yield 'ShowPhrases' |
|---|
| 135 | |
|---|
| 136 | #noinspection PyUnusedLocal |
|---|
| 137 | def get_macro_description(self, name): |
|---|
| 138 | return cleandoc("""Renders in a table the list of known phrases that |
|---|
| 139 | are highlighted to catch attention. |
|---|
| 140 | |
|---|
| 141 | Comment: Any delimiter `():<>` adjacent to a phrase will not be |
|---|
| 142 | presented. This makes it possible to naturally write `FIXME:`, |
|---|
| 143 | for example, but view the phrase highlighted without the colon |
|---|
| 144 | (`:`) which would not look natural. Prefixing a phrase with `!` |
|---|
| 145 | prevents it from being highlighted. |
|---|
| 146 | """) |
|---|
| 147 | |
|---|
| 148 | #noinspection PyUnusedLocal |
|---|
| 149 | def expand_macro(self, formatter, name, content, args=None): |
|---|
| 150 | t = [render_table(p, '1', |
|---|
| 151 | lambda s: self._format_phrase(formatter, s, None)) |
|---|
| 152 | for p in [self.fixme_phrases, self.todo_phrases, |
|---|
| 153 | self.done_phrases]] |
|---|
| 154 | style = 'border:none;text-align:center;vertical-align:top' |
|---|
| 155 | spacer = tag.td(style='width:2em;border:none') |
|---|
| 156 | return tag.table(tag.tr(tag.td(t[0], style=style), spacer, |
|---|
| 157 | tag.td(t[1], style=style), spacer, |
|---|
| 158 | tag.td(t[2], style=style))) |
|---|
| 159 | |
|---|
| 160 | |
|---|
| 161 | class AboutWikiPhrases(Component): |
|---|
| 162 | """Macro for displaying a wiki page on how to use attentional phrases. |
|---|
| 163 | |
|---|
| 164 | Create a wiki page `WikiPhrases` and insert the following line to show |
|---|
| 165 | detailed instructions to wiki authors on how to use attentional phrases |
|---|
| 166 | in wiki pages: |
|---|
| 167 | {{{ |
|---|
| 168 | [[AboutWikiPhrases]] |
|---|
| 169 | }}} |
|---|
| 170 | """ |
|---|
| 171 | |
|---|
| 172 | implements(IWikiMacroProvider) |
|---|
| 173 | |
|---|
| 174 | # IWikiMacroProvider methods |
|---|
| 175 | |
|---|
| 176 | def get_macros(self): |
|---|
| 177 | yield 'AboutWikiPhrases' |
|---|
| 178 | |
|---|
| 179 | #noinspection PyUnusedLocal |
|---|
| 180 | def get_macro_description(self, name): |
|---|
| 181 | return "Display a wiki page on how to use attentional phrases." |
|---|
| 182 | |
|---|
| 183 | #noinspection PyUnusedLocal |
|---|
| 184 | def expand_macro(self, formatter, name, content, args=None): |
|---|
| 185 | help_file = resource_filename(__name__, 'doc/WikiPhrases') |
|---|
| 186 | fd = open(help_file, 'r') |
|---|
| 187 | wiki_text = fd.read() |
|---|
| 188 | fd.close() |
|---|
| 189 | return format_to_html(self.env, formatter.context, wiki_text) |
|---|