diff -r 3a1992166861 htdocs/css/trac.css
--- a/htdocs/css/trac.css	Mon May 08 11:56:57 2006 +0200
+++ b/htdocs/css/trac.css	Tue May 09 01:13:29 2006 +0200
@@ -275,6 +288,15 @@ pre.wiki, pre.literal-block {
  padding: .25em;
  overflow: auto;
 }
+
+blockquote.citation { 
+ margin: 0;
+ border-style: solid; 
+ border-width: 0 0 0 0.15em; 
+ border-color: #b44; 
+ padding-left: .5em;
+}
+
 table.wiki {
  border: 2px solid #ccc;
  border-collapse: collapse;
diff -r 3a1992166861 trac/wiki/formatter.py
--- a/trac/wiki/formatter.py	Mon May 08 11:56:57 2006 +0200
+++ b/trac/wiki/formatter.py	Tue May 09 01:13:29 2006 +0200
@@ -179,6 +179,7 @@ class Formatter(object):
         % (INLINE_TOKEN, INLINE_TOKEN)]
 
     _post_rules = [
+        r"(?P<quote>^(?P<qdepth>>+))",
         r"(?P<htmlescape>[&<>])",
         # shref corresponds to short TracLinks, i.e. sns:stgt
         r"(?P<shref>!?((?P<sns>%s):(?P<stgt>%s|%s(?:%s*%s)?)))" \
@@ -193,7 +194,7 @@ class Formatter(object):
          r"(\]\]|\((?P<macroargs>.*?)\)\]\]))"),
         # heading, list, definition, indent, table...
         r"(?P<heading>^\s*(?P<hdepth>=+)\s.*\s(?P=hdepth)\s*$)",
-        r"(?P<list>^(?P<ldepth>\s+)(?:\*|\d+\.|[a-zA-Z]\.|[ivxIVX]{1,5}\.) )",
+        r"(?P<list>^(?P<ldepth>\s+)(?:[-*]|\d+\.|[a-zA-Z]\.|[ivxIVX]{1,5}\.) )",
         r"(?P<definition>^\s+((?:%s.*?%s|%s.*?%s|[^%s%s])+?::)(?:\s+|$))"
         % (INLINE_TOKEN, INLINE_TOKEN, STARTBLOCK_TOKEN, ENDBLOCK_TOKEN,
            INLINE_TOKEN, STARTBLOCK[0]),
@@ -456,11 +457,10 @@ class Formatter(object):
     
     def _list_formatter(self, match, fullmatch):
         ldepth = len(fullmatch.group('ldepth'))
-        depth = int((len(fullmatch.group('ldepth')) + 1) / 2)
         listid = match[ldepth]
-        self.in_list_item = depth > 0
+        self.in_list_item = True
         class_ = start = None
-        if listid == '*':
+        if listid in '-*':
             type_ = 'ul'
         else:
             type_ = 'ol'
@@ -473,45 +473,51 @@ class Formatter(object):
                 class_ = 'loweralpha'
             elif listid.isupper():
                 class_ = 'upperalpha'
-        self._set_list_depth(depth, type_, class_, start)
+        self._set_list_depth(ldepth, type_, class_, start)
         return ''
 
