diff --git a/doc/1_6.qbk b/doc/1_6.qbk
index 89c41f2..e9ce035 100644
--- a/doc/1_6.qbk
+++ b/doc/1_6.qbk
@@ -235,12 +235,60 @@ if you're totally sure that you will need it.
[section:elements New Elements]
-New elements in 1.6 (to be documented later):
+[section:block `block`]
-* `block`
-* `ordered_list`
-* `itemized_list`
-* `role`
+`block` is a block element that just marks its contents as a block,
+so that they aren't wrapped in paragraph tags. The main use is
+for escaped docbook block tags, such as:
+
+ [template chapter[title] [block''''''[title]'''''']]
+ [template chapterend [block'''''']]
+
+ [chapter An example chapter]
+
+ Content
+
+ [chapterend]
+
+Without the `block` element, the `chapter` and `chapterend` templates
+would be wrapped in paragraph tags.
+
+[endsect]
+
+[section:lists `ordered_list` and `itemized_list`]
+
+These are used as an alternative to the normal wiki-style markup for
+lists. They make it easier to nest lists inside other elements, and
+nest elements inside lists. The markup is similar to a single level
+table:
+
+ [ordered_list [item1][item2]]
+
+is equivalent to:
+
+ # item1
+ # item2
+
+[endsect]
+
+[section:role `role`]
+
+`role` is a phrase element used to mark up the text in the eventual html
+with an a class. For example:
+
+ [role red Text content]
+
+Will generate the docbook:
+
+ Text content
+
+Which will generate html along the lines of:
+
+ Text content
+
+And then you can use css to style this however you wish.
+
+[endsect]
[endsect]
diff --git a/doc/change_log.qbk b/doc/change_log.qbk
index fc49b86..aacd813 100644
--- a/doc/change_log.qbk
+++ b/doc/change_log.qbk
@@ -274,3 +274,12 @@ Boost 1.46.1:
* Callouts in code blocks.
* Escaped docbook in docinfo blocks.
* Starting to implement calling templates from link values.
+
+[heading Version 1.5.9 - Boost 1.54]
+
+* When code blocks are indented using a mixture of tabs and spaces,
+ convert indentation to spaces.
+* Internal changes:
+ * Convert to use `boost::string_ref`.
+ * Clean up the source map implementation (used to get the correct
+ location for error messages in things like templates and snippets).
diff --git a/src/Jamfile.v2 b/src/Jamfile.v2
index 0c55c7a..e699cd9 100644
--- a/src/Jamfile.v2
+++ b/src/Jamfile.v2
@@ -27,9 +27,9 @@ exe quickbook
actions.cpp
doc_info_actions.cpp
state.cpp
+ dependency_tracker.cpp
utils.cpp
files.cpp
- string_ref.cpp
input_path.cpp
values.cpp
id_manager.cpp
diff --git a/src/actions.cpp b/src/actions.cpp
index 304663f..fdfa5eb 100644
--- a/src/actions.cpp
+++ b/src/actions.cpp
@@ -63,7 +63,7 @@ namespace quickbook
}
std::string add_anchor(quickbook::state& state,
- std::string const& id,
+ boost::string_ref id,
id_category::categories category =
id_category::explicit_anchor_id)
{
@@ -474,7 +474,7 @@ namespace quickbook
if (saved_conditional)
{
- string_ref macro1 = values.consume().get_quickbook();
+ boost::string_ref macro1 = values.consume().get_quickbook();
std::string macro(macro1.begin(), macro1.end());
state.conditional = find(state.macro, macro.c_str());
@@ -702,7 +702,7 @@ namespace quickbook
int code_tag = code_block.get_tag();
value_consumer values = code_block;
- string_ref code_value = values.consume().get_quickbook();
+ boost::string_ref code_value = values.consume().get_quickbook();
values.finish();
bool inline_code = code_tag == code_tags::inline_code ||
@@ -710,7 +710,7 @@ namespace quickbook
bool block = code_tag != code_tags::inline_code;
std::string source_mode = state.source_mode_next.empty() ?
- state.source_mode : state.source_mode_next.get_quickbook();
+ state.source_mode : detail::to_s(state.source_mode_next.get_quickbook());
state.source_mode_next = value();
if (inline_code) {
@@ -726,17 +726,17 @@ namespace quickbook
// preprocess the code section to remove the initial indentation
mapped_file_builder mapped;
mapped.start(state.current_file);
- mapped.unindent_and_add(code_value.begin(), code_value.end());
+ mapped.unindent_and_add(code_value);
file_ptr f = mapped.release();
- if (f->source.empty())
+ if (f->source().empty())
return; // Nothing left to do here. The program is empty.
if (qbk_version_n >= 107u) state.start_callouts();
- parse_iterator first_(f->source.begin());
- parse_iterator last_(f->source.end());
+ parse_iterator first_(f->source().begin());
+ parse_iterator last_(f->source().end());
file_ptr saved_file = f;
boost::swap(state.current_file, saved_file);
@@ -813,8 +813,8 @@ namespace quickbook
detail::print_string(v.get_encoded(), out);
}
else {
- std::string value = v.get_quickbook();
- for(std::string::const_iterator
+ boost::string_ref value = v.get_quickbook();
+ for(boost::string_ref::const_iterator
first = value.begin(), last = value.end();
first != last; ++first)
{
@@ -841,8 +841,10 @@ namespace quickbook
value_consumer pair = pair_;
value name = pair.consume();
value value = pair.consume();
+ std::string name_str(name.get_quickbook().begin(),
+ name.get_quickbook().end());
pair.finish();
- if(!attributes.insert(std::make_pair(name.get_quickbook(), value)).second)
+ if(!attributes.insert(std::make_pair(name_str, value)).second)
{
detail::outwarn(name.get_file(), name.get_position())
<< "Duplicate image attribute: "
@@ -860,7 +862,7 @@ namespace quickbook
std::string fileref = attributes["fileref"].is_encoded() ?
attributes["fileref"].get_encoded() :
- attributes["fileref"].get_quickbook();
+ detail::to_s(attributes["fileref"].get_quickbook());
// Check for windows paths, then convert.
// A bit crude, but there you go.
@@ -937,7 +939,7 @@ namespace quickbook
// Now load the SVG file:
//
std::string svg_text;
- if (state.add_dependency(img)) {
+ if (state.dependencies.add_dependency(img)) {
fs::ifstream fs(img);
std::stringstream buffer;
buffer << fs.rdbuf();
@@ -1006,7 +1008,7 @@ namespace quickbook
void macro_definition_action(quickbook::state& state, quickbook::value macro_definition)
{
value_consumer values = macro_definition;
- std::string macro_id = values.consume().get_quickbook();
+ std::string macro_id = detail::to_s(values.consume().get_quickbook());
value phrase_value = values.optional_consume();
std::string phrase;
if (phrase_value.check()) phrase = phrase_value.get_encoded();
@@ -1035,11 +1037,11 @@ namespace quickbook
void template_body_action(quickbook::state& state, quickbook::value template_definition)
{
value_consumer values = template_definition;
- std::string identifier = values.consume().get_quickbook();
+ std::string identifier = detail::to_s(values.consume().get_quickbook());
std::vector template_values;
BOOST_FOREACH(value const& p, values.consume()) {
- template_values.push_back(p.get_quickbook());
+ template_values.push_back(detail::to_s(p.get_quickbook()));
}
BOOST_ASSERT(values.check(template_tags::block) || values.check(template_tags::phrase));
@@ -1207,7 +1209,7 @@ namespace quickbook
file_ptr saved_current_file = state.current_file;
state.current_file = content.get_file();
- string_ref source = content.get_quickbook();
+ boost::string_ref source = content.get_quickbook();
parse_iterator first(source.begin());
parse_iterator last(source.end());
@@ -1363,7 +1365,7 @@ namespace quickbook
bool template_escape = values.check(template_tags::escape);
if(template_escape) values.consume();
- std::string identifier = values.consume(template_tags::identifier).get_quickbook();
+ std::string identifier = detail::to_s(values.consume(template_tags::identifier).get_quickbook());
std::vector args;
@@ -1480,7 +1482,7 @@ namespace quickbook
// Note: dst is never actually encoded as boostbook, which
// is why the result is called with 'print_string' later.
std::string dst = dst_value.is_encoded() ?
- dst_value.get_encoded() : dst_value.get_quickbook();
+ dst_value.get_encoded() : detail::to_s(dst_value.get_quickbook());
state.phrase << markup.pre;
detail::print_string(dst, state.phrase.get());
@@ -1499,7 +1501,7 @@ namespace quickbook
write_anchors(state, state.out);
value_consumer values = variable_list;
- std::string title = values.consume(table_tags::title).get_quickbook();
+ std::string title = detail::to_s(values.consume(table_tags::title).get_quickbook());
state.out << "\n";
@@ -1538,7 +1540,7 @@ namespace quickbook
std::string element_id;
if(values.check(general_tags::element_id))
- element_id = values.consume().get_quickbook();
+ element_id = detail::to_s(values.consume().get_quickbook());
value title = values.consume(table_tags::title);
bool has_title = !title.empty();
@@ -1785,7 +1787,7 @@ namespace quickbook
// Counter-intuitively: encoded == plain text here.
std::string path_text = qbk_version_n >= 106u || path.is_encoded() ?
- path.get_encoded() : path.get_quickbook();
+ path.get_encoded() : detail::to_s(path.get_quickbook());
if(path_text.find('\\') != std::string::npos)
{
@@ -1875,7 +1877,7 @@ namespace quickbook
state.current_file->path.parent_path() / path;
// See if it can be found locally first.
- if (state.add_dependency(local_path))
+ if (state.dependencies.add_dependency(local_path))
{
result.insert(include_search_return(
local_path,
@@ -1887,7 +1889,7 @@ namespace quickbook
{
full /= path;
- if (state.add_dependency(full))
+ if (state.dependencies.add_dependency(full))
{
result.insert(include_search_return(full, path));
return result;
@@ -1896,7 +1898,7 @@ namespace quickbook
}
else
{
- if (state.add_dependency(path)) {
+ if (state.dependencies.add_dependency(path)) {
result.insert(include_search_return(path, path));
return result;
}
diff --git a/src/code_snippet.cpp b/src/code_snippet.cpp
index 4c63a3b..e8334dd 100644
--- a/src/code_snippet.cpp
+++ b/src/code_snippet.cpp
@@ -12,7 +12,6 @@
#include
#include
#include
-#include
#include "block_tags.hpp"
#include "template_stack.hpp"
#include "actions.hpp"
@@ -30,7 +29,7 @@ namespace quickbook
code_snippet_actions(std::vector& storage,
file_ptr source_file,
char const* source_type)
- : last_code_pos(source_file->source.begin())
+ : last_code_pos(source_file->source().begin())
, in_code(false)
, snippet_stack()
, storage(storage)
@@ -63,13 +62,13 @@ namespace quickbook
std::string id;
bool start_code;
- std::string::const_iterator source_pos;
+ string_iterator source_pos;
mapped_file_builder::pos start_pos;
boost::shared_ptr next;
};
void push_snippet_data(std::string const& id,
- std::string::const_iterator pos)
+ string_iterator pos)
{
boost::shared_ptr new_snippet(new snippet_data(id));
new_snippet->next = snippet_stack;
@@ -88,8 +87,8 @@ namespace quickbook
}
mapped_file_builder content;
- std::string::const_iterator mark_begin, mark_end;
- std::string::const_iterator last_code_pos;
+ boost::string_ref::const_iterator mark_begin, mark_end;
+ boost::string_ref::const_iterator last_code_pos;
bool in_code;
boost::shared_ptr snippet_stack;
std::vector& storage;
@@ -352,8 +351,8 @@ namespace quickbook
bool is_python = extension == ".py";
code_snippet_actions a(storage, load(filename, qbk_version_n), is_python ? "[python]" : "[c++]");
- string_iterator first(a.source_file->source.begin());
- string_iterator last(a.source_file->source.end());
+ string_iterator first(a.source_file->source().begin());
+ string_iterator last(a.source_file->source().end());
cl::parse_info info;
@@ -376,14 +375,14 @@ namespace quickbook
if (last_code_pos != first) {
if (!in_code)
{
- content.add("\n\n", last_code_pos);
- content.add(source_type, last_code_pos);
- content.add("```\n", last_code_pos);
+ content.add_at_pos("\n\n", last_code_pos);
+ content.add_at_pos(source_type, last_code_pos);
+ content.add_at_pos("```\n", last_code_pos);
in_code = true;
}
- content.add(last_code_pos, first);
+ content.add(boost::string_ref(last_code_pos, first - last_code_pos));
}
}
@@ -396,7 +395,7 @@ namespace quickbook
if (in_code)
{
- content.add("\n```\n\n", last_code_pos);
+ content.add_at_pos("\n```\n\n", last_code_pos);
in_code = false;
}
}
@@ -414,13 +413,13 @@ namespace quickbook
if (!in_code)
{
- content.add("\n\n", first);
- content.add(source_type, first);
- content.add("```\n", first);
+ content.add_at_pos("\n\n", first);
+ content.add_at_pos(source_type, first);
+ content.add_at_pos("```\n", first);
in_code = true;
}
- content.add(mark_begin, mark_end);
+ content.add(boost::string_ref(mark_begin, mark_end - mark_begin));
}
void code_snippet_actions::escaped_comment(string_iterator first, string_iterator last)
@@ -437,8 +436,8 @@ namespace quickbook
snippet_data& snippet = *snippet_stack;
- content.add("\n", mark_begin);
- content.unindent_and_add(mark_begin, mark_end);
+ content.add_at_pos("\n", mark_begin);
+ content.unindent_and_add(boost::string_ref(mark_begin, mark_end - mark_begin));
if (snippet.id == "!")
{
@@ -516,13 +515,13 @@ namespace quickbook
mapped_file_builder f;
f.start(source_file);
if (snippet->start_code) {
- f.add("\n\n", snippet->source_pos);
- f.add(source_type, snippet->source_pos);
- f.add("```\n", snippet->source_pos);
+ f.add_at_pos("\n\n", snippet->source_pos);
+ f.add_at_pos(source_type, snippet->source_pos);
+ f.add_at_pos("```\n", snippet->source_pos);
}
f.add(content, snippet->start_pos, content.get_pos());
if (in_code) {
- f.add("\n```\n\n", position);
+ f.add_at_pos("\n```\n\n", position);
}
std::vector params;
@@ -530,7 +529,7 @@ namespace quickbook
file_ptr body = f.release();
storage.push_back(template_symbol(snippet->id, params,
- qbk_value(body, body->source.begin(), body->source.end(),
+ qbk_value(body, body->source().begin(), body->source().end(),
template_tags::snippet)));
}
}
diff --git a/src/dependency_tracker.cpp b/src/dependency_tracker.cpp
new file mode 100644
index 0000000..53d24d2
--- /dev/null
+++ b/src/dependency_tracker.cpp
@@ -0,0 +1,83 @@
+/*=============================================================================
+ Copyright (c) 2013 Daniel James
+
+ Use, modification and distribution is subject to the Boost Software
+ License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+ http://www.boost.org/LICENSE_1_0.txt)
+=============================================================================*/
+
+#include "dependency_tracker.hpp"
+#include "input_path.hpp"
+#include
+#include
+
+namespace quickbook
+{
+ // Convert the path to its canonical representation if it exists.
+ // Or something close if it doesn't.
+ static fs::path normalize_path(fs::path const& path)
+ {
+ fs::path p = fs::absolute(path); // The base of the path.
+ fs::path extra; // The non-existant part of the path.
+ int parent_count = 0; // Number of active '..' sections
+
+ // Invariant: path is equivalent to: p / ('..' * parent_count) / extra
+ // i.e. if parent_count == 0: p/extra
+ // if parent_count == 2: p/../../extra
+
+ // Pop path sections from path until we find an existing
+ // path, adjusting for any dot path sections.
+ while (!fs::exists(fs::status(p))) {
+ fs::path name = p.filename();
+ p = p.parent_path();
+ if (name == "..") {
+ ++parent_count;
+ }
+ else if (name == ".") {
+ }
+ else if (parent_count) {
+ --parent_count;
+ }
+ else {
+ extra = name / extra;
+ }
+ }
+
+ // If there are any left over ".." sections, then add them
+ // on to the end of the real path, and trust Boost.Filesystem
+ // to sort them out.
+ while (parent_count) {
+ p = p / "..";
+ --parent_count;
+ }
+
+ // Cannoicalize the existing part of the path, and add 'extra' back to
+ // the end.
+ return fs::canonical(p) / extra;
+ }
+
+ bool dependency_tracker::add_dependency(fs::path const& f) {
+ bool found = fs::exists(fs::status(f));
+ dependencies[normalize_path(f)] |= found;
+ return found;
+ }
+
+ void dependency_tracker::write_dependencies(std::ostream& out)
+ {
+ BOOST_FOREACH(dependency_list::value_type const& d, dependencies)
+ {
+ if (d.second) {
+ out << detail::path_to_generic(d.first) << std::endl;
+ }
+ }
+ }
+
+ void dependency_tracker::write_checked_locations(std::ostream& out)
+ {
+ BOOST_FOREACH(dependency_list::value_type const& d, dependencies)
+ {
+ out << (d.second ? "+ " : "- ")
+ << detail::path_to_generic(d.first) << std::endl;
+ }
+ }
+}
diff --git a/src/dependency_tracker.hpp b/src/dependency_tracker.hpp
new file mode 100644
index 0000000..bbf991c
--- /dev/null
+++ b/src/dependency_tracker.hpp
@@ -0,0 +1,37 @@
+/*=============================================================================
+ Copyright (c) 2013 Daniel James
+
+ Use, modification and distribution is subject to the Boost Software
+ License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+ http://www.boost.org/LICENSE_1_0.txt)
+=============================================================================*/
+
+#if !defined(QUICKBOOK_DEPENDENCY_TRACKER_HPP)
+#define QUICKBOOK_DEPENDENCY_TRACKER_HPP
+
+#include