Edgewall Software

Ticket #6063: MyTitleIndex.py

File MyTitleIndex.py, 4.6 KB (added by Dave Abrahams <dave@…>, 5 years ago)

Macro plugin

Line 
1# Copyright David Abrahams 2007. Distributed under the Boost
2# Software License, Version 1.0. (See accompanying
3# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
4from datetime import datetime
5import imp
6import inspect
7import os
8import re
9from StringIO import StringIO
10
11from genshi.builder import Element, tag
12from genshi.core import Markup
13
14from trac.core import *
15from trac.util.datefmt import format_date, utc
16from trac.util.compat import sorted, groupby, any, set
17from trac.util.html import escape
18from trac.util.translation import _
19from trac.wiki.api import IWikiMacroProvider, WikiSystem, parse_args
20from trac.wiki.formatter import format_to_html, format_to_oneliner, \
21                                extract_link, OutlineFormatter
22from trac.wiki.model import WikiPage
23from trac.web.chrome import add_stylesheet
24
25from trac.wiki.macros import WikiMacroBase
26
27__all__ = [ 'MyTitleIndexMacro' ]
28
29class MyTitleIndexMacro(WikiMacroBase):
30    """Inserts an alphabetic list of all wiki pages into the output.
31
32    Accepts a prefix string as parameter: if provided, only pages with names
33    that start with the prefix are included in the resulting list. If this
34    parameter is omitted, all pages are listed.
35
36    Alternate `format` and `depth` can be specified:
37     - `format=group`: The list of page will be structured in groups
38       according to common prefix. This format also supports a `min=n`
39       argument, where `n` is the minimal number of pages for a group.
40     - `depth=n`: limit the depth of the pages to list. If set to 0,
41n       only toplevel pages will be shown, if set to 1, only immediate
42       children pages will be shown, etc. If not set, or set to -1,
43       all pages in the hierarchy will be shown.
44    """
45
46    SPLIT_RE = re.compile(r"( |/|[0-9])")
47
48    def expand_macro(self, formatter, name, content):
49        args, kw = parse_args(content)
50        prefix = args and args[0] or None
51        format = kw.get('format', '')
52        hideprefix = kw.get('hideprefix', None) 
53        minsize = max(int(kw.get('min', 2)), 2)
54        depth = int(kw.get('depth', -1))
55        start = prefix and prefix.count('/') or 0
56
57        wiki = formatter.wiki
58        pages = sorted(wiki.get_pages(prefix))
59
60        if format != 'group':
61            return tag.ul([tag.li(tag.a(wiki.format_page_name(page),
62                                        href=formatter.href.wiki(page)))
63                           for page in pages
64                           if depth < 0 or depth >= page.count('/') - start])
65
66        def lstripstring(s, start):
67            if s.startswith(start):
68                return s[len(start):]
69            else:
70                return s
71
72        # the string to strip off the beginning of each displayed page title
73        strip_prefix = hideprefix and prefix or ''
74
75        # How many elements of each title should be stripped?  This eliminates
76        # upper levels that have no siblings.  Otherwise, when stripping
77        # Foo/Bar/ you get something like:
78        #
79        # * Foo/
80        #   * Bar/
81        #     * x1
82        #     * x2
83        #     * ...
84        prefix_parts = hideprefix and len(self.SPLIT_RE.split(strip_prefix)) or 0
85
86        # Group by Wiki word and/or Wiki hierarchy
87        pages = [
88            (self.SPLIT_RE.split(
89                    wiki.format_page_name(
90                        page, split=True)
91            )[prefix_parts:],
92            page)
93                 
94            for page in pages
95            if depth < 0 or depth >= page.count('/') - start]
96       
97        def split_in_groups(group):
98            """Return list of pagename or (key, sublist) elements"""
99            groups = []
100            for key, subgrp in groupby(group, lambda (k,p): k and k[0] or ''):
101                subgrp = [(k[1:],p) for k,p in subgrp]
102                if key and len(subgrp) >= minsize:
103                    sublist = split_in_groups(sorted(subgrp))
104                    if len(sublist) == 1:
105                        elt = (key+sublist[0][0], sublist[0][1])
106                    else:
107                        elt = (key, sublist)
108                    groups.append(elt)
109                else:
110                    for elt in subgrp:
111                        groups.append(elt[1])
112            return groups
113
114        def render_groups(groups):
115            return tag.ul(
116                [tag.li(isinstance(elt, tuple) and 
117                        tag(tag.strong(elt[0]), render_groups(elt[1])) or
118                        tag.a(
119                            lstripstring(wiki.format_page_name(elt),strip_prefix),
120                            href=formatter.href.wiki(elt)))
121                 for elt in groups])
122       
123        return render_groups(split_in_groups(pages))