-    def _set_list_depth(self, depth, type_, class_, start):
-        current_depth = len(self._list_stack)
-        diff = depth - current_depth
-        self.close_table()
-        self.close_paragraph()
-        self.close_indentation()
-        begin_list = type_
-        if class_:
-            begin_list += ' class="%s"' % class_
-        if start:
-            begin_list += start and ' start="%s"' % start
-        if diff > 0:
-            for i in range(diff):
-                self._list_stack.append(type_)
-                self.out.write('<%s><li>' % begin_list)
-        elif diff < 0:
-            for i in range(-diff):
-                tmp = self._list_stack.pop()
-                self.out.write('</li></%s>' % tmp)
-            if self._list_stack != [] and type_ != self._list_stack[-1]:
-                tmp = self._list_stack.pop()
-                self._list_stack.append(type_)
-                self.out.write('</li></%s><%s><li>' % (tmp, begin_list))
+    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()
+            self._list_stack.append((new_type, depth))
+            self.out.write('<%s%s%s><li>' %
+                           (new_type,
+                            list_class and ' class="%s"' % list_class or '',
+                            start and ' start="%s"' % start or ''))
+        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:
-                self.out.write('</li><li>')
-        # diff == 0
-        elif self._list_stack != [] and type_ != self._list_stack[-1]:
-            tmp = self._list_stack.pop()
-            self._list_stack.append(type_)
-            self.out.write('</li></%s><%s><li>' % (tmp, begin_list))
-        elif depth > 0:
-            self.out.write('</li><li>')
+                if self._list_stack:
+                    old_type, old_offset = self._list_stack[-1]
+                    if 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):
-        if self._list_stack != []:
-            self._set_list_depth(0, None, None, None)
+        self._set_list_depth(0, None, None, None)
 
     # Definition Lists
 
@@ -530,31 +536,64 @@ class Formatter(object):
 
     # Blockquote
 
+    def _indent_formatter(self, match, fullmatch):
+        idepth = len(fullmatch.group('idepth'))
+        ldepth = self._get_list_depth()
+        if ldepth > 0 and 0 <= (idepth - ldepth) <= 2:
+            self.in_list_item = True
+        elif not self.in_def_list:
+            self._set_quote_depth(idepth)
+        return ''
+
+    def _quote_formatter(self, match, fullmatch):
+        qdepth = len(fullmatch.group('qdepth'))
+        self._set_quote_depth(qdepth, True)
+        return ''
+
     def close_indentation(self):
-        self.close_table()
-        self.out.write(('</blockquote>' + os.linesep) * self.indent_level)
-        self.indent_level = 0
-
-    def open_indentation(self, depth):
-        if self.in_def_list:
-            return
-        diff = depth - self.indent_level
-        if diff != 0:
+        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):
+        if depth > 0:
+            self.in_quote = True
+        def open_quote(depth):
             self.close_table()
             self.close_paragraph()
-            self.close_indentation()
             self.close_list()
-            self.indent_level = depth
-            self.out.write(('<blockquote>' + os.linesep) * depth)
-
-    def _indent_formatter(self, match, fullmatch):
-        depth = int((len(fullmatch.group('idepth')) + 1) / 2)
-        list_depth = len(self._list_stack)
-        if list_depth > 0 and depth == list_depth + 1:
-            self.in_list_item = 1
-        else:
-            self.open_indentation(depth)
-        return ''
+            def open_one_quote(d):
+                self._quote_stack.append(d)
+                self.out.write('<blockquote%s>%s' %
+                               (citation and ' class="citation"' or '',
+                                os.linesep))
+            if citation:
+                for d in range(self._get_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)
+        if depth > self._get_quote_depth():
+            open_quote(depth)
+        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)
 
     # Table
     
@@ -638,8 +677,8 @@ class Formatter(object):
         elif line.strip() == Formatter.ENDBLOCK:
             self.in_code_block -= 1
             if self.in_code_block == 0 and self.code_processor:
+                self.close_table()
                 self.close_paragraph()
-                self.close_table()
                 self.out.write(self.code_processor.process(self.req, self.code_text))
             else:
                 self.code_text += line + os.linesep
@@ -658,13 +697,13 @@ class Formatter(object):
         self.out = out
         self._open_tags = []
         self._list_stack = []
+        self._quote_stack = []
 
         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.indent_level = 0
         self.paragraph_open = 0
 
         for line in text.splitlines():
@@ -674,11 +713,11 @@ class Formatter(object):
                 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.close_table()
                 self.out.write('<hr />' + os.linesep)
                 continue
             # Handle new paragraph
@@ -692,11 +731,15 @@ class Formatter(object):
             if escape_newlines:
                 line += ' [[BR]]'
             self.in_list_item = False
+            self.in_quote = False
             # Throw a bunch of regexps on the problem
             result = re.sub(self.wiki.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()

