📄 actions.hpp
字号:
/*=============================================================================
Copyright (c) 2002 2004 Joel de Guzman
Copyright (c) 2004 Eric Niebler
http://spirit.sourceforge.net/
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(BOOST_SPIRIT_QUICKBOOK_ACTIONS_HPP)
#define BOOST_SPIRIT_QUICKBOOK_ACTIONS_HPP
#include <time.h>
#include <string>
#include <vector>
#include <stack>
#include <algorithm>
#include <sstream>
#include <boost/spirit/iterator/position_iterator.hpp>
#include "../syntax_highlight.hpp"
#include "utils.hpp"
namespace quickbook
{
struct error_action
{
// Prints an error message to std::cerr
template <typename Iterator>
void operator()(Iterator const& first, Iterator const& /*last*/) const
{
boost::spirit::file_position const pos = first.get_position();
std::cerr
<< "Syntax Error at \"" << pos.file
<< "\" line " << pos.line
<< ", column " << pos.column << ".\n";
}
};
struct phrase_action
{
// Handles paragraph, h1, h2, h3, h4, h5, h6,
// blurb, blockquote, preformatted, list_item,
// unordered_list, ordered_list
phrase_action(
std::ostream& out,
std::stringstream& phrase,
std::string& section_id,
std::string const& pre,
std::string const& post,
bool anchor = false)
: out(out)
, phrase(phrase)
, section_id(section_id)
, pre(pre)
, post(post)
, anchor(anchor) {}
template <typename Iterator>
void operator()(Iterator const& first, Iterator const& last) const
{
if (out)
{
std::string str = phrase.str();
if (anchor)
out << "<anchor id=\""
<< section_id << '.'
<< detail::make_identifier(str.begin(), str.end())
<< "\" />";
phrase.str(std::string());
out << pre << str << post;
}
}
std::ostream& out;
std::stringstream& phrase;
std::string& section_id;
std::string pre;
std::string post;
bool anchor;
};
struct simple_phrase_action
{
// Handles simple text formats
simple_phrase_action(
std::ostream& out,
std::string const& pre,
std::string const& post)
: out(out)
, pre(pre)
, post(post) {}
template <typename Iterator>
void operator()(Iterator first, Iterator const& last) const
{
if (out)
{
out << pre;
while (first != last)
detail::print_char(*first++, out);
out << post;
}
}
std::ostream& out;
std::string pre;
std::string post;
};
struct list_action
{
// Handles lists
typedef std::pair<char, int> mark_type;
list_action(
std::ostream& out
, std::stringstream& list_buffer
, int& indent
, std::stack<mark_type>& list_marks)
: out(out)
, list_buffer(list_buffer)
, indent(indent)
, list_marks(list_marks) {}
template <typename Iterator>
void operator()(Iterator const& first, Iterator const& last) const
{
assert(!list_marks.empty()); // there must be at least one item in the stack
std::string str = list_buffer.str();
list_buffer.str(std::string());
out << str;
while (!list_marks.empty())
{
char mark = list_marks.top().first;
list_marks.pop();
out << std::string((mark == '#') ? "\n</orderedlist>" : "\n</itemizedlist>");
if (list_marks.size() >= 1)
out << std::string("\n</listitem>");
}
indent = -1; // reset
}
std::ostream& out;
std::stringstream& list_buffer;
int& indent;
std::stack<mark_type>& list_marks;
};
struct list_format_action
{
// Handles list formatting and hierarchy
typedef std::pair<char, int> mark_type;
list_format_action(
std::stringstream& out
, int& indent
, std::stack<mark_type>& list_marks)
: out(out)
, indent(indent)
, list_marks(list_marks) {}
template <typename Iterator>
void operator()(Iterator first, Iterator const& last) const
{
int new_indent = 0;
while (first != last && (*first == ' ' || *first == '\t'))
{
char mark = *first++;
if (mark == ' ')
{
++new_indent;
}
else // must be a tab
{
assert(mark == '\t');
// hardcoded tab to 4 for now
new_indent = ((new_indent + 4) / 4) * 4;
}
}
char mark = *first;
assert(mark == '#' || mark == '*'); // expecting a mark
if (indent == -1) // the very start
{
assert(new_indent == 0);
}
if (new_indent > indent)
{
//~ char parent_mark = 0;
//~ if (list_marks.size() >= 1)
//~ parent_mark = list_marks.top().first;
indent = new_indent;
list_marks.push(mark_type(mark, indent));
if (list_marks.size() > 1)
{
// Make this new list a child of the previous list.
// The previous listelem has already ended so we erase
// </listitem> to accomodate this sub-list. We'll close
// the listelem later.
std::string str = out.str();
std::string::size_type pos = str.rfind("\n</listitem>");
assert(pos <= str.size());
str.erase(str.begin()+pos, str.end());
out.str(std::string());
out << str;
//~ out << std::string((parent_mark == '#') ? "<orderedlist>\n" : "<itemizedlist>\n");
}
//~ else
//~ {
out << std::string((mark == '#') ? "<orderedlist>\n" : "<itemizedlist>\n");
//~ }
}
else if (new_indent < indent)
{
assert(!list_marks.empty());
indent = new_indent;
//~ list_marks.pop();
//~ out << std::string((mark == '#') ? "\n</orderedlist>" : "\n</itemizedlist>");
//~ if (list_marks.size() >= 1)
//~ out << std::string("\n</listitem>");
while (!list_marks.empty() && (indent < list_marks.top().second))
{
char mark = list_marks.top().first;
list_marks.pop();
out << std::string((mark == '#') ? "\n</orderedlist>" : "\n</itemizedlist>");
if (list_marks.size() >= 1)
out << std::string("\n</listitem>");
}
}
if (mark != list_marks.top().first) // new_indent == indent
{
boost::spirit::file_position const pos = first.get_position();
std::cerr
<< "Illegal change of list style at \"" << pos.file
<< "\" line " << pos.line
<< ", column " << pos.column << ".\n";
std::cerr << "Ignoring change of list style" << std::endl;
}
}
std::stringstream& out;
int& indent;
std::stack<mark_type>& list_marks;
};
struct span
{
// Decorates c++ code fragments
span(char const* name, std::ostream& out)
: name(name), out(out) {}
template <typename Iterator>
void operator()(Iterator first, Iterator last) const
{
if (out)
{
out << "<phrase role=\"" << name << "\">";
while (first != last)
detail::print_char(*first++, out);
out << "</phrase>";
}
}
char const* name;
std::ostream& out;
};
struct unexpected_char
{
// Handles unexpected chars in c++ syntax
unexpected_char(std::ostream& out)
: out(out) {}
template <typename Char>
void operator()(Char) const
{
if (out)
out << '#'; // print out an unexpected character
}
std::ostream& out;
};
struct anchor_action
{
// Handles anchors
anchor_action(std::ostream& out)
: out(out) {}
template <typename Iterator>
void operator()(Iterator first, Iterator last) const
{
if (out)
{
out << "<anchor id=\"";
while (first != last)
detail::print_char(*first++, out);
out << "\" />\n";
}
}
std::ostream& out;
};
char const* quickbook_get_date = "__quickbook_get_date__";
char const* quickbook_get_time = "__quickbook_get_time__";
struct do_macro_action
{
// Handles macro substitutions
do_macro_action(std::ostream& phrase)
: phrase(phrase) {}
void operator()(std::string const& str) const
{
if (str == quickbook_get_date)
{
char strdate[ 64 ];
time_t t = time(0);
strftime( strdate, sizeof(strdate), "%Y-%b-%d", localtime(&t) );
phrase << strdate;
}
else if (str == quickbook_get_time)
{
char strdate[ 64 ];
time_t t = time(0);
strftime( strdate, sizeof(strdate), "%I:%M:%S %p", localtime(&t) );
phrase << strdate;
}
else
{
phrase << str;
}
}
std::ostream& phrase;
};
struct space
{
// Prints a space
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -