Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r75446 - in branches/quickbook-dev/tools/quickbook: doc src test
From: dnljms_at_[hidden]
Date: 2011-11-10 13:17:05


Author: danieljames
Date: 2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
New Revision: 75446
URL: http://svn.boost.org/trac/boost/changeset/75446

Log:
Quickbook: Parse lists with paragraphs.

Quite a big change. I moved the list logic into the grammar so that it's
easier to tell how to parse different blocks. Also reworked some of the
block vs. phrase stuff - it's a lot cleaner now which helped implement
this. It generates terrible markup at the moment, but at least the
parser is in place.
Added:
   branches/quickbook-dev/tools/quickbook/test/list_test-1_6.gold
      - copied, changed from r75445, /branches/quickbook-dev/tools/quickbook/test/list_test-1_5.gold
   branches/quickbook-dev/tools/quickbook/test/list_test-1_6.quickbook
      - copied, changed from r75445, /branches/quickbook-dev/tools/quickbook/test/list_test-1_5.quickbook
Text files modified:
   branches/quickbook-dev/tools/quickbook/doc/1_6.qbk | 33 +++
   branches/quickbook-dev/tools/quickbook/src/actions.cpp | 97 ++-------
   branches/quickbook-dev/tools/quickbook/src/actions.hpp | 15 +
   branches/quickbook-dev/tools/quickbook/src/actions_class.cpp | 1
   branches/quickbook-dev/tools/quickbook/src/actions_class.hpp | 6
   branches/quickbook-dev/tools/quickbook/src/block_tags.hpp | 2
   branches/quickbook-dev/tools/quickbook/src/grammar_impl.hpp | 31 +-
   branches/quickbook-dev/tools/quickbook/src/main_grammar.cpp | 390 +++++++++++++++++++++++++++++++--------
   branches/quickbook-dev/tools/quickbook/src/quickbook.cpp | 10
   branches/quickbook-dev/tools/quickbook/test/Jamfile.v2 | 1
   branches/quickbook-dev/tools/quickbook/test/list_test-1_5.gold | 123 ++++++++++++
   branches/quickbook-dev/tools/quickbook/test/list_test-1_5.quickbook | 33 +++
   branches/quickbook-dev/tools/quickbook/test/list_test-1_6.gold | 161 ++++++++++++++++
   branches/quickbook-dev/tools/quickbook/test/list_test-1_6.quickbook | 49 ++++
   14 files changed, 772 insertions(+), 180 deletions(-)

Modified: branches/quickbook-dev/tools/quickbook/doc/1_6.qbk
==============================================================================
--- branches/quickbook-dev/tools/quickbook/doc/1_6.qbk (original)
+++ branches/quickbook-dev/tools/quickbook/doc/1_6.qbk 2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
@@ -200,4 +200,37 @@
 
 [endsect]
 
+[section:listparagraphs Pargraphs in lists]
+
+I'm still refining this, but paragraphs can now be used in lists:
+
+[pre
+* Para 1
+
+ Para 2
+ * Nested Para 1
+
+ Nested Para 2
+
+ Code block
+ Para 3
+]
+
+generates:
+
+* Para 1
+
+ Para 2
+ * Nested Para 1
+
+ Nested Para 2
+
+ Code block
+ Para 3
+
+/TODO/: Improve code generation.
+/TODO/: Allow block elements in list items.
+
+[endsect]
+
 [endsect] [/1_6]
\ No newline at end of file

Modified: branches/quickbook-dev/tools/quickbook/src/actions.cpp
==============================================================================
--- branches/quickbook-dev/tools/quickbook/src/actions.cpp (original)
+++ branches/quickbook-dev/tools/quickbook/src/actions.cpp 2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
@@ -67,7 +67,6 @@
         }
     }
 
- void list_action(quickbook::actions&, value);
     void explicit_list_action(quickbook::actions&, value);
     void header_action(quickbook::actions&, value);
     void begin_section_action(quickbook::actions&, value);
@@ -99,8 +98,6 @@
         
         switch(v.get_tag())
         {
- case block_tags::list:
- return list_action(actions, v);
         case block_tags::ordered_list:
         case block_tags::itemized_list:
             return explicit_list_action(actions, v);
@@ -314,6 +311,14 @@
         }
     }
 
+ void list_item_action::operator()() const
+ {
+ std::string str;
+ actions.phrase.swap(str);
+ actions.out << str;
+ write_anchors(actions, actions.out);
+ }
+
     void phrase_end_action::operator()() const
     {
         write_anchors(actions, actions.phrase);
@@ -486,76 +491,30 @@
         }
     }
 
- void list_action(quickbook::actions& actions, value list)
+ void actions::start_list(char mark)
     {
- write_anchors(actions, actions.out);
-
- typedef std::pair<char, int> mark_type;
- std::stack<mark_type> list_marks;
- int list_indent = -1;
-
- BOOST_FOREACH(value_consumer values, list)
- {
- int new_indent = indent_length(
- values.consume(general_tags::list_indent).get_quickbook());
- value mark_value = values.consume(general_tags::list_mark);
- std::string content = values.consume().get_boostbook();
- values.finish();
-
- char mark = *mark_value.get_quickbook().begin();
- assert(mark == '*' || mark == '#');
-
- if(list_indent == -1) {
- assert(new_indent == 0);
- }
-
- if(new_indent > list_indent)
- {
- list_indent = new_indent;
- list_marks.push(mark_type(mark, list_indent));
-
- actions.out << ((mark == '#') ? "<orderedlist>\n" : "<itemizedlist>\n");
- }
- else if (new_indent < list_indent)
- {
- BOOST_ASSERT(!list_marks.empty());
- list_indent = new_indent;
+ write_anchors(*this, out);
+ assert(mark == '*' || mark == '#');
+ out << ((mark == '#') ? "<orderedlist>\n" : "<itemizedlist>\n");
+ }
 
- while (!list_marks.empty() && (list_indent < list_marks.top().second))
- {
- char mark = list_marks.top().first;
- list_marks.pop();
- actions.out << "</simpara></listitem>";
- actions.out << ((mark == '#') ? "\n</orderedlist>" : "\n</itemizedlist>");
- }
- actions.out << "</simpara></listitem>";
- }
- else
- {
- actions.out << "</simpara></listitem>";
- }
+ void actions::end_list(char mark)
+ {
+ write_anchors(*this, out);
+ assert(mark == '*' || mark == '#');
+ out << ((mark == '#') ? "\n</orderedlist>" : "\n</itemizedlist>");
+ }
 
- if (mark != list_marks.top().first) // new_indent == list_indent
- {
- detail::outerr(mark_value.get_file(), mark_value.get_position())
- << "Illegal change of list style.\n";
- detail::outwarn(mark_value.get_file(), mark_value.get_position())
- << "Ignoring change of list style" << std::endl;
- ++actions.error_count;
- }
-
- actions.out << "<listitem><simpara>";
- actions.out << content;
- }
+ void actions::start_list_item()
+ {
+ out << "<listitem><simpara>";
+ write_anchors(*this, out);
+ }
 
- assert(!list_marks.empty());
- while (!list_marks.empty())
- {
- char mark = list_marks.top().first;
- list_marks.pop();
- actions.out << "</simpara></listitem>";
- actions.out << ((mark == '#') ? "\n</orderedlist>" : "\n</itemizedlist>");
- }
+ void actions::end_list_item()
+ {
+ write_anchors(*this, out);
+ out << "</simpara></listitem>";
     }
 
     void explicit_list_action(quickbook::actions& actions, value list)

Modified: branches/quickbook-dev/tools/quickbook/src/actions.hpp
==============================================================================
--- branches/quickbook-dev/tools/quickbook/src/actions.hpp (original)
+++ branches/quickbook-dev/tools/quickbook/src/actions.hpp 2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
@@ -131,6 +131,21 @@
         quickbook::actions& actions;
     };
 
+ struct list_item_action
+ {
+ // implicit paragraphs
+ // doesn't output the paragraph if it's only whitespace.
+
+ list_item_action(
+ quickbook::actions& actions)
+ : actions(actions) {}
+
+ void operator()() const;
+ void operator()(parse_iterator, parse_iterator) const { (*this)(); }
+
+ quickbook::actions& actions;
+ };
+
     struct phrase_end_action
     {
         phrase_end_action(quickbook::actions& actions) :

Modified: branches/quickbook-dev/tools/quickbook/src/actions_class.cpp
==============================================================================
--- branches/quickbook-dev/tools/quickbook/src/actions_class.cpp (original)
+++ branches/quickbook-dev/tools/quickbook/src/actions_class.cpp 2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
@@ -59,6 +59,7 @@
         , code_block(phrase, phrase, *this)
         , inline_code(phrase, *this)
         , paragraph(*this)
+ , list_item(*this)
         , phrase_end(*this)
         , raw_char(phrase)
         , plain_char(phrase, *this)

Modified: branches/quickbook-dev/tools/quickbook/src/actions_class.hpp
==============================================================================
--- branches/quickbook-dev/tools/quickbook/src/actions_class.hpp (original)
+++ branches/quickbook-dev/tools/quickbook/src/actions_class.hpp 2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
@@ -77,6 +77,11 @@
     // actions
     ///////////////////////////////////////////////////////////////////////////
 
+ void start_list(char mark);
+ void end_list(char mark);
+ void start_list_item();
+ void end_list_item();
+
         scoped_parser<to_value_scoped_action>
                                 to_value;
         scoped_parser<cond_phrase_push>
@@ -91,6 +96,7 @@
         code_action code_block;
         inline_code_action inline_code;
         paragraph_action paragraph;
+ list_item_action list_item;
         phrase_end_action phrase_end;
         raw_char_action raw_char;
         plain_char_action plain_char;

Modified: branches/quickbook-dev/tools/quickbook/src/block_tags.hpp
==============================================================================
--- branches/quickbook-dev/tools/quickbook/src/block_tags.hpp (original)
+++ branches/quickbook-dev/tools/quickbook/src/block_tags.hpp 2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
@@ -23,7 +23,7 @@
         (variable_list)(table)
         (xinclude)(import)(include)
         (paragraph)
- (list)(ordered_list)(itemized_list)
+ (ordered_list)(itemized_list)
         (hr)
     )
 

