new trac version to lenny
hello
i would like to ship a new version to lenny if it is still possible.
debdiff attached and the packages are available in
http://alioth.debian.org/~gass-guest/trac .
evaluating the changelog:
* Updated README.Debian about upgrading issues ( Closes: #501338 )
- users need to upgrade their projects database, when upgrading trac
from etch. that is not written anywhere.
* Added option to allow python2.5 built in functions of squilite. (
Closes: #518560 )
- a small change in debian/control
* Applied patch to finally install the contrib directory ( Closes:
#495019 )
this is a removal of a patch and a simple change in debian/rules to
correctly install the contrib directory
* Raised compat version ( Closes: #497862 )
why not?
please, check if this is ok to go to lenny, thanks.
Luis Matos
diff -u trac-0.11.1/debian/compat trac-0.11.1/debian/compat
--- trac-0.11.1/debian/compat
+++ trac-0.11.1/debian/compat
@@ -1 +1 @@
-4
+6
diff -u trac-0.11.1/debian/rules trac-0.11.1/debian/rules
--- trac-0.11.1/debian/rules
+++ trac-0.11.1/debian/rules
@@ -33,6 +33,7 @@
dh_testroot
dh_installchangelogs
dh_installdocs
+ dh_install
dh_installman
dh_link
dh_lintian
diff -u trac-0.11.1/debian/changelog trac-0.11.1/debian/changelog
--- trac-0.11.1/debian/changelog
+++ trac-0.11.1/debian/changelog
@@ -1,3 +1,14 @@
+trac (0.11.1-2.1lenny1) UNRELEASED; urgency=low
+
+ * Updated README.Debian about upgrading issues ( Closes: #501338 )
+ * Added option to allow python2.5 built in functions of squilite. (
+ Closes: #518560 )
+ * Applied patch to finally install the contrib directory ( Closes:
+ #495019 )
+ * Raised compat version ( Closes: #497862 )
+
+ -- Luis Matos <gass@otiliamatos.ath.cx> Mon, 30 Mar 2009 19:45:20 +0100
+
trac (0.11.1-2.1) unstable; urgency=high
* Non-maintainer upload.
diff -u trac-0.11.1/debian/README.Debian trac-0.11.1/debian/README.Debian
--- trac-0.11.1/debian/README.Debian
+++ trac-0.11.1/debian/README.Debian
@@ -13,6 +13,16 @@
Trac uses SQLite (python-pysqlite2) as an embedded database, but
can be configured to use PostgreSQL or MySQL instead.
+Upgrading a Project Environment
+-------------------------------
+
+Bug: #501338
+The project database from versions 0.10.x used sqlite v2.
+0.11.x versions use sqlite v3.
+To upgrade you must follow these steps:
+sqlite db/trac.db .dump | sqlite3 db/trac.db3
+
+
Creating a Project Environment
------------------------------
Trac Environment is the backend storage format where Trac stores
diff -u trac-0.11.1/debian/control trac-0.11.1/debian/control
--- trac-0.11.1/debian/control
+++ trac-0.11.1/debian/control
@@ -1,8 +1,8 @@
Source: trac
Section: web
Priority: optional
-Build-Depends-Indep: python-setuptools (> 0.5)
-Build-Depends: python-genshi (>= 0.5), python-central, python-all-dev, debhelper (>= 6.0.7), dpatch
+Build-Depends-Indep: python-genshi (>= 0.5), python-central, python-all-dev, python-setuptools (> 0.5)
+Build-Depends: debhelper (>= 6.0.7), dpatch
Maintainer: Debian Trac Team <pkg-trac-devel@lists.alioth.debian.org>
Uploaders: Otavio Salvador <otavio@debian.org>, Andres Salomon <dilinger@debian.org>, Jesus Climent <jesus.climent@hispalinux.es>, Luis Matos <gass@otiliamatos.ath.cx>
Standards-Version: 3.8.0
@@ -13,7 +13,7 @@
Package: trac
Architecture: all
-Depends: ${python:Depends}, python-setuptools (> 0.5), python-pysqlite2 (>= 2.3.2), python-subversion, subversion (>= 1.0.1), python-genshi (>= 0.5), libjs-jquery
+Depends: ${python:Depends}, python-setuptools (> 0.5), python (>= 2.5) | python-pysqlite2 (>= 2.3.2), python-subversion, subversion (>= 1.0.1), python-genshi (>= 0.5), libjs-jquery
Recommends: apache2 | httpd, python-pygments (>= 0.6) | enscript, python-tz
Suggests: python-docutils, libapache2-mod-wsgi | libapache2-mod-python, python-psycopg2, python-mysqldb (>= 1.2.1), python-textile (>= 2.0), trac-git, trac-spamfilter, trac-bzr (>= 0.2+bzr45), trac-mercurial (>= 0.11.0.4)
Conflicts: libapache2-mod-python2.3 (<< 3.2.8-3)
diff -u trac-0.11.1/debian/patches/00list trac-0.11.1/debian/patches/00list
--- trac-0.11.1/debian/patches/00list
+++ trac-0.11.1/debian/patches/00list
@@ -2,3 +2,2 @@
15_remove_jquery_file.dpatch
-16_install_contrib_dir.dpatch
17_SA32652.dpatch
reverted:
--- trac-0.11.1/debian/patches/16_install_contrib_dir.dpatch
+++ trac-0.11.1.orig/debian/patches/16_install_contrib_dir.dpatch
@@ -1,34 +0,0 @@
-#! /bin/sh /usr/share/dpatch/dpatch-run
-## 16_install_contrib_dir.dpatch by <gass@otiliamatos.ath.cx>
-##
-## All lines beginning with `## DP:' are a description of the patch.
-## DP: Installs the contrib directory from trac source
-
-@DPATCH@
-
-diff --git a/setup.py b/setup.py
-index 37e61fb..c1334c6 100755
---- a/setup.py
-+++ b/setup.py
-@@ -13,6 +13,9 @@
- # history and logs, available at http://trac.edgewall.org/log/.
-
- from setuptools import setup, find_packages
-+from glob import glob
-+
-+
-
- setup(
- name = 'Trac',
-@@ -48,7 +51,10 @@ facilities.
- 'trac.wiki': ['default-pages/*'],
- 'trac.ticket': ['workflows/*.ini'],
- },
--
-+ data_files=[(('/usr/share/doc/trac/contrib/'), glob('contrib/*.*')),
-+ (('/usr/share/doc/trac/contrib/workflow/'), glob('contrib/workflow/*')),
-+ (('/usr/share/doc/trac/contrib/rpm/'), glob('contrib/rpm/*'))
-+ ],
- test_suite = 'trac.test.suite',
- zip_safe = False,
-
only in patch2:
unchanged:
--- trac-0.11.1.orig/debian/install
+++ trac-0.11.1/debian/install
@@ -0,0 +1 @@
+contrib usr/share/doc/trac
only in patch2:
unchanged:
--- trac-0.11.1.orig/debian/patches/SA32652.dpatch
+++ trac-0.11.1/debian/patches/SA32652.dpatch
@@ -0,0 +1,2595 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## SA32652.dpatch by Giuseppe Iuculano <giuseppe@iuculano.it>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: No description.
+
+@DPATCH@
+diff -urNad trac-0.11.1~/trac/util/html.py trac-0.11.1/trac/util/html.py
+--- trac-0.11.1~/trac/util/html.py 2008-08-07 03:00:20.000000000 +0200
++++ trac-0.11.1/trac/util/html.py 2008-11-16 18:13:37.000000000 +0100
+@@ -14,10 +14,74 @@
+ import re
+
+ from genshi import Markup, escape, unescape
+-from genshi.core import stripentities, striptags
++from genshi.core import stripentities, striptags, START, END
+ from genshi.builder import Element, ElementFactory, Fragment
++from genshi.filters.html import HTMLSanitizer
+
+-__all__ = ['escape', 'unescape', 'html', 'plaintext']
++__all__ = ['escape', 'unescape', 'html', 'plaintext', 'TracHTMLSanitizer']
++
++
++class TracHTMLSanitizer(HTMLSanitizer):
++
++ UNSAFE_CSS = ['position']
++
++ def __init__(self):
++ safe_attrs = HTMLSanitizer.SAFE_ATTRS | set(['style'])
++ super(TracHTMLSanitizer, self).__init__(safe_attrs=safe_attrs)
++
++ def sanitize_css(self, text):
++ decls = []
++ text = self._strip_css_comments(self._replace_unicode_escapes(text))
++ for decl in filter(None, text.split(';')):
++ decl = decl.strip()
++ if not decl:
++ continue
++ try:
++ prop, value = decl.split(':', 1)
++ except ValueError:
++ continue
++ if not self.is_safe_css(prop.strip().lower(), value.strip()):
++ continue
++ is_evil = False
++ if 'expression' in decl:
++ is_evil = True
++ for match in re.finditer(r'url\s*\(([^)]+)', decl):
++ if not self.is_safe_uri(match.group(1)):
++ is_evil = True
++ break
++ if not is_evil:
++ decls.append(decl.strip())
++ return decls
++
++ def __call__(self, stream):
++ """Remove input type="password" elements from the stream
++ """
++ suppress = False
++ for kind, data, pos in super(TracHTMLSanitizer, self).__call__(stream):
++ if kind is START:
++ tag, attrs = data
++ if (tag == 'input' and
++ attrs.get('type', '').lower() == 'password'):
++ suppress = True
++ else:
++ yield kind, data, pos
++ elif kind is END:
++ if not suppress:
++ yield kind, data, pos
++ suppress = False
++ else:
++ yield kind, data, pos
++
++ def is_safe_css(self, prop, value):
++ """Determine whether the given css property declaration is to be
++ considered safe for inclusion in the output.
++ """
++ if prop in self.UNSAFE_CSS:
++ return False
++ # Negative margins can be used for phishing
++ elif prop.startswith('margin') and '-' in value:
++ return False
++ return True
+
+
+ class Deuglifier(object):
+diff -urNad trac-0.11.1~/trac/wiki/formatter.py trac-0.11.1/trac/wiki/formatter.py
+--- trac-0.11.1~/trac/wiki/formatter.py 2008-08-07 03:00:20.000000000 +0200
++++ trac-0.11.1/trac/wiki/formatter.py 2008-11-16 18:15:09.000000000 +0100
+@@ -26,7 +26,6 @@
+
+ from genshi.builder import tag, Element
+ from genshi.core import Stream, Markup, escape
+-from genshi.filters import HTMLSanitizer
+ from genshi.input import HTMLParser, ParseError
+ from genshi.util import plaintext
+
+@@ -38,6 +37,7 @@
+ from trac.wiki.parser import WikiParser
+ from trac.util.text import shorten_line, to_unicode, \
+ unicode_quote, unicode_quote_plus
++from trac.util.html import TracHTMLSanitizer
+ from trac.util.translation import _
+
+ __all__ = ['wiki_to_html', 'wiki_to_oneliner', 'wiki_to_outline',
+@@ -86,8 +86,7 @@
+ 'span': self._span_processor,
+ 'Span': self._span_processor}
+
+- self._sanitizer = HTMLSanitizer(safe_attrs=HTMLSanitizer.SAFE_ATTRS |
+- set(['style']))
++ self._sanitizer = TracHTMLSanitizer()
+
+ self.processor = builtin_processors.get(name)
+ if not self.processor:
+diff -urNad trac-0.11.1~/trac/wiki/formatter.py.orig trac-0.11.1/trac/wiki/formatter.py.orig
+--- trac-0.11.1~/trac/wiki/formatter.py.orig 1970-01-01 01:00:00.000000000 +0100
++++ trac-0.11.1/trac/wiki/formatter.py.orig 2008-08-07 03:00:20.000000000 +0200
+@@ -0,0 +1,1139 @@
++# -*- coding: utf-8 -*-
++#
++# Copyright (C) 2003-2008 Edgewall Software
++# Copyright (C) 2003-2005 Jonas Borgström <jonas@edgewall.com>
++# Copyright (C) 2004-2005 Christopher Lenz <cmlenz@gmx.de>
++# Copyright (C) 2005-2007 Christian Boos <cboos@neuf.fr>
++# All rights reserved.
++#
++# This software is licensed as described in the file COPYING, which
++# you should have received as part of this distribution. The terms
++# are also available at http://trac.edgewall.org/wiki/TracLicense.
++#
++# This software consists of voluntary contributions made by many
++# individuals. For the exact contribution history, see the revision
++# history and logs, available at http://trac.edgewall.org/log/.
++#
++# Author: Jonas Borgström <jonas@edgewall.com>
++# Christopher Lenz <cmlenz@gmx.de>
++# Christian Boos <cboos@neuf.fr>
++
++import re
++import os
++import urllib
++
++from StringIO import StringIO
++
++from genshi.builder import tag, Element
++from genshi.core import Stream, Markup, escape
++from genshi.filters import HTMLSanitizer
++from genshi.input import HTMLParser, ParseError
++from genshi.util import plaintext
++
++from trac.core import *
++from trac.mimeview import *
++from trac.resource import get_relative_url
++from trac.util.compat import set
++from trac.wiki.api import WikiSystem, parse_args
++from trac.wiki.parser import WikiParser
++from trac.util.text import shorten_line, to_unicode, \
++ unicode_quote, unicode_quote_plus
++from trac.util.translation import _
++
++__all__ = ['wiki_to_html', 'wiki_to_oneliner', 'wiki_to_outline',
++ 'Formatter', 'format_to', 'format_to_html', 'format_to_oneliner',
++ 'extract_link']
++
++def system_message(msg, text=None):
++ return tag.div(tag.strong(msg), text and tag.pre(text),
++ class_="system-message")
++
++def _markup_to_unicode(markup):
++ stream = None
++ if isinstance(markup, Element):
++ stream = markup.generate()
++ elif isinstance(markup, Stream):
++ stream = markup
++ if stream:
++ markup = stream.render('xhtml', encoding=None, strip_whitespace=False)
++ return to_unicode(markup)
++
++
++class WikiProcessor(object):
++
++ _code_block_re = re.compile('^<div(?:\s+class="([^"]+)")?>(.*)</div>$')
++
++ def __init__(self, formatter, name, args={}):
++ """Find the processor by name
++
++ :param formatter: the formatter embedding a call for this processor
++ :param name: the name of the processor
++ :param args: extra parameters for the processor
++
++ (since 0.11)
++ """
++ self.formatter = formatter
++ self.env = formatter.env
++ self.name = name
++ self.args = args
++ self.error = None
++ self.macro_provider = None
++
++ builtin_processors = {'html': self._html_processor,
++ 'default': self._default_processor,
++ 'comment': self._comment_processor,
++ 'div': self._div_processor,
++ 'span': self._span_processor,
++ 'Span': self._span_processor}
++
++ self._sanitizer = HTMLSanitizer(safe_attrs=HTMLSanitizer.SAFE_ATTRS |
++ set(['style']))
++
++ self.processor = builtin_processors.get(name)
++ if not self.processor:
++ # Find a matching wiki macro
++ for macro_provider in WikiSystem(self.env).macro_providers:
++ for macro_name in macro_provider.get_macros():
++ if self.name == macro_name:
++ if hasattr(macro_provider, 'expand_macro'):
++ self.processor = self._macro_processor
++ else:
++ self.processor = self._legacy_macro_processor
++ self.macro_provider = macro_provider
++ break
++ if not self.processor:
++ # Find a matching mimeview renderer
++ from trac.mimeview.api import Mimeview
++ mimetype = Mimeview(formatter.env).get_mimetype(self.name)
++ if mimetype:
++ self.name = mimetype
++ self.processor = self._mimeview_processor
++ else:
++ self.processor = self._default_processor
++ self.error = "No macro or processor named '%s' found" % name
++
++ # builtin processors
++
++ def _comment_processor(self, text):
++ return ''
++
++ def _default_processor(self, text):
++ return tag.pre(text, class_="wiki")
++
++ def _html_processor(self, text):
++ if WikiSystem(self.env).render_unsafe_content:
++ return Markup(text)
++ try:
++ stream = Stream(HTMLParser(StringIO(text)))
++ return (stream | self._sanitizer).render('xhtml', encoding=None)
++ except ParseError, e:
++ self.env.log.warn(e)
++ line = unicode(text).splitlines()[e.lineno - 1].strip()
++ return system_message(_('HTML parsing error: %(message)s',
++ message=escape(e.msg)), line)
++
++ def _elt_processor(self, eltname, format_to, text, args):
++ elt = getattr(tag, eltname)(**args)
++ if not WikiSystem(self.env).render_unsafe_content:
++ sanitized_elt = getattr(tag, eltname)
++ for (k,data,pos) in (Stream(elt) | self._sanitizer):
++ sanitized_elt.attrib = data[1]
++ break # only look at START (elt,attrs)
++ elt = sanitized_elt
++ elt.append(format_to(self.env, self.formatter.context, text))
++ return elt
++
++ def _div_processor(self, text):
++ return self._elt_processor('div', format_to_html, text, self.args)
++
++ def _span_processor(self, text):
++ args, kwargs = parse_args(text, strict=True)
++ return self._elt_processor('span', format_to_oneliner, ', '.join(args),
++ kwargs)
++
++ # generic processors
++
++ def _legacy_macro_processor(self, text): # TODO: remove in 0.12
++ self.env.log.warning('Executing pre-0.11 Wiki macro %s by provider %s'
++ % (self.name, self.macro_provider))
++ return self.macro_provider.render_macro(self.formatter.req, self.name,
++ text)
++
++ def _macro_processor(self, text):
++ self.env.log.debug('Executing Wiki macro %s by provider %s'
++ % (self.name, self.macro_provider))
++ return self.macro_provider.expand_macro(self.formatter, self.name,
++ text)
++
++ def _mimeview_processor(self, text):
++ return Mimeview(self.env).render(self.formatter.context,
++ self.name, text)
++ # TODO: use convert('text/html') instead of render
++
++ def process(self, text, in_paragraph=False):
++ if self.error:
++ text = system_message(tag('Error: Failed to load processor ',
++ tag.code(self.name)),
++ self.error)
++ else:
++ text = self.processor(text)
++ if not text:
++ return ''
++ if in_paragraph:
++ content_for_span = None
++ interrupt_paragraph = False
++ if isinstance(text, Element):
++ tagname = text.tag.lower()
++ if tagname == 'div':
++ class_ = text.attrib.get('class', '')
++ if class_ and 'code' in class_:
++ content_for_span = text.children
++ else:
++ interrupt_paragraph = True
++ elif tagname == 'table':
++ interrupt_paragraph = True
++ else:
++ text = to_unicode(text)
++ match = re.match(self._code_block_re, unicode(text))
++ if match:
++ if match.group(1) and 'code' in match.group(1):
++ content_for_span = match.group(2)
++ else:
++ interrupt_paragraph = True
++ elif text.startswith('<table'):
++ interrupt_paragraph = True
++ if content_for_span:
++ text = tag.span(class_='code-block')(*content_for_span)
++ elif interrupt_paragraph:
++ text = "</p>%s<p>" % to_unicode(text)
++ return text
++
++
++class Formatter(object):
++ """Base Wiki formatter.
++
++ Parses and formats wiki text, in a given `Context`.
++ """
++
++ flavor = 'default'
++
++ # 0.10 compatibility
++ INTERTRAC_SCHEME = WikiParser.INTERTRAC_SCHEME
++ QUOTED_STRING = WikiParser.QUOTED_STRING
++ LINK_SCHEME = WikiParser.LINK_SCHEME
++
++ def __init__(self, env, context):
++ """Note: `req` is still temporarily used."""
++ self.env = env
++ self.context = context
++ self.req = context.req
++ self.href = context.href
++ self.resource = context.resource
++ self.perm = context.perm
++ self.db = self.env.get_db_cnx() # FIXME: remove
++ self.wiki = WikiSystem(self.env)
++ self.wikiparser = WikiParser(self.env)
++ self._anchors = {}
++ self._open_tags = []
++
++ def split_link(self, target):
++ """Split a target along "?" and "#" in `(path, query, fragment)`."""
++ query = fragment = ''
++ idx = target.find('#')
++ if idx >= 0:
++ target, fragment = target[:idx], target[idx:]
++ idx = target.find('?')
++ if idx >= 0:
++ target, query = target[:idx], target[idx:]
++ return (target, query, fragment)
++
++ # -- Pre- IWikiSyntaxProvider rules (Font styles)
++
++ def tag_open_p(self, tag):
++ """Do we currently have any open tag with `tag` as end-tag?"""
++ return tag in self._open_tags
++
++ def close_tag(self, tag):
++ tmp = ''
++ for i in xrange(len(self._open_tags)-1, -1, -1):
++ tmp += self._open_tags[i][1]
++ if self._open_tags[i][1] == tag:
++ del self._open_tags[i]
++ for j in xrange(i, len(self._open_tags)):
++ tmp += self._open_tags[j][0]
++ break
++ return tmp
++
++ def open_tag(self, open, close):
++ self._open_tags.append((open, close))
++
++ def simple_tag_handler(self, match, open_tag, close_tag):
++ """Generic handler for simple binary style tags"""
++ if self.tag_open_p((open_tag, close_tag)):
++ return self.close_tag(close_tag)
++ else:
++ self.open_tag(open_tag, close_tag)
++ return open_tag
++
++ def _bolditalic_formatter(self, match, fullmatch):
++ italic = ('<i>', '</i>')
++ italic_open = self.tag_open_p(italic)
++ tmp = ''
++ if italic_open:
++ tmp += italic[1]
++ self.close_tag(italic[1])
++ tmp += self._bold_formatter(match, fullmatch)
++ if not italic_open:
++ tmp += italic[0]
++ self.open_tag(*italic)
++ return tmp
++
++ def _bold_formatter(self, match, fullmatch):
++ return self.simple_tag_handler(match, '<strong>', '</strong>')
++
++ def _italic_formatter(self, match, fullmatch):
++ return self.simple_tag_handler(match, '<i>', '</i>')
++
++ def _underline_formatter(self, match, fullmatch):
++ return self.simple_tag_handler(match, '<span class="underline">',
++ '</span>')
++
++ def _strike_formatter(self, match, fullmatch):
++ return self.simple_tag_handler(match, '<del>', '</del>')
++
++ def _subscript_formatter(self, match, fullmatch):
++ return self.simple_tag_handler(match, '<sub>', '</sub>')
++
++ def _superscript_formatter(self, match, fullmatch):
++ return self.simple_tag_handler(match, '<sup>', '</sup>')
++
++ def _inlinecode_formatter(self, match, fullmatch):
++ return tag.tt(fullmatch.group('inline'))
++
++ def _inlinecode2_formatter(self, match, fullmatch):
++ return tag.tt(fullmatch.group('inline2'))
++
++ # -- Post- IWikiSyntaxProvider rules
++
++ # E-mails
++
++ def _email_formatter(self, match, fullmatch):
++ from trac.web.chrome import Chrome
++ omatch = Chrome(self.env).format_emails(self.context, match)
++ if omatch == match: # not obfuscated, make a link
++ return self._make_mail_link('mailto:'+match, match)
++ else:
++ return omatch
++
++ # HTML escape of &, < and >
++
++ def _htmlescape_formatter(self, match, fullmatch):
++ return match == "&" and "&" or match == "<" and "<" or ">"
++
++ # Short form (shref) and long form (lhref) of TracLinks
++
++ def _unquote(self, text):
++ if text and text[0] in "'\"" and text[0] == text[-1]:
++ return text[1:-1]
++ else:
++ return text
++
++ def _shref_formatter(self, match, fullmatch):
++ ns = fullmatch.group('sns')
++ target = self._unquote(fullmatch.group('stgt'))
++ return self._make_link(ns, target, match, match, fullmatch)
++
++ def _lhref_formatter(self, match, fullmatch):
++ rel = fullmatch.group('rel')
++ ns = fullmatch.group('lns')
++ target = self._unquote(fullmatch.group('ltgt'))
++ label = fullmatch.group('label')
++ if not label: # e.g. `[http://target]` or `[wiki:target]`
++ if target:
++ if target.startswith('//'): # for `[http://target]`
++ label = ns+':'+target # use `http://target`
++ else: # for `wiki:target`
++ label = target # use only `target`
++ else: # e.g. `[search:]`
++ label = ns
++ else:
++ label = self._unquote(label)
++ if rel:
++ path, query, fragment = self.split_link(rel)
++ if path.startswith('//'):
++ path = '/' + path.lstrip('/')
++ elif path.startswith('/'):
++ path = self.href(path)
++ else:
++ path = get_relative_url(self.env, self.resource, self.href,
++ path)
++ if '?' in path and query:
++ query = '&' + query.lstrip('?')
++ return tag.a(label or rel, href=path + query + fragment)
++ else:
++ return self._make_link(ns, target, match, label, fullmatch)
++
++ def _make_link(self, ns, target, match, label, fullmatch):
++ # first check for an alias defined in trac.ini
++ ns = self.env.config['intertrac'].get(ns, ns)
++ if ns in self.wikiparser.link_resolvers:
++ return self.wikiparser.link_resolvers[ns](self, ns, target,
++ escape(label, False))
++ elif target.startswith('//'):
++ return self._make_ext_link(ns+':'+target, label)
++ elif ns == "mailto":
++ from trac.web.chrome import Chrome
++ otarget = Chrome(self.env).format_emails(self.context, target)
++ olabel = Chrome(self.env).format_emails(self.context, label)
++ if (otarget, olabel) == (target, label):
++ return self._make_mail_link('mailto:'+target, label)
++ else:
++ return olabel or otarget
++ else:
++ if label == target and not fullmatch.group('label'):
++ # add ns for Inter* links when nothing is set
++ label = ns+':'+label
++ return self._make_intertrac_link(ns, target, label) or \
++ self._make_interwiki_link(ns, target, label) or \
++ escape(match)
++
++ def _make_intertrac_link(self, ns, target, label):
++ intertrac = self.env.config['intertrac']
++ url = intertrac.get(ns+'.url')
++ if not url and ns == 'trac':
++ url = 'http://trac.edgewall.org'
++ if url:
++ name = intertrac.get(ns+'.title', 'Trac project %s' % ns)
++ compat = intertrac.getbool(ns+'.compat', 'false')
++ # set `compat` default to False now that 0.10 is widely used
++ # TODO: remove compatibility code completely for 1.0 release
++ if compat:
++ sep = target.find(':')
++ if sep != -1:
++ url = '%s/%s/%s' % (url, target[:sep], target[sep + 1:])
++ else:
++ url = '%s/search?q=%s' % (url, unicode_quote_plus(target))
++ else:
++ url = '%s/intertrac/%s' % (url, unicode_quote(target))
++ if target:
++ title = '%s in %s' % (target, name)
++ else:
++ title = name
++ return self._make_ext_link(url, label, title)
++ else:
++ return None
++
++ def shorthand_intertrac_helper(self, ns, target, label, fullmatch):
++ if fullmatch: # short form
++ it_group = fullmatch.group('it_%s' % ns)
++ if it_group:
++ alias = it_group.strip()
++ intertrac = self.env.config['intertrac']
++ target = '%s:%s' % (ns, target[len(it_group):])
++ return self._make_intertrac_link(intertrac.get(alias, alias),
++ target, label) or label
++ return None
++
++ def _make_interwiki_link(self, ns, target, label):
++ from trac.wiki.interwiki import InterWikiMap
++ interwiki = InterWikiMap(self.env)
++ if ns in interwiki:
++ url, title = interwiki.url(ns, target)
++ return self._make_ext_link(url, label, title)
++ else:
++ return None
++
++ def _make_ext_link(self, url, text, title=''):
++ local_url = self.env.config.get('project', 'url') or \
++ (self.req or self.env).abs_href.base
++ if not url.startswith(local_url):
++ return tag.a(tag.span(text, class_="icon"),
++ class_="ext-link", href=url, title=title or None)
++ else:
++ return tag.a(text, href=url, title=title or None)
++
++ def _make_mail_link(self, url, text, title=''):
++ return tag.a(tag.span(text, class_="icon"),
++ class_="mail-link", href=url, title=title or None)
++
++ # WikiMacros
++
++ def _macro_formatter(self, match, fullmatch):
++ name = fullmatch.group('macroname')
++ if name.lower() == 'br':
++ return '<br />'
++ args = fullmatch.group('macroargs')
++ try:
++ macro = WikiProcessor(self, name)
++ return macro.process(args, in_paragraph=True)
++ except Exception, e:
++ self.env.log.error('Macro %s(%s) failed' % (name, args),
++ exc_info=True)
++ return system_message('Error: Macro %s(%s) failed' % (name, args),
++ e)
++
++ # Headings
++
++ def _parse_heading(self, match, fullmatch, shorten):
++ match = match.strip()
++
++ depth = min(len(fullmatch.group('hdepth')), 5)
++ anchor = fullmatch.group('hanchor') or ''
++ heading_text = match[depth+1:-depth-1-len(anchor)]
++ heading = format_to_oneliner(self.env, self.context, heading_text,
++ False)
++ if anchor:
++ anchor = anchor[1:]
++ else:
++ sans_markup = plaintext(heading, keeplinebreaks=False)
++ anchor = WikiParser._anchor_re.sub('', sans_markup)
++ if not anchor or anchor[0].isdigit() or anchor[0] in '.-':
++ # an ID must start with a Name-start character in XHTML
++ anchor = 'a' + anchor # keeping 'a' for backward compat
++ i = 1
++ anchor_base = anchor
++ while anchor in self._anchors:
++ anchor = anchor_base + str(i)
++ i += 1
++ self._anchors[anchor] = True
++ if shorten:
++ heading = format_to_oneliner(self.env, self.context, heading_text,
++ True)
++ return (depth, heading, anchor)
++
++ def _heading_formatter(self, match, fullmatch):
++ self.close_table()
++ self.close_paragraph()
++ self.close_indentation()
++ self.close_list()
++ self.close_def_list()
++ depth, heading, anchor = self._parse_heading(match, fullmatch, False)
++ self.out.write('<h%d id="%s">%s</h%d>' %
++ (depth, anchor, heading, depth))
++
++ # Generic indentation (as defined by lists and quotes)
++
++ def _set_tab(self, depth):
++ """Append a new tab if needed and truncate tabs deeper than `depth`
++
++ given: -*-----*--*---*--
++ setting: *
++ results in: -*-----*-*-------
++ """
++ tabstops = []
++ for ts in self._tabstops:
++ if ts >= depth:
++ break
++ tabstops.append(ts)
++ tabstops.append(depth)
++ self._tabstops = tabstops
++
++ # Lists
++
++ def _list_formatter(self, match, fullmatch):
++ ldepth = len(fullmatch.group('ldepth'))
++ listid = match[ldepth]
++ self.in_list_item = True
++ class_ = start = None
++ if listid in '-*':
++ type_ = 'ul'
++ else:
++ type_ = 'ol'
++ idx = '01iI'.find(listid)
++ if idx >= 0:
++ class_ = ('arabiczero', None, 'lowerroman', 'upperroman')[idx]
++ elif listid.isdigit():
++ start = match[ldepth:match.find('.')]
++ elif listid.islower():
++ class_ = 'loweralpha'
++ elif listid.isupper():
++ class_ = 'upperalpha'
++ self._set_list_depth(ldepth, type_, class_, start)
++ return ''
++
++ def _get_list_depth(self):
++ """Return the space offset associated to the deepest opened list."""
++ return self._list_stack and self._list_stack[-1][1] or 0
++
++ def _set_list_depth(self, depth, new_type, list_class, start):
++ def open_list():
++ self.close_table()
++ self.close_paragraph()
++ self.close_indentation() # FIXME: why not lists in quotes?
++ self._list_stack.append((new_type, depth))
++ self._set_tab(depth)
++ class_attr = (list_class and ' class="%s"' % list_class) or ''
++ start_attr = (start and ' start="%s"' % start) or ''
++ self.out.write('<'+new_type+class_attr+start_attr+'><li>')
++ def close_list(tp):
++ self._list_stack.pop()
++ self.out.write('</li></%s>' % tp)
++
++ # depending on the indent/dedent, open or close lists
++ if depth > self._get_list_depth():
++ open_list()
++ else:
++ while self._list_stack:
++ deepest_type, deepest_offset = self._list_stack[-1]
++ if depth >= deepest_offset:
++ break
++ close_list(deepest_type)
++ if depth > 0:
++ if self._list_stack:
++ old_type, old_offset = self._list_stack[-1]
++ if new_type and old_type != new_type:
++ close_list(old_type)
++ open_list()
++ else:
++ if old_offset != depth: # adjust last depth
++ self._list_stack[-1] = (old_type, depth)
++ self.out.write('</li><li>')
++ else:
++ open_list()
++
++ def close_list(self):
++ self._set_list_depth(0, None, None, None)
++
++ # Definition Lists
++
++ def _definition_formatter(self, match, fullmatch):
++ tmp = self.in_def_list and '</dd>' or '<dl>'
++ definition = match[:match.find('::')]
++ tmp += '<dt>%s</dt><dd>' % format_to_oneliner(self.env, self.context,
++ definition)
++ self.in_def_list = True
++ return tmp
++
++ def close_def_list(self):
++ if self.in_def_list:
++ self.out.write('</dd></dl>\n')
++ self.in_def_list = False
++
++ # Blockquote
++
++ def _indent_formatter(self, match, fullmatch):
++ idepth = len(fullmatch.group('idepth'))
++ if self._list_stack:
++ ltype, ldepth = self._list_stack[-1]
++ if idepth < ldepth:
++ for _, ldepth in self._list_stack:
++ if idepth > ldepth:
++ self.in_list_item = True
++ self._set_list_depth(idepth, None, None, None)
++ return ''
++ elif idepth <= ldepth + (ltype == 'ol' and 3 or 2):
++ self.in_list_item = True
++ return ''
++ if not self.in_def_list:
++ self._set_quote_depth(idepth)
++ return ''
++
++ def _citation_formatter(self, match, fullmatch):
++ cdepth = len(fullmatch.group('cdepth').replace(' ', ''))
++ self._set_quote_depth(cdepth, True)
++ return ''
++
++ def close_indentation(self):
++ self._set_quote_depth(0)
++
++ def _get_quote_depth(self):
++ """Return the space offset associated to the deepest opened quote."""
++ return self._quote_stack and self._quote_stack[-1] or 0
++
++ def _set_quote_depth(self, depth, citation=False):
++ def open_quote(depth):
++ self.close_table()
++ self.close_paragraph()
++ self.close_list()
++ def open_one_quote(d):
++ self._quote_stack.append(d)
++ self._set_tab(d)
++ class_attr = citation and ' class="citation"' or ''
++ self.out.write('<blockquote%s>' % class_attr + os.linesep)
++ if citation:
++ for d in range(quote_depth+1, depth+1):
++ open_one_quote(d)
++ else:
++ open_one_quote(depth)
++ def close_quote():
++ self.close_table()
++ self.close_paragraph()
++ self._quote_stack.pop()
++ self.out.write('</blockquote>' + os.linesep)
++ quote_depth = self._get_quote_depth()
++ if depth > quote_depth:
++ self._set_tab(depth)
++ tabstops = self._tabstops[::-1]
++ while tabstops:
++ tab = tabstops.pop()
++ if tab > quote_depth:
++ open_quote(tab)
++ else:
++ while self._quote_stack:
++ deepest_offset = self._quote_stack[-1]
++ if depth >= deepest_offset:
++ break
++ close_quote()
++ if not citation and depth > 0:
++ if self._quote_stack:
++ old_offset = self._quote_stack[-1]
++ if old_offset != depth: # adjust last depth
++ self._quote_stack[-1] = depth
++ else:
++ open_quote(depth)
++ if depth > 0:
++ self.in_quote = True
++
++ # Table
++
++ def _last_table_cell_formatter(self, match, fullmatch):
++ return ''
++
++ def _table_cell_formatter(self, match, fullmatch):
++ self.open_table()
++ self.open_table_row()
++ if self.in_table_cell:
++ return '</td><td>'
++ else:
++ self.in_table_cell = 1
++ return '<td>'
++
++ def open_table(self):
++ if not self.in_table:
++ self.close_paragraph()
++ self.close_list()
++ self.close_def_list()
++ self.in_table = 1
++ self.out.write('<table class="wiki">' + os.linesep)
++
++ def open_table_row(self):
++ if not self.in_table_row:
++ self.open_table()
++ self.in_table_row = 1
++ self.out.write('<tr>')
++
++ def close_table_row(self):
++ if self.in_table_row:
++ self.in_table_row = 0
++ if self.in_table_cell:
++ self.in_table_cell = 0
++ self.out.write('</td>')
++
++ self.out.write('</tr>')
++
++ def close_table(self):
++ if self.in_table:
++ self.close_table_row()
++ self.out.write('</table>' + os.linesep)
++ self.in_table = 0
++
++ # Paragraphs
++
++ def open_paragraph(self):
++ if not self.paragraph_open:
++ self.out.write('<p>' + os.linesep)
++ self.paragraph_open = 1
++
++ def close_paragraph(self):
++ if self.paragraph_open:
++ while self._open_tags != []:
++ self.out.write(self._open_tags.pop()[1])
++ self.out.write('</p>' + os.linesep)
++ self.paragraph_open = 0
++
++ # Code blocks
++
++ def handle_code_block(self, line):
++ if line.strip() == WikiParser.STARTBLOCK:
++ self.in_code_block += 1
++ if self.in_code_block == 1:
++ self.code_processor = None
++ self.code_buf = []
++ else:
++ self.code_buf.append(line)
++ if not self.code_processor:
++ self.code_processor = WikiProcessor(self, 'default')
++ elif line.strip() == WikiParser.ENDBLOCK:
++ self.in_code_block -= 1
++ if self.in_code_block == 0 and self.code_processor:
++ self.close_table()
++ self.close_paragraph()
++ if self.code_buf:
++ self.code_buf.append('')
++ code_text = os.linesep.join(self.code_buf)
++ processed = self.code_processor.process(code_text)
++ self.out.write(_markup_to_unicode(processed))
++
++ else:
++ self.code_buf.append(line)
++ elif not self.code_processor:
++ match = WikiParser._processor_re.match(line)
++ if match:
++ name = match.group(1)
++ args = WikiParser._processor_param_re.split(line[len(name):])
++ del args[::3]
++ keys = [str(k) for k in args[::2]] # used as keyword parameters
++ values = [v and v[0] in '"\'' and v[1:-1] or v
++ for v in args[1::2]]
++ args = dict(zip(keys, values))
++ self.code_processor = WikiProcessor(self, name, args)
++ else:
++ self.code_buf.append(line)
++ self.code_processor = WikiProcessor(self, 'default')
++ else:
++ self.code_buf.append(line)
++
++ def close_code_blocks(self):
++ while self.in_code_block > 0:
++ self.handle_code_block(WikiParser.ENDBLOCK)
++
++ # -- Wiki engine
++
++ def handle_match(self, fullmatch):
++ for itype, match in fullmatch.groupdict().items():
++ if match and not itype in self.wikiparser.helper_patterns:
++ # Check for preceding escape character '!'
++ if match[0] == '!':
++ return escape(match[1:])
++ if itype in self.wikiparser.external_handlers:
++ external_handler = self.wikiparser.external_handlers[itype]
++ return external_handler(self, match, fullmatch)
++ else:
++ internal_handler = getattr(self, '_%s_formatter' % itype)
++ return internal_handler(match, fullmatch)
++
++ def replace(self, fullmatch):
++ """Replace one match with its corresponding expansion"""
++ replacement = self.handle_match(fullmatch)
++ if replacement:
++ return _markup_to_unicode(replacement)
++
++ def reset(self, source, out=None):
++ self.source = source
++ class NullOut(object):
++ def write(self, data): pass
++ self.out = out or NullOut()
++ self._open_tags = []
++ self._list_stack = []
++ self._quote_stack = []
++ self._tabstops = []
++
++ self.in_code_block = 0
++ self.in_table = 0
++ self.in_def_list = 0
++ self.in_table_row = 0
++ self.in_table_cell = 0
++ self.paragraph_open = 0
++
++ def format(self, text, out=None, escape_newlines=False):
++ self.reset(text, out)
++ for line in text.splitlines():
++ # Handle code block
++ if self.in_code_block or line.strip() == WikiParser.STARTBLOCK:
++ self.handle_code_block(line)
++ continue
++ # Handle Horizontal ruler
++ elif line[0:4] == '----':
++ self.close_table()
++ self.close_paragraph()
++ self.close_indentation()
++ self.close_list()
++ self.close_def_list()
++ self.out.write('<hr />' + os.linesep)
++ continue
++ # Handle new paragraph
++ elif line == '':
++ self.close_paragraph()
++ self.close_indentation()
++ self.close_list()
++ self.close_def_list()
++ continue
++
++ # Tab expansion and clear tabstops if no indent
++ line = line.replace('\t', ' '*8)
++ if not line.startswith(' '):
++ self._tabstops = []
++
++ self.in_list_item = False
++ self.in_quote = False
++ # Throw a bunch of regexps on the problem
++ result = re.sub(self.wikiparser.rules, self.replace, line)
++
++ if not self.in_list_item:
++ self.close_list()
++
++ if not self.in_quote:
++ self.close_indentation()
++
++ if self.in_def_list and not line.startswith(' '):
++ self.close_def_list()
++
++ if self.in_table and not line.lstrip().startswith('||'):
++ self.close_table()
++
++ sep = os.linesep
++ if not(self.in_list_item or self.in_def_list or self.in_table):
++ if len(result):
++ self.open_paragraph()
++ if escape_newlines and not result.rstrip().endswith('<br />'):
++ sep = '<br />' + sep
++ self.out.write(result + sep)
++ self.close_table_row()
++
++ self.close_table()
++ self.close_paragraph()
++ self.close_indentation()
++ self.close_list()
++ self.close_def_list()
++ self.close_code_blocks()
++
++
++class OneLinerFormatter(Formatter):
++ """
++ A special version of the wiki formatter that only implement a
++ subset of the wiki formatting functions. This version is useful
++ for rendering short wiki-formatted messages on a single line
++ """
++ flavor = 'oneliner'
++
++ def __init__(self, env, context):
++ Formatter.__init__(self, env, context)
++
++ # Override a few formatters to disable some wiki syntax in "oneliner"-mode
++ def _list_formatter(self, match, fullmatch): return match
++ def _indent_formatter(self, match, fullmatch): return match
++ def _citation_formatter(self, match, fullmatch):
++ return escape(match, False)
++ def _heading_formatter(self, match, fullmatch):
++ return escape(match, False)
++ def _definition_formatter(self, match, fullmatch):
++ return escape(match, False)
++ def _table_cell_formatter(self, match, fullmatch): return match
++ def _last_table_cell_formatter(self, match, fullmatch): return match
++
++ def _macro_formatter(self, match, fullmatch):
++ name = fullmatch.group('macroname')
++ if name.lower() == 'br':
++ return ' '
++ elif name == 'comment':
++ return ''
++ else:
++ args = fullmatch.group('macroargs')
++ return '[[%s%s]]' % (name, args and '(...)' or '')
++
++ def format(self, text, out, shorten=False):
++ if not text:
++ return
++ self.reset(text, out)
++
++ # Simplify code blocks
++ in_code_block = 0
++ processor = None
++ buf = StringIO()
++ for line in text.strip().splitlines():
++ if line.strip() == WikiParser.STARTBLOCK:
++ in_code_block += 1
++ elif line.strip() == WikiParser.ENDBLOCK:
++ if in_code_block:
++ in_code_block -= 1
++ if in_code_block == 0:
++ if processor != 'comment':
++ buf.write(' [...]' + os.linesep)
++ processor = None
++ elif in_code_block:
++ if not processor:
++ if line.startswith('#!'):
++ processor = line[2:].strip()
++ else:
++ buf.write(line + os.linesep)
++ result = buf.getvalue()[:-len(os.linesep)]
++
++ if shorten:
++ result = shorten_line(result)
++
++ result = re.sub(self.wikiparser.rules, self.replace, result)
++ result = result.replace('[...]', u'[\u2026]')
++ if result.endswith('...'):
++ result = result[:-3] + u'\u2026'
++
++ # Close all open 'one line'-tags
++ result += self.close_tag(None)
++ # Flush unterminated code blocks
++ if in_code_block > 0:
++ result += u'[\u2026]'
++ out.write(result)
++
++
++class OutlineFormatter(Formatter):
++ """Special formatter that generates an outline of all the headings."""
++ flavor = 'outline'
++
++ def __init__(self, env, context):
++ Formatter.__init__(self, env, context)
++
++ # Avoid the possible side-effects of rendering WikiProcessors
++
++ def _macro_formatter(self, match, fullmatch):
++ return ''
++
++ def handle_code_block(self, line):
++ if line.strip() == WikiParser.STARTBLOCK:
++ self.in_code_block += 1
++ elif line.strip() == WikiParser.ENDBLOCK:
++ self.in_code_block -= 1
++
++ def format(self, text, out, max_depth=6, min_depth=1):
++ self.outline = []
++ Formatter.format(self, text)
++
++ if min_depth > max_depth:
++ min_depth, max_depth = max_depth, min_depth
++ max_depth = min(6, max_depth)
++ min_depth = max(1, min_depth)
++
++ curr_depth = min_depth - 1
++ for depth, anchor, text in self.outline:
++ if depth < min_depth or depth > max_depth:
++ continue
++ if depth < curr_depth:
++ out.write('</li></ol>' * (curr_depth - depth))
++ out.write("</li><li>\n")
++ elif depth > curr_depth:
++ out.write('<ol><li>' * (depth - curr_depth))
++ else:
++ out.write("</li><li>\n")
++ curr_depth = depth
++ out.write('<a href="#%s">%s</a>' % (anchor, text))
++ out.write('</li></ol>' * curr_depth)
++
++ def _heading_formatter(self, match, fullmatch):
++ depth, heading, anchor = self._parse_heading(match, fullmatch, True)
++ heading = re.sub(r'</?a(?: .*?)?>', '', heading) # Strip out link tags
++ self.outline.append((depth, anchor, heading))
++
++
++class LinkFormatter(OutlineFormatter):
++ """Special formatter that focuses on TracLinks."""
++ flavor = 'link'
++
++ def __init__(self, env, context):
++ OutlineFormatter.__init__(self, env, context)
++
++ def _heading_formatter(self, match, fullmatch):
++ return ''
++
++ def match(self, wikitext):
++ """Return the Wiki match found at the beginning of the `wikitext`"""
++ self.reset(wikitext)
++ match = re.match(self.wikiparser.rules, wikitext)
++ if match:
++ return self.handle_match(match)
++
++
++# Pure Wiki Formatter
++
++class HtmlFormatter(object):
++ """Format parsed wiki text to HTML"""
++
++ flavor = 'default'
++
++ def __init__(self, env, context, wikidom):
++ self.env = env
++ self.context = context
++ if isinstance(wikidom, basestring):
++ wikidom = WikiParser(env).parse(wikidom)
++ self.wikidom = wikidom
++
++ def generate(self, escape_newlines=False):
++ """Generate HTML elements.
++
++ newlines in the wikidom will be preserved if `escape_newlines` is set.
++ """
++ # FIXME: compatibility code only for now
++ out = StringIO()
++ Formatter(self.env, self.context).format(self.wikidom, out,
++ escape_newlines)
++ return Markup(out.getvalue())
++
++
++class InlineHtmlFormatter(object):
++ """Format parsed wiki text to inline elements HTML.
++
++ Block level content will be disguarded or compacted.
++ """
++
++ flavor = 'oneliner'
++
++ def __init__(self, env, context, wikidom):
++ self.env = env
++ self.context = context
++ if isinstance(wikidom, basestring):
++ wikidom = WikiParser(env).parse(wikidom)
++ self.wikidom = wikidom
++
++ def generate(self, shorten=False):
++ """Generate HTML inline elements.
++
++ If `shorten` is set, the generation will stop once enough characters
++ have been emitted.
++ """
++ # FIXME: compatibility code only for now
++ out = StringIO()
++ OneLinerFormatter(self.env, self.context).format(self.wikidom, out,
++ shorten)
++ return Markup(out.getvalue())
++
++
++def format_to(env, flavor, context, wikidom, **options):
++ if flavor == 'oneliner':
++ return format_to_oneliner(env, context, wikidom, **options)
++ else:
++ return format_to_html(env, context, wikidom, **options)
++
++def format_to_html(env, context, wikidom, escape_newlines=False):
++ if not wikidom:
++ return Markup()
++ return HtmlFormatter(env, context, wikidom).generate(escape_newlines)
++
++def format_to_oneliner(env, context, wikidom, shorten=False):
++ if not wikidom:
++ return Markup()
++ return InlineHtmlFormatter(env, context, wikidom).generate(shorten)
++
++def extract_link(env, context, wikidom):
++ if not wikidom:
++ return Markup()
++ return LinkFormatter(env, context).match(wikidom)
++
++
++# pre-0.11 wiki text to Markup compatibility methods
++
++def wiki_to_html(wikitext, env, req, db=None,
++ absurls=False, escape_newlines=False):
++ if not wikitext:
++ return Markup()
++ abs_ref, href = (req or env).abs_href, (req or env).href
++ context = Context.from_request(req, absurls=absurls)
++ out = StringIO()
++ Formatter(env, context).format(wikitext, out, escape_newlines)
++ return Markup(out.getvalue())
++
++def wiki_to_oneliner(wikitext, env, db=None, shorten=False, absurls=False,
++ req=None):
++ if not wikitext:
++ return Markup()
++ abs_ref, href = (req or env).abs_href, (req or env).href
++ context = Context.from_request(req, absurls=absurls)
++ out = StringIO()
++ OneLinerFormatter(env, context).format(wikitext, out, shorten)
++ return Markup(out.getvalue())
++
++def wiki_to_outline(wikitext, env, db=None,
++ absurls=False, max_depth=None, min_depth=None):
++ if not wikitext:
++ return Markup()
++ abs_ref, href = (req or env).abs_href, (req or env).href
++ context = Context.from_request(req, absurls=absurls)
++ out = StringIO()
++ OutlineFormatter(env, context).format(wikitext, out, max_depth, min_depth)
++ return Markup(out.getvalue())
+diff -urNad trac-0.11.1~/trac/wiki/parser.py trac-0.11.1/trac/wiki/parser.py
+--- trac-0.11.1~/trac/wiki/parser.py 2008-08-07 03:00:20.000000000 +0200
++++ trac-0.11.1/trac/wiki/parser.py 2008-11-16 18:16:22.000000000 +0100
+@@ -98,9 +98,10 @@
+ # * list
+ r"(?P<list>^(?P<ldepth>\s+)(?:[-*]|\d+\.|[a-zA-Z]\.|[ivxIVX]{1,5}\.) )",
+ # definition::
+- r"(?P<definition>^\s+((?:%s[^%s]*%s|%s.*?%s|[^%s%s:]|:[^:])+::)(?:\s+|$))"
++ r"(?P<definition>^\s+((?:%s[^%s]*%s|%s(?:%s{,2}[^%s])*?%s|[^%s%s:]|:[^:])+::)(?:\s+|$))"
+ % (INLINE_TOKEN, INLINE_TOKEN, INLINE_TOKEN,
+- STARTBLOCK_TOKEN, ENDBLOCK_TOKEN, INLINE_TOKEN, STARTBLOCK[0]),
++ STARTBLOCK_TOKEN, ENDBLOCK[0], ENDBLOCK[0], ENDBLOCK_TOKEN,
++ INLINE_TOKEN, STARTBLOCK[0]),
+ # (leading space)
+ r"(?P<indent>^(?P<idepth>\s+)(?=\S))",
+ # || table ||
+diff -urNad trac-0.11.1~/trac/wiki/tests/wiki-tests.txt trac-0.11.1/trac/wiki/tests/wiki-tests.txt
+--- trac-0.11.1~/trac/wiki/tests/wiki-tests.txt 2008-08-07 03:00:20.000000000 +0200
++++ trac-0.11.1/trac/wiki/tests/wiki-tests.txt 2008-11-16 18:16:53.000000000 +0100
+@@ -1034,6 +1034,16 @@
+ </blockquote>
+ ------------------------------
+ term::definition
++============================== Pathological definition list counter example with block quotes
++ {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}}
++------------------------------
++<blockquote>
++<p>
++<tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt>
++</p>
++</blockquote>
++------------------------------
++<tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt>
+ ============================== Definition list + escaped definition list
+ complex topic:: multiline
+ `not:: a dl`
+diff -urNad trac-0.11.1~/trac/wiki/tests/wiki-tests.txt.orig trac-0.11.1/trac/wiki/tests/wiki-tests.txt.orig
+--- trac-0.11.1~/trac/wiki/tests/wiki-tests.txt.orig 1970-01-01 01:00:00.000000000 +0100
++++ trac-0.11.1/trac/wiki/tests/wiki-tests.txt.orig 2008-08-07 03:00:20.000000000 +0200
+@@ -0,0 +1,1296 @@
++============================================================
++
++ Font styles
++
++============================== Bold + italic markup
++This should be '''''bold and italic'''''
++------------------------------
++<p>
++This should be <strong><i>bold and italic</i></strong>
++</p>
++------------------------------
++============================== Consecutive bold + italic markup
++'''''one''''', '''''two''''', '''''three''''', '''''four'''''
++------------------------------
++<p>
++<strong><i>one</i></strong>, <strong><i>two</i></strong>, <strong><i>three</i></strong>, <strong><i>four</i></strong>
++</p>
++------------------------------
++============================== Underline + overstrike markup
++__~~underlineoversrike~~__
++------------------------------
++<p>
++<span class="underline"><del>underlineoversrike</del></span>
++</p>
++------------------------------
++============================== Problematic markup: overlapping tags
++__~~overlapping__tags~~
++------------------------------
++<p>
++<span class="underline"><del>overlapping</del></span><del>tags</del>
++</p>
++------------------------------
++============================== Problematic markup: out of order close tags
++__~~outoforderclosetags__~~
++------------------------------
++<p>
++<span class="underline"><del>outoforderclosetags</del></span><del></del>
++</p>
++------------------------------
++============================== Problematic markup: bold + missing close italic
++'''''bolditalic''' # Open italic should be closed before paragraph end
++------------------------------
++<p>
++<strong><i>bolditalic</i></strong><i> # Open italic should be closed before paragraph end
++</i></p>
++------------------------------
++============================== Italic immediately followed by bold markup
++''italic'''''bold'''
++------------------------------
++<p>
++<i>italic</i><strong>bold</strong>
++</p>
++------------------------------
++============================== Bold immediately followed by italic markup
++'''bold'''''italic''
++------------------------------
++<p>
++<strong>bold</strong><i>italic</i>
++</p>
++------------------------------
++============================== Multiline bold italic markup
++'''''bold
++italic
++multiline'''''
++------------------------------
++<p>
++<strong><i>bold
++italic
++multiline</i></strong>
++</p>
++------------------------------
++============================== Problematic multiline bold italic markup
++'''''bold
++italic
++multiline
++without endtags
++------------------------------
++<p>
++<strong><i>bold
++italic
++multiline
++without endtags
++</i></strong></p>
++------------------------------
++============================== Super and subscript markup
++^superscript^, ,,subscript,,, normal.
++------------------------------
++<p>
++<sup>superscript</sup>, <sub>subscript</sub>, normal.
++</p>
++------------------------------
++<sup>superscript</sup>, <sub>subscript</sub>, normal.
++============================== Escaping markup
++!'''''foobar!''''' x
++!''foo!'' x
++!'''bar!''' x
++!__foo!__ x
++!~~bar!~~ x
++!,,boo!,, x
++!^baz!^ x
++------------------------------
++<p>
++'''''foobar''''' x
++''foo'' x
++'''bar''' x
++__foo__ x
++~~bar~~ x
++,,boo,, x
++^baz^ x
++</p>
++------------------------------
++============================== Complex mixed verbatim markup
++{{{verbatim}}}
++{{{
++{{{in `block`
++}}}
++`{{{this is verbatim}}}` and {{{`that` should also `be` verbatim}}}
++------------------------------
++<p>
++<tt>verbatim</tt>
++</p>
++<pre class="wiki">{{{in `block`
++</pre><p>
++<tt>{{{this is verbatim}}}</tt> and <tt>`that` should also `be` verbatim</tt>
++</p>
++------------------------------
++<tt>verbatim</tt>
++ […]
++<tt>{{{this is verbatim}}}</tt> and <tt>`that` should also `be` verbatim</tt>
++============================================================
++
++ Link Resolvers
++
++============================== Link resolvers, short form
++link:1
++
++Thing [link:1] Thing[link:2]
++------------------------------
++<p>
++<a class="odd resolver" href="/thing/1">link:1</a>
++</p>
++<p>
++Thing <a class="odd resolver" href="/thing/1">1</a> Thing<a class="even resolver" href="/thing/2">2</a>
++</p>
++------------------------------
++============================== Escaping links resolvers, short form
++!link:1
++Thing ![link:1 number 1], CS![link:1], ![link:bar]
++------------------------------
++<p>
++link:1
++Thing [link:1 number 1], CS[link:1], [link:bar]
++</p>
++------------------------------
++============================== Link resolvers, long form with label
++[link:1 thing one], [http://www.edgewall.com/ edgewall]
++------------------------------
++<p>
++<a class="odd resolver" href="/thing/1">thing one</a>, <a class="ext-link" href="http://www.edgewall.com/"><span class="icon">edgewall</span></a>
++</p>
++------------------------------
++============================== Link resolver SHREF_TARGET_LAST
++Add-on to link:123:
++Some change.
++link:1
++This ticket is the first one
++link:123>
++link:123&
++see link:xü.
++------------------------------
++<p>
++Add-on to <a class="odd resolver" href="/thing/123">link:123</a>:
++Some change.
++<a class="odd resolver" href="/thing/1">link:1</a>
++This ticket is the first one
++<a class="odd resolver" href="/thing/123">link:123</a>>
++<a class="odd resolver" href="/thing/123">link:123</a>&
++see <a class="text resolver" href="/stuff/x%C3%BC">link:xü</a>.
++</p>
++------------------------------
++Add-on to <a class="odd resolver" href="/thing/123">link:123</a>:
++Some change.
++<a class="odd resolver" href="/thing/1">link:1</a>
++This ticket is the first one
++<a class="odd resolver" href="/thing/123">link:123</a>>
++<a class="odd resolver" href="/thing/123">link:123</a>&
++see <a class="text resolver" href="/stuff/x%C3%BC">link:xü</a>.
++============================== Link resolver SHREF_TARGET_FIRST
++<bug>http://localhost/bugzilla/show_bug.cgi?id=1284</bug> 804
++__Summary:__
++see link:Überflüssigkeit
++------------------------------
++<p>
++<bug><a class="ext-link" href="http://localhost/bugzilla/show_bug.cgi?id=1284"><span class="icon">http://localhost/bugzilla/show_bug.cgi?id=1284</span></a></bug> 804
++<span class="underline">Summary:</span>
++see <a class="text resolver" href="/stuff/%C3%9Cberfl%C3%BCssigkeit">link:Überflüssigkeit</a>
++</p>
++------------------------------
++============================== Link resolver SHREF_TARGET_MIDDLE
++||http://example.com/img.png||text||
++------------------------------
++<table class="wiki">
++<tr><td><a class="ext-link" href="http://example.com/img.png"><span class="icon">http://example.com/img.png</span></a></td><td>text
++</td></tr></table>
++------------------------------
++||<a class="ext-link" href="http://example.com/img.png"><span class="icon">http://example.com/img.png</span></a>||text||
++============================== Link resolver, long form with quoting
++[link:WikiStart Foo] [http://www.edgewall.com/ Edgewall]
++
++link:"Foo Bar" link:"Foo Bar#baz"
++
++[link:"Foo Bar" Foo Bar] [link:"Foo Bar#baz" Foo Bar]
++
++[link:Argv "*argv[] versus **argv"]
++
++[link:test "test.txt", line 123]
++
++[link:pl/de %de]
++------------------------------
++<p>
++<a class="text resolver" href="/stuff/WikiStart">Foo</a> <a class="ext-link" href="http://www.edgewall.com/"><span class="icon">Edgewall</span></a>
++</p>
++<p>
++<a class="text resolver" href="/stuff/Foo%20Bar">link:"Foo Bar"</a> <a class="text resolver" href="/stuff/Foo%20Bar%23baz">link:"Foo Bar#baz"</a>
++</p>
++<p>
++<a class="text resolver" href="/stuff/Foo%20Bar">Foo Bar</a> <a class="text resolver" href="/stuff/Foo%20Bar%23baz">Foo Bar</a>
++</p>
++<p>
++<a class="text resolver" href="/stuff/Argv">*argv[] versus **argv</a>
++</p>
++<p>
++<a class="text resolver" href="/stuff/test">"test.txt", line 123</a>
++</p>
++<p>
++<a class="text resolver" href="/stuff/pl/de">%de</a>
++</p>
++------------------------------
++============================== Link resolver in markup
++'''link:1''', ''link:1'', ~~link:1~~, __link:1__
++------------------------------
++<p>
++<strong><a class="odd resolver" href="/thing/1">link:1</a></strong>, <i><a class="odd resolver" href="/thing/1">link:1</a></i>, <del><a class="odd resolver" href="/thing/1">link:1</a></del>, <span class="underline"><a class="odd resolver" href="/thing/1">link:1</a></span>
++</p>
++------------------------------
++============================== Link resolver, quoting of target
++link:1
++link:12
++link:123
++link:'1'
++link:'12'
++link:'123'
++link:"1"
++link:"12"
++link:"123"
++------------------------------
++<p>
++<a class="odd resolver" href="/thing/1">link:1</a>
++<a class="even resolver" href="/thing/12">link:12</a>
++<a class="odd resolver" href="/thing/123">link:123</a>
++<a class="odd resolver" href="/thing/1">link:'1'</a>
++<a class="even resolver" href="/thing/12">link:'12'</a>
++<a class="odd resolver" href="/thing/123">link:'123'</a>
++<a class="odd resolver" href="/thing/1">link:"1"</a>
++<a class="even resolver" href="/thing/12">link:"12"</a>
++<a class="odd resolver" href="/thing/123">link:"123"</a>
++</p>
++------------------------------
++============================== Link resolver look alike, quoting of target
++nolink:"<blink>"
++------------------------------
++<p>
++nolink:"<blink>"
++</p>
++------------------------------
++============================================================
++
++ Other Links
++
++============================== Relative links
++Relative links are supported:
++[../parent See above] Note: see wikisyntax tests for other parent tests
++[./sibling See next]
++[... nothing to see] [...]
++[//docs See documentation]
++[//images/logo.png Our logo]
++[/] Note: "" is an Href("/") artifact
++[/newticket?component=test new ticket]
++[#title]
++[#title see Title]
++------------------------------
++<p>
++Relative links are supported:
++<a href="/wiki/parent">See above</a> Note: see wikisyntax tests for other parent tests
++<a href="/wiki/WikiStart/sibling">See next</a>
++[... nothing to see] [...]
++<a href="/docs">See documentation</a>
++<a href="/images/logo.png">Our logo</a>
++<a href="">/</a> Note: "" is an Href("/") artifact
++<a href="/newticket?component=test">new ticket</a>
++<a href="/wiki/WikiStart#title">#title</a>
++<a href="/wiki/WikiStart#title">see Title</a>
++</p>
++------------------------------
++============================== Image links are now regular external links
++http://example.com/img.png?foo=bar
++------------------------------
++<p>
++<a class="ext-link" href="http://example.com/img.png?foo=bar"><span class="icon">http://example.com/img.png?foo=bar</span></a>
++</p>
++------------------------------
++<a class="ext-link" href="http://example.com/img.png?foo=bar"><span class="icon">http://example.com/img.png?foo=bar</span></a>
++============================== Arbitrary protocol Link
++''RFCs von ftp://ftp.rfc-editor.org/in-notes/rfcXXXX.txt''
++------------------------------
++<p>
++<i>RFCs von <a class="ext-link" href="ftp://ftp.rfc-editor.org/in-notes/rfcXXXX.txt"><span class="icon">ftp://ftp.rfc-editor.org/in-notes/rfcXXXX.txt</span></a></i>
++</p>
++------------------------------
++============================== mailto: links and automatic e-mail detection
++Author: mailto:cboos@neuf.fr,
++i.e. [mailto:cboos@neuf.fr me]
++
++joe'bar@site.info,
++trac+devel@another-site.fr,
++T_r=a-c1.23@yet_another-site.edu.au
++!not@an.email.com
++someone@louvre.museum-
++------------------------------
++<p>
++Author: <a class="mail-link" href="mailto:cboos@neuf.fr"><span class="icon">mailto:cboos@neuf.fr</span></a>,
++i.e. <a class="mail-link" href="mailto:cboos@neuf.fr"><span class="icon">me</span></a>
++</p>
++<p>
++<a class="mail-link" href="mailto:joe'bar@site.info"><span class="icon">joe'bar@site.info</span></a>,
++<a class="mail-link" href="mailto:trac+devel@another-site.fr"><span class="icon">trac+devel@another-site.fr</span></a>,
++<a class="mail-link" href="mailto:T_r=a-c1.23@yet_another-site.edu.au"><span class="icon">T_r=a-c1.23@yet_another-site.edu.au</span></a>
++not@an.email.com
++<a class="mail-link" href="mailto:someone@louvre.museum"><span class="icon">someone@louvre.museum</span></a>-
++</p>
++------------------------------
++============================== Arbitrary protocol Link
++''RFCs von ftp://ftp.rfc-editor.org/in-notes/rfcXXXX.txt''
++------------------------------
++<p>
++<i>RFCs von <a class="ext-link" href="ftp://ftp.rfc-editor.org/in-notes/rfcXXXX.txt"><span class="icon">ftp://ftp.rfc-editor.org/in-notes/rfcXXXX.txt</span></a></i>
++</p>
++------------------------------
++============================== Generic InterTrac links
++th:roadmap
++th:roadmap:
++[th:]
++[th: Trac Hacks]
++------------------------------
++<p>
++<a class="ext-link" href="http://trac-hacks.org/intertrac/roadmap" title="roadmap in Trac Hacks"><span class="icon">th:roadmap</span></a>
++<a class="ext-link" href="http://trac-hacks.org/intertrac/roadmap" title="roadmap in Trac Hacks"><span class="icon">th:roadmap</span></a>:
++<a class="ext-link" href="http://trac-hacks.org/intertrac/" title="Trac Hacks"><span class="icon">th</span></a>
++<a class="ext-link" href="http://trac-hacks.org/intertrac/" title="Trac Hacks"><span class="icon">Trac Hacks</span></a>
++</p>
++------------------------------
++============================== Another arbitrary protocol Link
++svn+ssh://secureserver.org
++[svn+ssh://secureserver.org SVN link]
++rfc-2396.compatible://link
++[rfc-2396.compatible://link RFC 2396]
++------------------------------
++<p>
++<a class="ext-link" href="svn+ssh://secureserver.org"><span class="icon">svn+ssh://secureserver.org</span></a>
++<a class="ext-link" href="svn+ssh://secureserver.org"><span class="icon">SVN link</span></a>
++<a class="ext-link" href="rfc-2396.compatible://link"><span class="icon">rfc-2396.compatible://link</span></a>
++<a class="ext-link" href="rfc-2396.compatible://link"><span class="icon">RFC 2396</span></a>
++</p>
++------------------------------
++============================== Link resolver counter examples
++Test:[[BR]] There should be a line break
++
++Other test:'''bold text''' should be bold
++------------------------------
++<p>
++Test:<br /> There should be a line break
++</p>
++<p>
++Other test:<strong>bold text</strong> should be bold
++</p>
++------------------------------
++Test: There should be a line break
++
++Other test:<strong>bold text</strong> should be bold
++============================== Link resolver counter example
++'''Note:'''
++------------------------------
++<p>
++<strong>Note:</strong>
++</p>
++------------------------------
++<strong>Note:</strong>
++==============================
++============================================================
++
++ Processor blocks
++
++============================== Code Block 1
++{{{
++Preformatted text.
++}}}
++Paragraph
++------------------------------
++<pre class="wiki">Preformatted text.
++</pre><p>
++Paragraph
++</p>
++------------------------------
++ […]
++Paragraph
++============================== Code Block 2
++{{{
++<b>Preformatted text</b>.
++}}}
++Paragraph
++------------------------------
++<pre class="wiki"><b>Preformatted text</b>.
++</pre><p>
++Paragraph
++</p>
++------------------------------
++ […]
++Paragraph
++============================== Embedded code blocks
++{{{
++Outer block.
++{{{
++Inner block.
++}}}
++}}}
++Paragraph
++------------------------------
++<pre class="wiki">Outer block.
++{{{
++Inner block.
++}}}
++</pre><p>
++Paragraph
++</p>
++------------------------------
++ […]
++Paragraph
++============================== Consecutive code blocks
++Block
++{{{
++number one
++}}}
++and block
++{{{
++number two
++}}}
++.
++------------------------------
++<p>
++Block
++</p>
++<pre class="wiki">number one
++</pre><p>
++and block
++</p>
++<pre class="wiki">number two
++</pre><p>
++.
++</p>
++------------------------------
++Block
++ […]
++and block
++ […]
++.
++============================== Unfinished code blocks
++Block
++{{{
++number one
++
++and block
++{{{
++number two
++ }}
++------------------------------
++<p>
++Block
++</p>
++<pre class="wiki">number one
++
++and block
++{{{
++number two
++ }}
++}}}
++</pre>------------------------------
++Block […]
++============================== Wiki processor
++{{{
++#!default
++Preformatted text.
++}}}
++Paragraph
++------------------------------
++<pre class="wiki">Preformatted text.
++</pre><p>
++Paragraph
++</p>
++------------------------------
++ […]
++Paragraph
++============================== Wiki processor counter example
++{{{
++#!/bin/sh
++echo "foo"
++}}}
++Paragraph
++------------------------------
++<pre class="wiki">#!/bin/sh
++echo "foo"
++</pre><p>
++Paragraph
++</p>
++------------------------------
++ […]
++Paragraph
++============================== HTML wiki processor
++{{{
++#!html
++<p>Hello World</p>
++}}}
++------------------------------
++<p>Hello World</p>
++------------------------------
++ […]
++============================== HTML wiki processor, XSS check 1
++{{{
++#!html
++<script>alert("");</script>
++}}}
++------------------------------
++
++------------------------------
++ […]
++============================== HTML wiki processor, XSS check 2
++{{{
++#!html
++<div onclick="alert('')">Click me</div>
++}}}
++------------------------------
++<div>Click me</div>
++------------------------------
++ […]
++============================== div and span wiki processors
++And now it's [[span('''TIME FOR BED!,class=important)]]. Really.
++{{{
++#!div ; class=important
++Go ahead, edit it freely.
++
++{{{
++#!div; style="border: 2pt solid blue; margin: 1em; padding: .5em"; class=demo
++And now it's [[span('''TIME FOR BED! ''',class=important)]]. Really.
++}}}
++etc.
++}}}
++Done.
++------------------------------
++<p>
++And now it's <span class="important"><strong>TIME FOR BED!</strong></span>. Really.
++</p>
++<div class="important"><p>
++Go ahead, edit it freely.
++</p>
++<div style="border: 2pt solid blue; margin: 1em; padding: .5em" class="demo"><p>
++And now it's <span class="important"><strong>TIME FOR BED! </strong></span>. Really.
++</p>
++</div><p>
++etc.
++</p>
++</div><p>
++Done.
++</p>
++------------------------------
++And now it's [[span(...)]]. Really.
++ […]
++Done.
++============================== div and Span wiki processors
++{{{
++#!div ; class="important"
++Go ahead, [[Span(''edit it freely'',class=important)]].
++}}}
++Done.
++------------------------------
++<div class="important"><p>
++Go ahead, <span class="important"><i>edit it freely</i></span>.
++</p>
++</div><p>
++Done.
++</p>
++------------------------------
++ […]
++Done.
++============================================================
++
++ Wiki Macros
++
++============================== Macro with arguments (leading)
++[[HelloWorld(hej hopp)]]
++------------------------------
++<p>
++Hello World, args = hej hopp
++</p>
++------------------------------
++[[HelloWorld(...)]]
++============================== Macro with arguments (in flow)
++Hello, [[HelloWorld(hej hopp)]]
++------------------------------
++<p>
++Hello, Hello World, args = hej hopp
++</p>
++------------------------------
++Hello, [[HelloWorld(...)]]
++============================== Bad macro call
++[[HelloWorld(hej hopp) ]] # This shouldnt executed as macro since it contain whitespace between ) and ]
++------------------------------
++<p>
++[[<a class="missing wiki" href="/wiki/HelloWorld" rel="nofollow">HelloWorld?</a>(hej hopp) ]] # This shouldnt executed as macro since it contain whitespace between ) and ]
++</p>
++------------------------------
++[[<a class="missing wiki" href="/wiki/HelloWorld" rel="nofollow">HelloWorld?</a>(hej hopp) ]] # This shouldnt executed as macro since it contain whitespace between ) and ]
++============================== Another bad macro call
++[[HelloWorld(hej hopp))]] # Extra right brace and still executed
++------------------------------
++<p>
++Hello World, args = hej hopp) # Extra right brace and still executed
++</p>
++------------------------------
++[[HelloWorld(...)]] # Extra right brace and still executed
++============================== Two consecutive macros on a line
++[[HelloWorld(hej hopp)]] [[HelloWorld(hej hopp2)]] # Test non greedy match
++------------------------------
++<p>
++Hello World, args = hej hopp Hello World, args = hej hopp2 # Test non greedy match
++</p>
++------------------------------
++[[HelloWorld(...)]] [[HelloWorld(...)]] # Test non greedy match
++============================== Macro returning a <div>
++[[DivHelloWorld(hej hopp)]]
++------------------------------
++<p>
++</p><div>Hello World, args = hej hopp</div><p>
++</p>
++------------------------------
++[[DivHelloWorld(...)]]
++============================== Macro returning a <div class="...code...">
++[[DivCode(hej hopp)]]
++------------------------------
++<p>
++<span class="code-block">Hello World, args = hej hopp</span>
++</p>
++------------------------------
++[[DivCode(...)]]
++============================== Macro returning an html.DIV(class="...code...">)
++[[DivCodeElement(hej hopp)]]
++------------------------------
++<p>
++<span class="code-block">Hello World, args = hej hopp</span>
++</p>
++------------------------------
++[[DivCodeElement(...)]]
++============================== Macro returning a Genshi Stream (no "code" div)
++[[DivCodeStream(hej hopp)]]
++------------------------------
++<p>
++</p><div>Hello World, args = hej hopp</div><p>
++</p>
++------------------------------
++[[DivCodeStream(...)]]
++============================== Macro returning None
++[[None(hej hopp)]] nada
++------------------------------
++<p>
++ nada
++</p>
++------------------------------
++[[None(...)]] nada
++============================== Inlined HTML wiki processor
++Inline [[html(<B> Test </B>)]] text
++------------------------------
++<p>
++Inline <b> Test </b> text
++</p>
++------------------------------
++Inline [[html(...)]] text
++============================== BR macro
++Line break [[BR]] another line[[br]]last line
++------------------------------
++<p>
++Line break <br /> another line<br />last line
++</p>
++------------------------------
++Line break another line last line
++============================== Comment wiki processor
++Test comment blocks
++{{{
++#!comment
++This is simply removed from the output
++}}}
++------------------------------
++<p>
++Test comment blocks
++</p>
++------------------------------
++Test comment blocks
++============================== Comment wiki processor called as a macro
++Inline [[comment(This should not be seen)]] comment
++------------------------------
++<p>
++Inline comment
++</p>
++------------------------------
++Inline comment
++============================================================
++
++ Headings
++
++============================== I18N heading
++= ça marche! =
++------------------------------
++<h1 id="çamarche">ça marche!</h1>
++------------------------------
++= ça marche! =
++============================== Quoted heading
++= "Test" =
++------------------------------
++<h1 id="Test">"Test"</h1>
++------------------------------
++= "Test" =
++============================== Heading with < and >
++= Foo <Bar> Baz =
++------------------------------
++<h1 id="FooBarBaz">Foo <Bar> Baz</h1>
++------------------------------
++= Foo <Bar> Baz =
++============================== Heading with .
++= Version 0.10 =
++------------------------------
++<h1 id="Version0.10">Version 0.10</h1>
++------------------------------
++= Version 0.10 =
++============================== Normal heading
++== Heading with trailing white-space ==
++------------------------------
++<h2 id="Headingwithtrailingwhite-space">Heading with trailing white-space</h2>
++------------------------------
++== Heading with trailing white-space ==
++============================== Formatted heading
++== ''Formatted'' ~~Heading~~ ==
++------------------------------
++<h2 id="FormattedHeading"><i>Formatted</i> <del>Heading</del></h2>
++------------------------------
++== ''Formatted'' ~~Heading~~ ==
++============================== Heading with link
++== [wiki:SandBox Linked Heading] ==
++------------------------------
++<h2 id="LinkedHeading"><a class="missing wiki" href="/wiki/SandBox" rel="nofollow">Linked Heading?</a></h2>
++------------------------------
++== [wiki:SandBox Linked Heading] ==
++============================== Normal heading, fixed id
++== Heading with fixed id == #heading-fixed-id
++------------------------------
++<h2 id="heading-fixed-id">Heading with fixed id</h2>
++------------------------------
++== Heading with fixed id == #heading-fixed-id
++============================== Normal heading, auto-corrected id
++== 10 tips ==
++------------------------------
++<h2 id="a10tips">10 tips</h2>
++------------------------------
++== 10 tips ==
++============================================================
++
++ Lists
++
++============================== Bulleted lists
++Paragraph
++ * foo bar
++ boo baz
++ * Subitem
++ Subitem line 2
++ * item 2
++ item 2 line 2
++Paragraph
++------------------------------
++<p>
++Paragraph
++</p>
++<ul><li>foo bar
++boo baz
++<ul><li>Subitem
++Subitem line 2
++</li></ul></li><li>item 2
++item 2 line 2
++</li></ul><p>
++Paragraph
++</p>
++------------------------------
++Paragraph
++ * foo bar
++ boo baz
++ * Subitem
++ Subitem line 2
++ * item 2
++ item 2 line 2
++Paragraph
++============================== Changelog sample (and e-mail link)
++2003-09-18 23:26 Joe Bar <joeb@gloogle.gom>
++
++ * src/code.py: Fix problem with obsolete use of
++ backslash in symbols.
++ * src/test.py: Added unit tests.
++ - test + symbol
++ - test - symbol
++Paragraph
++------------------------------
++<p>
++2003-09-18 23:26 Joe Bar <<a class="mail-link" href="mailto:joeb@gloogle.gom"><span class="icon">joeb@gloogle.gom</span></a>>
++</p>
++<ul><li>src/code.py: Fix problem with obsolete use of
++backslash in symbols.
++</li><li>src/test.py: Added unit tests.
++<ul><li>test + symbol
++</li><li>test - symbol
++</li></ul></li></ul><p>
++Paragraph
++</p>
++------------------------------
++============================== Complex bulleted list
++ * foo bar
++ boo baz
++ * Subitem 1
++ - nested item 1
++ - nested item 2
++ nested item 2 continued
++ Subitem 1 continued
++ * Subitem 2
++ Subitem 2 continued
++ * Subitem 3
++ continued
++ * item 2
++ item 2 line 2
++Paragraph
++------------------------------
++<ul><li>foo bar
++boo baz
++<ul><li>Subitem 1
++<ul><li>nested item 1
++</li><li>nested item 2
++nested item 2 continued
++</li></ul></li><li>Subitem 1 continued
++</li></ul></li><li>Subitem 2
++Subitem 2 continued
++</li><li>Subitem 3
++continued
++</li></ul><ul><li>item 2
++item 2 line 2
++</li></ul><p>
++Paragraph
++</p>
++------------------------------
++============================== Numbered lists
++ 1. item 1
++ a. item 1.a
++ a. item 1.b
++
++Some paragraph
++
++ 2. continue with item 2
++ i. roman 1
++ ii. roman 2
++Paragraph
++------------------------------
++<ol><li>item 1
++<ol class="loweralpha"><li>item 1.a
++</li><li>item 1.b
++</li></ol></li></ol><p>
++Some paragraph
++</p>
++<ol start="2"><li>continue with item 2
++<ol class="lowerroman"><li>roman 1
++</li><li>roman 2
++</li></ol></li></ol><p>
++Paragraph
++</p>
++------------------------------
++1. item 1
++ a. item 1.a
++ a. item 1.b
++
++Some paragraph
++
++ 2. continue with item 2
++ i. roman 1
++ ii. roman 2
++Paragraph
++============================== Numbered lists multi-line items
++ 1. This is a very long line at
++ the first level, which works correctly.
++ 1. But this line at the second level, which
++ is also continued on the next line, does not.
++Paragraph
++------------------------------
++<ol><li>This is a very long line at
++the first level, which works correctly.
++<ol><li>But this line at the second level, which
++is also continued on the next line, does not.
++</li></ol></li></ol><p>
++Paragraph
++</p>
++------------------------------
++1. This is a very long line at
++ the first level, which works correctly.
++ 1. But this line at the second level, which
++ is also continued on the next line, does not.
++Paragraph
++============================== Numbered lists counter-examples
++ This will not start a new numbered
++ list. There's more than one character
++ before the "."
++ OTOH, the following is a roman numbered list:
++ iii. start
++ xxvii. maximal number in sequence
++Paragraph
++------------------------------
++<blockquote>
++<p>
++This will not start a new numbered
++list. There's more than one character
++before the "."
++OTOH, the following is a roman numbered list:
++</p>
++</blockquote>
++<ol class="lowerroman"><li>start
++</li><li>maximal number in sequence
++</li></ol><p>
++Paragraph
++</p>
++------------------------------
++============================== Mixed lists multi-line items
++ 1. multi-line
++ numbered list
++ i. multi-line
++ item i.
++ * sub item
++ ii. multi-line
++ item ii.
++ * sub item
++ multiline
++ a. subsub
++ multiline
++ b. subsub
++ iii. multi-line
++ item iii.
++ * sub item
++Paragraph
++------------------------------
++<ol><li>multi-line
++numbered list
++<ol class="lowerroman"><li>multi-line
++item i.
++<ul><li>sub item
++</li></ul></li><li>multi-line
++item ii.
++<ul><li>sub item
++multiline
++<ol class="loweralpha"><li>subsub
++multiline
++</li><li>subsub
++</li></ol></li></ul></li><li>multi-line
++item iii.
++<ul><li>sub item
++</li></ul></li></ol></li></ol><p>
++Paragraph
++</p>
++------------------------------
++============================== Simple definition list
++ term:: definition
++------------------------------
++<dl><dt>term</dt><dd>definition
++</dd></dl>
++------------------------------
++term:: definition
++============================== Tricky definition list
++ term:: definition:: text
++------------------------------
++<dl><dt>term</dt><dd>definition:: text
++</dd></dl>
++------------------------------
++term:: definition:: text
++============================== Verbatim term in definition list
++ `term`:: definition
++------------------------------
++<dl><dt><tt>term</tt></dt><dd>definition
++</dd></dl>
++------------------------------
++<tt>term</tt>:: definition
++============================== Another verbatim term in definition list
++ {{{term}}}:: definition
++------------------------------
++<dl><dt><tt>term</tt></dt><dd>definition
++</dd></dl>
++------------------------------
++<tt>term</tt>:: definition
++============================== Complex definition list
++ complex topic:: multiline
++ ''formatted''
++ definition
++------------------------------
++<dl><dt>complex topic</dt><dd>multiline
++<i>formatted</i>
++definition
++</dd></dl>
++------------------------------
++complex topic:: multiline
++ <i>formatted</i>
++ definition
++============================== Definition list counter example
++ term::definition
++------------------------------
++<blockquote>
++<p>
++term::definition
++</p>
++</blockquote>
++------------------------------
++term::definition
++============================== Definition list + escaped definition list
++ complex topic:: multiline
++ `not:: a dl`
++------------------------------
++<dl><dt>complex topic</dt><dd>multiline
++<tt>not:: a dl</tt>
++</dd></dl>
++------------------------------
++complex topic:: multiline
++ <tt>not:: a dl</tt>
++============================== Definition list + another escaped definition list
++ complex topic:: multiline
++ {{{not:: a dl}}}
++------------------------------
++<dl><dt>complex topic</dt><dd>multiline
++<tt>not:: a dl</tt>
++</dd></dl>
++------------------------------
++complex topic:: multiline
++ <tt>not:: a dl</tt>
++============================================================
++
++ Tables
++
++============================== Simple Table, one column
++|| a ||
++|| b ||
++------------------------------
++<table class="wiki">
++<tr><td> a
++</td></tr><tr><td> b
++</td></tr></table>
++------------------------------
++|| a ||
++|| b ||
++============================== Simple Table, multiple columns
++in:
++|| RPC# || parameter len || ..... parameter ..... ||
++out:
++|| RPC# || parameter len || ..... parameter ..... ||
++----
++------------------------------
++<p>
++in:
++</p>
++<table class="wiki">
++<tr><td> RPC# </td><td> parameter len </td><td> ..... parameter .....
++</td></tr></table>
++<p>
++out:
++</p>
++<table class="wiki">
++<tr><td> RPC# </td><td> parameter len </td><td> ..... parameter .....
++</td></tr></table>
++<hr />
++------------------------------
++in:
++|| RPC# || parameter len || ..... parameter ..... ||
++out:
++|| RPC# || parameter len || ..... parameter ..... ||
++----
++============================== Indented tables, multiple columns
++|| a || b ||
++
++ || a || b ||
++ || a || b ||
++
++|| a || b ||
++------------------------------
++<table class="wiki">
++<tr><td> a </td><td> b
++</td></tr></table>
++<blockquote>
++<table class="wiki">
++<tr><td> a </td><td> b
++</td></tr><tr><td> a </td><td> b
++</td></tr></table>
++</blockquote>
++<table class="wiki">
++<tr><td> a </td><td> b
++</td></tr></table>
++------------------------------
++|| a || b ||
++
++ || a || b ||
++ || a || b ||
++
++|| a || b ||
++============================================================
++
++ Mixed examples
++
++============================== Mix of headings and lists
++= Heading 1 =
++Paragraph
++ * Item 1
++ * Item 2
++Another paragraph
++------------------------------
++<h1 id="Heading1">Heading 1</h1>
++<p>
++Paragraph
++</p>
++<ul><li>Item 1
++<ul><li>Item 2
++</li></ul></li></ul><p>
++Another paragraph
++</p>
++------------------------------
++= Heading 1 =
++Paragraph
++ * Item 1
++ * Item 2
++Another paragraph
++============================== Heading, lists and table
++Paragraph
++----
++ 1. Item 1
++ 2. Item 2
++||Table||cell||
++||Foo||Bar||Baz||
++http://www.edgewall.com/
++------------------------------
++<p>
++Paragraph
++</p>
++<hr />
++<ol><li>Item 1
++<ol start="2"><li>Item 2
++</li></ol></li></ol><table class="wiki">
++<tr><td>Table</td><td>cell
++</td></tr><tr><td>Foo</td><td>Bar</td><td>Baz
++</td></tr></table>
++<p>
++<a class="ext-link" href="http://www.edgewall.com/"><span class="icon">http://www.edgewall.com/</span></a>
++</p>
++------------------------------
++Paragraph
++----
++ 1. Item 1
++ 2. Item 2
++||Table||cell||
++||Foo||Bar||Baz||
++<a class="ext-link" href="http://www.edgewall.com/"><span class="icon">http://www.edgewall.com/</span></a>
++============================== Lists, indents and table
++
++ * Bar
++ * Foo
++
++ || Foo || Bar ||
++
++ || Foo || Bar ||
++------------------------------
++<ul><li>Bar
++<ul><li>Foo
++</li></ul></li></ul><blockquote>
++<blockquote>
++<table class="wiki">
++<tr><td> Foo </td><td> Bar
++</td></tr></table>
++</blockquote>
++</blockquote>
++<blockquote>
++<table class="wiki">
++<tr><td> Foo </td><td> Bar
++</td></tr></table>
++</blockquote>
++------------------------------
++* Bar
++ * Foo
++
++ || Foo || Bar ||
++
++ || Foo || Bar ||
++============================== "Tabstops" set by lists and quotes
++ This is one level deep
++
++ * Bar
++ * Foo
++
++ Now this should be 2 levels deep as well
++
++ This is now level 3.
++
++ Continue on level 2.
++
++ - but a list always restart at level 1.
++Paragraph.
++------------------------------
++<blockquote>
++<p>
++This is one level deep
++</p>
++</blockquote>
++<ul><li>Bar
++<ul><li>Foo
++</li></ul></li></ul><blockquote>
++<blockquote>
++<p>
++Now this should be 2 levels deep as well
++</p>
++</blockquote>
++</blockquote>
++<blockquote>
++<blockquote>
++<blockquote>
++<p>
++This is now level 3.
++</p>
++</blockquote>
++</blockquote>
++</blockquote>
++<blockquote>
++<blockquote>
++<p>
++Continue on level 2.
++</p>
++</blockquote>
++</blockquote>
++<ul><li>but a list always restart at level 1.
++</li></ul><p>
++Paragraph.
++</p>
++------------------------------
++============================== Citations
++> This is the quoted text
++>> a nested quote
++A comment on the above
++>> start 2nd level
++> first level
++------------------------------
++<blockquote class="citation">
++<p>
++ This is the quoted text
++</p>
++<blockquote class="citation">
++<p>
++ a nested quote
++</p>
++</blockquote>
++</blockquote>
++<p>
++A comment on the above
++</p>
++<blockquote class="citation">
++<blockquote class="citation">
++<p>
++ start 2nd level
++</p>
++</blockquote>
++<p>
++ first level
++</p>
++</blockquote>
++------------------------------
++> This is the quoted text
++>> a nested quote
++A comment on the above
++>> start 2nd level
++> first level
Reply to: