| 1 | # -*- coding: iso-8859-1 -*- |
|---|
| 2 | # |
|---|
| 3 | # Copyright (C) 2011 Mikael Relbe <mikael@relbe.se> |
|---|
| 4 | # All rights reserved. |
|---|
| 5 | # |
|---|
| 6 | # Copyright (C) 2006 Christian Boos <cboos@neuf.fr> |
|---|
| 7 | # All rights reserved. |
|---|
| 8 | # |
|---|
| 9 | # This software is licensed as described in the file COPYING, which |
|---|
| 10 | # you should have received as part of this distribution. The terms |
|---|
| 11 | # are also available at http://trac.edgewall.com/license.html. |
|---|
| 12 | # |
|---|
| 13 | # Author: Christian Boos <cboos@neuf.fr> |
|---|
| 14 | # Mikael Relbe <mikael@relbe.se> |
|---|
| 15 | |
|---|
| 16 | from trac.util.html import Markup, html as tag |
|---|
| 17 | |
|---|
| 18 | from trac.config import BoolOption, ConfigSection, ListOption |
|---|
| 19 | from trac.core import implements, Component |
|---|
| 20 | from trac.wiki import IWikiSyntaxProvider, IWikiMacroProvider |
|---|
| 21 | |
|---|
| 22 | from tracwikiextras.util import prepare_regexp, render_table |
|---|
| 23 | |
|---|
| 24 | |
|---|
| 25 | SYMBOLS = { |
|---|
| 26 | '<-': '←', |
|---|
| 27 | '->': '→', |
|---|
| 28 | '<->': '↔', |
|---|
| 29 | '<=': '⇐', |
|---|
| 30 | '=>': '⇒', |
|---|
| 31 | '<=>': '⇔', |
|---|
| 32 | '>=': '≥', |
|---|
| 33 | '=<': '≤', # ... as <= is already used for ⇐ |
|---|
| 34 | '<>': '≠', # '!=' can't be used, because of the '!' escaping |
|---|
| 35 | '--': '—', |
|---|
| 36 | '(c)': '©', |
|---|
| 37 | '(C)': '©', |
|---|
| 38 | '(R)': '®', |
|---|
| 39 | '1/2': '½', |
|---|
| 40 | '1/4': '¼', |
|---|
| 41 | '3/4': '¾', |
|---|
| 42 | '+/-': '±', |
|---|
| 43 | '/\\': '∧', |
|---|
| 44 | '\\/': '∨', |
|---|
| 45 | '(TM)': '™', |
|---|
| 46 | '...': '…', |
|---|
| 47 | } |
|---|
| 48 | |
|---|
| 49 | |
|---|
| 50 | class Symbols(Component): |
|---|
| 51 | """Replace character sequences with symbols. |
|---|
| 52 | |
|---|
| 53 | Characters and symbols are configurable in the `[wikiextras-symbols]` |
|---|
| 54 | section in `trac.ini`. Use the `ShowSymbols` macro to display a list of |
|---|
| 55 | currently defined symbols. |
|---|
| 56 | """ |
|---|
| 57 | |
|---|
| 58 | implements(IWikiMacroProvider, IWikiSyntaxProvider) |
|---|
| 59 | |
|---|
| 60 | symbols_section = ConfigSection('wikiextras-symbols', |
|---|
| 61 | """The set of symbols is configurable by providing associations |
|---|
| 62 | between symbols and wiki keywords. A default set of symbols and |
|---|
| 63 | keywords is defined, which can be revoked one-by-one (_remove) or |
|---|
| 64 | all at once (_remove_defaults). |
|---|
| 65 | |
|---|
| 66 | Example: |
|---|
| 67 | {{{ |
|---|
| 68 | [wikiextras-symbols] |
|---|
| 69 | _remove_defaults = true |
|---|
| 70 | _remove = <- -> |
|---|
| 71 | « = << |
|---|
| 72 | » = >> |
|---|
| 73 | ∑ = (SUM) |
|---|
| 74 | ♥ = <3 |
|---|
| 75 | }}} |
|---|
| 76 | |
|---|
| 77 | Keywords are space-separated! |
|---|
| 78 | |
|---|
| 79 | A symbol can also be removed by associating it with no keyword: |
|---|
| 80 | {{{ |
|---|
| 81 | ← = |
|---|
| 82 | }}} |
|---|
| 83 | |
|---|
| 84 | Use the `ShowSymbols` macro to find out the current set of symbols |
|---|
| 85 | and keywords. |
|---|
| 86 | """) |
|---|
| 87 | |
|---|
| 88 | remove_defaults = BoolOption('wikiextras-symbols', '_remove_defaults', |
|---|
| 89 | False, doc="Set to true to remove all " |
|---|
| 90 | "default symbols.") |
|---|
| 91 | |
|---|
| 92 | remove = ListOption('wikiextras-symbols', '_remove', sep=' ', doc="""\ |
|---|
| 93 | Space-separated(!) list of keywords that shall not be interpreted |
|---|
| 94 | as symbols (even if defined in this section).""") |
|---|
| 95 | |
|---|
| 96 | def __init__(self): |
|---|
| 97 | self.symbols = None |
|---|
| 98 | |
|---|
| 99 | # IWikiSyntaxProvider methods |
|---|
| 100 | |
|---|
| 101 | def get_wiki_syntax(self): |
|---|
| 102 | if self.symbols is None: |
|---|
| 103 | self.symbols = SYMBOLS.copy() |
|---|
| 104 | if self.remove_defaults: |
|---|
| 105 | self.symbols = {} |
|---|
| 106 | for symbol, value in self.symbols_section.options(): |
|---|
| 107 | if not symbol.startswith('_remove'): |
|---|
| 108 | if value: |
|---|
| 109 | for keyword in value.split(): |
|---|
| 110 | self.symbols[keyword.strip()] = symbol |
|---|
| 111 | else: |
|---|
| 112 | # no keyword, remove all keywords associated with |
|---|
| 113 | # symbol |
|---|
| 114 | for k in self.symbols.keys(): |
|---|
| 115 | if self.symbols[k] == symbol: |
|---|
| 116 | del self.symbols[k] |
|---|
| 117 | for keyword in self.remove: |
|---|
| 118 | if keyword in self.symbols: |
|---|
| 119 | del self.symbols[keyword] |
|---|
| 120 | |
|---|
| 121 | if self.symbols: |
|---|
| 122 | yield ('!?(?:%s)' % prepare_regexp(self.symbols), |
|---|
| 123 | self._format_symbol) |
|---|
| 124 | else: |
|---|
| 125 | yield (None, None) |
|---|
| 126 | |
|---|
| 127 | def get_link_resolvers(self): |
|---|
| 128 | return [] |
|---|
| 129 | |
|---|
| 130 | #noinspection PyUnusedLocal |
|---|
| 131 | def _format_symbol(self, formatter, match, fullmatch): |
|---|
| 132 | return Markup(self.symbols[match]) |
|---|
| 133 | |
|---|
| 134 | # IWikiMacroProvider methods |
|---|
| 135 | |
|---|
| 136 | def get_macros(self): |
|---|
| 137 | yield 'ShowSymbols' |
|---|
| 138 | |
|---|
| 139 | #noinspection PyUnusedLocal |
|---|
| 140 | def get_macro_description(self, name): |
|---|
| 141 | return ("Renders in a table the list of known symbols. " |
|---|
| 142 | "Optional argument is the number of columns in the table " |
|---|
| 143 | "(defaults 3).") |
|---|
| 144 | |
|---|
| 145 | #noinspection PyUnusedLocal |
|---|
| 146 | def expand_macro(self, formatter, name, content, args=None): |
|---|
| 147 | return render_table(self.symbols.keys(), content, |
|---|
| 148 | lambda s: self._format_symbol(formatter, s, None), |
|---|
| 149 | colspace=4) |
|---|