Modified: branches/quickbook-dev/tools/quickbook/src/grammar_impl.hpp
==============================================================================
--- branches/quickbook-dev/tools/quickbook/src/grammar_impl.hpp (original)
+++ branches/quickbook-dev/tools/quickbook/src/grammar_impl.hpp 2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
@@ -22,26 +22,21 @@
 
     struct element_info
     {
- enum context {
- in_block = 1,
- in_phrase = 2,
- in_conditional = 4,
- in_nested_block = 8,
- // This is a magic value to indicate an element that
- // might be a block or might be a phrase. It isn't
- // perfect, if a contextual_block appears at the
- // beginning of a paragraph it might interpreted as
- // a block when is should be a phrase.
- contextual_block = 16
- };
-
         enum type_enum {
             nothing = 0,
- block = in_block,
- conditional_or_block = block | in_conditional,
- nested_block = conditional_or_block | in_nested_block,
- phrase = nested_block | in_phrase,
- maybe_block = phrase | contextual_block
+ block = 1,
+ conditional_or_block = 2,
+ nested_block = 4,
+ phrase = 8,
+ maybe_block = 16
+ };
+
+ enum context {
+ in_phrase = phrase | maybe_block,
+ in_conditional = in_phrase | conditional_or_block,
+ in_nested_block = in_conditional | nested_block,
+ only_block = block | conditional_or_block | nested_block,
+ only_contextual_block = block | conditional_or_block | nested_block | maybe_block
         };
 
         element_info()

Modified: branches/quickbook-dev/tools/quickbook/src/main_grammar.cpp
==============================================================================
--- branches/quickbook-dev/tools/quickbook/src/main_grammar.cpp (original)
+++ branches/quickbook-dev/tools/quickbook/src/main_grammar.cpp 2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
@@ -16,6 +16,7 @@
 #include "phrase_tags.hpp"
 #include "parsers.hpp"
 #include "scoped.hpp"
+#include "input_path.hpp"
 #include <boost/spirit/include/classic_core.hpp>
 #include <boost/spirit/include/classic_chset.hpp>
 #include <boost/spirit/include/classic_if.hpp>
@@ -23,16 +24,65 @@
 #include <boost/spirit/include/classic_attribute.hpp>
 #include <boost/spirit/include/classic_lazy.hpp>
 #include <boost/spirit/include/phoenix1_primitives.hpp>
+#include <boost/range/algorithm/find_first_of.hpp>
+#include <boost/range/as_literal.hpp>
+
+#include <iostream>
 
 namespace quickbook
 {
     namespace cl = boost::spirit::classic;
 
+ struct list_stack_item {
+ bool root;
+ unsigned int indent;
+ unsigned int indent2;
+ char mark;
+
+ list_stack_item() :
+ root(true), indent(0), indent2(0), mark('\0') {}
+
+ list_stack_item(char mark, unsigned int indent, unsigned int indent2) :
+ root(false), indent(indent), indent2(indent2), mark(mark)
+ {}
+
+ };
+
+ struct block_types {
+ enum values {
+ none, code, list, paragraph
+ };
+ };
+
+ template <typename T>
+ struct member_action
+ {
+ typedef void(T::*member_function)(parse_iterator, parse_iterator);
+
+ T& l;
+ member_function mf;
+
+ member_action(T& l, member_function mf) : l(l), mf(mf) {}
+
+ void operator()(parse_iterator first, parse_iterator last) const {
+ (l.*mf)(first, last);
+ }
+ };
+
     struct main_grammar_local
     {
         ////////////////////////////////////////////////////////////////////////
         // Local actions
 
+ void start_blocks_impl(parse_iterator first, parse_iterator last);
+ void end_blocks_impl(parse_iterator first, parse_iterator last);
+ void check_indentation_impl(parse_iterator first, parse_iterator last);
+ void check_code_block_impl(parse_iterator first, parse_iterator last);
+ void plain_block(string_iterator first, string_iterator last);
+ void list_block(string_iterator first, string_iterator mark_pos,
+ string_iterator last);
+ void clear_stack();
+
         struct process_element_impl : scoped_action_base {
             process_element_impl(main_grammar_local& l)
                 : l(l) {}
@@ -45,16 +95,10 @@
 
                 info_ = l.info;
 
- if (!(info_.type & element_info::in_phrase))
+ if (info_.type != element_info::phrase &&
+ info_.type != element_info::maybe_block)
                     l.actions_.paragraph();
 
- if ((info_.type & element_info::contextual_block) &&
- l.top_level.parse_blocks())
- {
- info_.type = element_info::type_enum(
- info_.type & ~element_info::in_phrase);
- }
-
                 l.actions_.values.builder.reset();
                 
                 return true;
@@ -76,32 +120,25 @@
             main_grammar_local& l;
             element_info info_;
         };
-
- struct is_block_type
- {
- typedef bool result_type;
- template <typename Arg1 = void>
- struct result { typedef bool type; };
-
- is_block_type(main_grammar_local& l)
- : l_(l)
- {}
 
- bool operator()() const
- {
- return l_.element_type && !(l_.element_type & element_info::in_phrase);
+ struct in_list_impl {
+ main_grammar_local& l;
+
+ in_list_impl(main_grammar_local& l) :
+ l(l) {}
+
+ bool operator()() const {
+ return !l.list_stack.top().root;
             }
-
- main_grammar_local& l_;
         };
 
         ////////////////////////////////////////////////////////////////////////
         // Local members
 
         cl::rule<scanner>
- blocks, paragraph_separator,
+ top_level, indent_check,
+ paragraph_separator,
                         code, code_line, blank_line, hr,
- list, list_item,
                         inline_code,
                         template_,
                         code_block, macro,
@@ -121,10 +158,9 @@
             member1 mark;
         };
 
- struct block_parse_closure
- : cl::closure<block_parse_closure, bool>
+ struct block_item_closure : cl::closure<block_item_closure, bool>
         {
- member1 parse_blocks;
+ member1 still_in_block;
         };
 
         struct context_closure : cl::closure<context_closure, element_info::context>
@@ -135,24 +171,39 @@
         cl::rule<scanner, simple_markup_closure::context_t> simple_markup;
         cl::rule<scanner> simple_markup_end;
 
- cl::rule<scanner, block_parse_closure::context_t> top_level;
+ cl::rule<scanner, block_item_closure::context_t> paragraph;
+ cl::rule<scanner, context_closure::context_t> paragraph_item;
+ cl::rule<scanner, block_item_closure::context_t> list;
+ cl::rule<scanner, context_closure::context_t> list_item;
         cl::rule<scanner, context_closure::context_t> common;
         cl::rule<scanner, context_closure::context_t> element;
 
+ std::stack<list_stack_item> list_stack;
+ unsigned int list_indent;
+ block_types::values block_type;
+
         element_info info;
         element_info::type_enum element_type;
 
         quickbook::actions& actions_;
+ member_action<main_grammar_local> check_indentation;
+ member_action<main_grammar_local> check_code_block;
+ member_action<main_grammar_local> start_blocks;
+ member_action<main_grammar_local> end_blocks;
+ in_list_impl in_list;
         scoped_parser<process_element_impl> process_element;
- is_block_type is_block;
 
         ////////////////////////////////////////////////////////////////////////
         // Local constructor
 
         main_grammar_local(quickbook::actions& actions)
             : actions_(actions)
+ , check_indentation(*this, &main_grammar_local::check_indentation_impl)
+ , check_code_block(*this, &main_grammar_local::check_indentation_impl)
+ , start_blocks(*this, &main_grammar_local::start_blocks_impl)
+ , end_blocks(*this, &main_grammar_local::end_blocks_impl)
+ , in_list(*this)
             , process_element(*this)
- , is_block(*this)
             {}
     };
 
@@ -219,47 +270,85 @@
             ]
             ;
         // Top level blocks
- block_start = local.top_level;
+ block_start =
+ (*eol) [local.start_blocks]
+ >> (*local.top_level) [local.end_blocks]
+ ;
 
         local.top_level =
- cl::eps_p [local.top_level.parse_blocks = true]
- >> *( cl::eps_p(local.top_level.parse_blocks)
- >> local.blocks
- | local.element(element_info::in_block)
- [local.top_level.parse_blocks = false]
- >> !(cl::eps_p(local.is_block) >> +eol)
- [local.top_level.parse_blocks = true]
- | local.paragraph_separator [local.top_level.parse_blocks = true]
- | local.common(element_info::in_phrase)
- [local.top_level.parse_blocks = false]
+ cl::eps_p(local.indent_check)
+ >> ( cl::eps_p(ph::var(local.block_type) == block_types::code)
+ >> local.code
+ | cl::eps_p(ph::var(local.block_type) == block_types::list)
+ >> local.list
+ | cl::eps_p(ph::var(local.block_type) == block_types::paragraph)
+ >> ( local.hr
+ | local.paragraph
+ )
+ )
+ >> *eol
+ ;
+
+ local.indent_check =
+ ( *cl::blank_p
+ >> !( (cl::ch_p('*') | '#')
+ >> *cl::blank_p)
+ ) [local.check_indentation]
+ ;
+
+ local.paragraph =
+ cl::eps_p [local.paragraph.still_in_block = true]
+ >> local.paragraph_item(element_info::only_contextual_block)
+ >> *( cl::eps_p(local.paragraph.still_in_block)
+ >> local.paragraph_item(element_info::only_block)
                 )
>> cl::eps_p [actions.paragraph]
             ;
 
+ local.paragraph_item =
+ local.element(local.paragraph_item.context)
+ >> !eol [local.paragraph.still_in_block = false]
+ | local.paragraph_separator [local.paragraph.still_in_block = false]
+ | local.common(element_info::in_phrase)
+ ;
+
+ local.list =
+ *cl::blank_p
+ >> (cl::ch_p('*') | '#')
+ >> *cl::blank_p [local.list.still_in_block = true]
+ >> *( cl::eps_p(local.list.still_in_block)
+ >> local.list_item
+ )
+ >> cl::eps_p [actions.list_item]
+ ;
+
+ local.list_item =
+ cl::eps_p(local.paragraph_separator) [local.list.still_in_block = false]
+ | local.common(element_info::in_phrase)
+ ;
+
+ local.paragraph_separator =
+ cl::eol_p
+ >> cl::eps_p
+ ( *cl::blank_p
+ >> ( cl::eol_p
+ | cl::eps_p(local.in_list) >> (cl::ch_p('*') | '#')
+ )
+ )
+ >> *eol
+ ;
+
         // Blocks contains within an element, e.g. a table cell or a footnote.
         inside_paragraph =
             actions.values.save()
             [ *( local.paragraph_separator [actions.paragraph]
+ >> *eol
                 | ~cl::eps_p(']')
>> local.common(element_info::in_nested_block)
                 )
             ] [actions.paragraph]
             ;
 
- local.blocks =
- +( local.code
- | local.list
- | local.hr
- | +eol
- )
- ;
-
- local.paragraph_separator
- = cl::eol_p
- >> *cl::blank_p
- >> cl::eol_p [actions.paragraph]
- ;
-
         local.hr =
                 cl::str_p("----")
>> actions.values.list(block_tags::hr)
@@ -297,39 +386,18 @@
             ;
 
         local.code_line =
- cl::blank_p >> *(cl::anychar_p - cl::eol_p) >> (cl::eol_p | cl::end_p)
+ ( *cl::blank_p
+ >> ~cl::eps_p(cl::eol_p)
+ ) [local.check_code_block]
+ >> cl::eps_p(ph::var(local.block_type) == block_types::code)
+ >> *(cl::anychar_p - cl::eol_p)
+ >> (cl::eol_p | cl::end_p)
             ;
 
         local.blank_line =
             *cl::blank_p >> cl::eol_p
             ;
 
- local.list =
- cl::eps_p(cl::ch_p('*') | '#')
- >> actions.values.list(block_tags::list)
- [ +actions.values.list()
- [ (*cl::blank_p) [actions.values.entry(ph::arg1, ph::arg2, general_tags::list_indent)]
- >> (cl::ch_p('*') | '#')
- [actions.values.entry(ph::arg1, ph::arg2, general_tags::list_mark)]
- >> *cl::blank_p
- >> actions.to_value() [ local.list_item ]
- ]
- ] [actions.element]
- ;
-
- local.list_item =
- actions.values.save()
- [
- *( ~cl::eps_p
- ( cl::eol_p >> *cl::blank_p
- >> (cl::ch_p('*') | '#' | cl::eol_p)
- )
- >> local.common(element_info::in_phrase)
- )
- ]
- >> (+eol | cl::end_p)
- ;
-
         local.common =
                 local.macro
             | local.element(local.common.context)
@@ -621,4 +689,160 @@
>> +(cl::anychar_p - (cl::space_p | ']'))
             ;
     }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Indentation Handling
+
+ template <typename Iterator>
+ int indent_length(Iterator first, Iterator end)
+ {
+ int length = 0;
+ for(; first != end; ++first)
+ {
+ if (*first == '\t') {
+ // hardcoded tab to 4 for now
+ length = length + 4 - (length % 4);
+ }
+ else {
+ ++length;
+ }
+ }
+
+ return length;
+ }
+
+ void main_grammar_local::start_blocks_impl(parse_iterator, parse_iterator)
+ {
+ list_stack.push(list_stack_item());
+ }
+
+ void main_grammar_local::end_blocks_impl(parse_iterator, parse_iterator)
+ {
+ clear_stack();
+ list_stack.pop();
+ }
+
+ void main_grammar_local::check_indentation_impl(parse_iterator first_, parse_iterator last_)
+ {
+ string_iterator first = first_.base();
+ string_iterator last = last_.base();
+ string_iterator mark_pos = boost::find_first_of(
+ boost::make_iterator_range(first, last),
+ boost::as_literal("#*"));
+
+ if (mark_pos == last) {
+ plain_block(first, last);
+ }
+ else {
+ list_block(first, mark_pos, last);
+ }
+ }
+
+ void main_grammar_local::check_code_block_impl(parse_iterator first, parse_iterator last)
+ {
+ unsigned int new_indent = indent_length(first.base(), last.base());
+
+ block_type = (new_indent > list_stack.top().indent2) ?
+ block_types::code : block_types::none;
+ }
+
+ void main_grammar_local::plain_block(string_iterator first, string_iterator last)
+ {
+ if (qbk_version_n >= 106u) {
+ unsigned int new_indent = indent_length(first, last);
+
+ if (new_indent > list_stack.top().indent2) {
+ block_type = block_types::code;
+ }
+ else {
+ while (!list_stack.top().root && new_indent < list_stack.top().indent)
+ {
+ actions_.end_list_item();
+ actions_.end_list(list_stack.top().mark);
+ list_stack.pop();
+ list_indent = list_stack.top().indent;
+ }
+
+ if (!list_stack.top().root && new_indent == list_stack.top().indent)
+ {
+ list_stack_item save = list_stack.top();
+ list_stack.pop();
+ if (new_indent == list_stack.top().indent) {
+ actions_.end_list_item();
+ actions_.end_list(save.mark);
+ list_indent = list_stack.top().indent;
+ }
+ else {
+ list_stack.push(save);
+ }
+ }
+
+ block_type = block_types::paragraph;
+ }
+ }
+ else {
+ clear_stack();
+
+ if (last == first)
+ block_type = block_types::paragraph;
+ else
+ block_type = block_types::code;
+ }
+ }
+
+ void main_grammar_local::list_block(string_iterator first, string_iterator mark_pos,
+ string_iterator last)
+ {
+ unsigned int new_indent = indent_length(first, mark_pos);
+ unsigned int new_indent2 = indent_length(first, last);
+ char mark = *mark_pos;
+
+ if (list_stack.top().root && new_indent > 0) {
+ block_type = block_types::code;
+ return;
+ }
+
+ if (list_stack.top().root || new_indent > list_indent) {
+ list_stack.push(list_stack_item(mark, new_indent, new_indent2));
+ actions_.start_list(mark);
+ }
+ else if (new_indent == list_indent) {
+ actions_.end_list_item();
+ }
+ else {
+ // This should never reach root, since the first list
+ // has indentation 0.
+ while(!list_stack.top().root && new_indent < list_stack.top().indent)
+ {
+ actions_.end_list_item();
+ actions_.end_list(list_stack.top().mark);
+ list_stack.pop();
+ }
+
+ actions_.end_list_item();
+ }
+
+ list_indent = new_indent;
+
+ if (mark != list_stack.top().mark)
+ {
+ detail::outerr(actions_.current_file, first)
+ << "Illegal change of list style.\n";
+ detail::outwarn(actions_.current_file, first)
+ << "Ignoring change of list style." << std::endl;
+ ++actions_.error_count;
+ }
+
+ actions_.start_list_item();
+ block_type = block_types::list;
+ }
+
+ void main_grammar_local::clear_stack()
+ {
+ while (!list_stack.top().root) {
+ actions_.end_list_item();
+ actions_.end_list(list_stack.top().mark);
+ list_stack.pop();
+ }
+ }
 }

Modified: branches/quickbook-dev/tools/quickbook/src/quickbook.cpp
==============================================================================
--- branches/quickbook-dev/tools/quickbook/src/quickbook.cpp (original)
+++ branches/quickbook-dev/tools/quickbook/src/quickbook.cpp 2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
@@ -98,10 +98,8 @@
             pre(actor.out, actor, include_doc_id, docinfo_type);
 
             info = cl::parse(info.hit ? info.stop : first, last, actor.grammar().block);
- if (info.full)
- {
- post(actor.out, actor, docinfo_type);
- }
+
+ post(actor.out, actor, docinfo_type);
         }
 
         if (!info.full)
@@ -148,10 +146,10 @@
             result = 1;
         }
 
- std::string stage2 = ids.replace_placeholders(buffer.str());
-
         if (result == 0)
         {
+ std::string stage2 = ids.replace_placeholders(buffer.str());
+
             fs::ofstream fileout(fileout_);
 
             if (pretty_print)

Modified: branches/quickbook-dev/tools/quickbook/test/Jamfile.v2
==============================================================================
--- branches/quickbook-dev/tools/quickbook/test/Jamfile.v2 (original)
+++ branches/quickbook-dev/tools/quickbook/test/Jamfile.v2 2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
@@ -60,6 +60,7 @@
     [ quickbook-test link-1_1 ]
     [ quickbook-test link-1_6 ]
     [ quickbook-test list_test-1_5 ]
+ [ quickbook-test list_test-1_6 ]
     [ quickbook-test macro-1_5 ]
     [ quickbook-test macro-1_6 ]
     [ quickbook-error-test mismatched_brackets-1_1-fail ]

Modified: branches/quickbook-dev/tools/quickbook/test/list_test-1_5.gold
==============================================================================
--- branches/quickbook-dev/tools/quickbook/test/list_test-1_5.gold (original)
+++ branches/quickbook-dev/tools/quickbook/test/list_test-1_5.gold 2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
@@ -211,6 +211,77 @@
     </listitem>
   </orderedlist>
   <para>
+ Inconsistent Indentation:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <simpara>
+ A1
+ <itemizedlist>
+ <listitem>
+ <simpara>
+ B1
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ B2
+ <itemizedlist>
+ <listitem>
+ <simpara>
+ C1
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ C2
+ </simpara>
+ </listitem>
+ </itemizedlist>
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ B3
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ B4
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ B5
+ <itemizedlist>
+ <listitem>
+ <simpara>
+ C3
+ </simpara>
+ </listitem>
+ </itemizedlist>
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ B6
+ </simpara>
+ </listitem>
+ </itemizedlist>
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ A2
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ A3
+ </simpara>
+ </listitem>
+ </itemizedlist>
+ <para>
     Markup in list:
   </para>
   <itemizedlist>
@@ -239,6 +310,58 @@
       </simpara>
     </listitem>
   </itemizedlist>
+ <para>
+ Don't end list with comment 1:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <simpara>
+ A1
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ A2
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ A3
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ A4
+ </simpara>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Don't end list with comment 2:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <simpara>
+ A1
+ <itemizedlist>
+ <listitem>
+ <simpara>
+ B1
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ B2
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ B3
+ </simpara>
+ </listitem>
+ </itemizedlist>
+ </simpara>
+ </listitem>
+ </itemizedlist>
   <section id="list_test.list_immediately_following_markup">
     <title><link linkend="list_test.list_immediately_following_markup">List immediately
     following markup</link></title>

Modified: branches/quickbook-dev/tools/quickbook/test/list_test-1_5.quickbook
==============================================================================
--- branches/quickbook-dev/tools/quickbook/test/list_test-1_5.quickbook (original)
+++ branches/quickbook-dev/tools/quickbook/test/list_test-1_5.quickbook 2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
@@ -52,6 +52,21 @@
 # G
 # H
 
+Inconsistent Indentation:
+
+* A1
+ * B1
+ * B2
+ * C1
+ * C2
+ * B3
+ * B4
+ * B5
+ * C3
+ * B6
+ * A2
+* A3
+
 Markup in list:
 
 * *Bold*
@@ -59,6 +74,24 @@
 * ["Quoted]
 * [footnote Footnote]
 
+Don't end list with comment 1:
+
+* A1
+* A2
+
+[/ End list?]
+* A3
+* A4
+
+Don't end list with comment 2:
+
+* A1
+ * B1
+
+[/ End list?]
+ * B2
+ * B3
+
 [section List immediately following markup]
 * One
 * Two

Copied: branches/quickbook-dev/tools/quickbook/test/list_test-1_6.gold (from r75445, /branches/quickbook-dev/tools/quickbook/test/list_test-1_5.gold)
==============================================================================
--- /branches/quickbook-dev/tools/quickbook/test/list_test-1_5.gold (original)
+++ branches/quickbook-dev/tools/quickbook/test/list_test-1_6.gold 2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
@@ -211,6 +211,77 @@
     </listitem>
   </orderedlist>
   <para>
+ Inconsistent Indentation:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <simpara>
+ A1
+ <itemizedlist>
+ <listitem>
+ <simpara>
+ B1
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ B2
+ <itemizedlist>
+ <listitem>
+ <simpara>
+ C1
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ C2
+ </simpara>
+ </listitem>
+ </itemizedlist>
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ B3
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ B4
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ B5
+ <itemizedlist>
+ <listitem>
+ <simpara>
+ C3
+ </simpara>
+ </listitem>
+ </itemizedlist>
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ B6
+ </simpara>
+ </listitem>
+ </itemizedlist>
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ A2
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ A3
+ </simpara>
+ </listitem>
+ </itemizedlist>
+ <para>
     Markup in list:
   </para>
   <itemizedlist>
@@ -239,8 +310,60 @@
       </simpara>
     </listitem>
   </itemizedlist>
- <section id="list_test.list_immediately_following_markup">
- <title><link linkend="list_test.list_immediately_following_markup">List immediately
+ <para>
+ Don't end list with comment 1:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <simpara>
+ A1
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ A2
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ A3
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ A4
+ </simpara>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Don't end list with comment 2:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <simpara>
+ A1
+ <itemizedlist>
+ <listitem>
+ <simpara>
+ B1
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ B2
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ B3
+ </simpara>
+ </listitem>
+ </itemizedlist>
+ </simpara>
+ </listitem>
+ </itemizedlist>
+ <section id="list_test.list_immediately_following_marku">
+ <title><link linkend="list_test.list_immediately_following_marku">List immediately
     following markup</link></title>
     <itemizedlist>
       <listitem>
@@ -260,4 +383,38 @@
       </listitem>
     </itemizedlist>
   </section>
+ <section id="list_test.paragraphs_in_list_items">
+ <title><link linkend="list_test.paragraphs_in_list_items">Paragraphs in list
+ items</link></title>
+ <itemizedlist>
+ <listitem>
+ <simpara>
+ One
+ <para>
+ Two
+ </para>
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ Three
+ <itemizedlist>
+ <listitem>
+ <simpara>
+ Four
+ <para>
+ Five
+ </para>
+ </simpara>
+ </listitem>
+ </itemizedlist>
+ </simpara>
+ </listitem>
+ <listitem>
+ <simpara>
+ Six
+ </simpara>
+ </listitem>
+ </itemizedlist>
+ </section>
 </article>

Copied: branches/quickbook-dev/tools/quickbook/test/list_test-1_6.quickbook (from r75445, /branches/quickbook-dev/tools/quickbook/test/list_test-1_5.quickbook)
==============================================================================
--- /branches/quickbook-dev/tools/quickbook/test/list_test-1_5.quickbook (original)
+++ branches/quickbook-dev/tools/quickbook/test/list_test-1_6.quickbook 2011-11-10 13:17:00 EST (Thu, 10 Nov 2011)
@@ -1,5 +1,5 @@
 [article List Test
-[quickbook 1.5]
+[quickbook 1.6]
 ]
 
 Simple list:
@@ -52,6 +52,21 @@
 # G
 # H
 
+Inconsistent Indentation:
+
+* A1
+ * B1
+ * B2
+ * C1
+ * C2
+ * B3
+ * B4
+ * B5
+ * C3
+ * B6
+ * A2
+* A3
+
 Markup in list:
 
 * *Bold*
@@ -59,9 +74,41 @@
 * ["Quoted]
 * [footnote Footnote]
 
+Don't end list with comment 1:
+
+* A1
+* A2
+
+[/ End list?]
+* A3
+* A4
+
+Don't end list with comment 2:
+
+* A1
+ * B1
+
+[/ End list?]
+ * B2
+ * B3
+
 [section List immediately following markup]
 * One
 * Two
 * Three
 
 [endsect]
+
+[section Paragraphs in list items]
+
+* One
+
+ Two
+
+* Three
+ * Four
+
+ Five
+* Six
+
+[endsect]
\ No newline at end of file


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk