📄 actions.cpp
字号:
/*============================================================================= Copyright (c) 2002 2004 2006 Joel de Guzman Copyright (c) 2004 Eric Niebler Copyright (c) 2005 Thomas Guest 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)=============================================================================*/#include <numeric>#include <functional>#include <boost/bind.hpp>#include <boost/filesystem/convenience.hpp>#include <boost/filesystem/fstream.hpp>#include <boost/lexical_cast.hpp>#include "./actions.hpp"#include "./utils.hpp"#include "./markups.hpp"#include "./actions_class.hpp"#include "../block.hpp"#include "../phrase.hpp"#include "../code_snippet.hpp"namespace quickbook{ // Handles line-breaks (DEPRECATED!!!) void break_action::operator()(iterator first, iterator) const { boost::spirit::file_position const pos = first.get_position(); detail::outwarn(pos.file,pos.line) << "in column:" << pos.column << ", " << "[br] and \\n are deprecated" << ".\n"; phrase << break_mark; } void error_action::operator()(iterator first, iterator /*last*/) const { boost::spirit::file_position const pos = first.get_position(); detail::outerr(pos.file,pos.line) << "Syntax Error near column " << pos.column << ".\n"; } void phrase_action::operator()(iterator first, iterator last) const { std::string str; phrase.swap(str); out << pre << str << post; } void header_action::operator()(iterator first, iterator last) const { std::string str; phrase.swap(str); if (qbk_version_n < 103) // version 1.2 and below { out << "<anchor id=\"" << section_id << '.' << detail::make_identifier(str.begin(), str.end()) << "\" />" << pre << str << post ; } else // version 1.3 and above { std::string anchor = library_id + '.' + qualified_section_id + '.' + detail::make_identifier(str.begin(), str.end()); out << "<anchor id=\"" << anchor << "\"/>" << pre << "<link linkend=\"" << anchor << "\">" << str << "</link>" << post ; } } void generic_header_action::operator()(iterator first, iterator last) const { int level_ = section_level + 2; // section_level is zero-based. We need to use a // 0ne-based heading which is one greater // than the current. Thus: section_level + 2. if (level_ > 6) // The max is h6, clip it if it goes level_ = 6; // further than that std::string str; phrase.swap(str); std::string anchor = library_id + '.' + qualified_section_id + '.' + detail::make_identifier(str.begin(), str.end()); out << "<anchor id=\"" << anchor << "\"/>" << "<bridgehead renderas=\"sect" << level_ << "\">" << "<link linkend=\"" << anchor << "\">" << str << "</link>" << "</bridgehead>" ; } void simple_phrase_action::operator()(iterator first, iterator last) const { out << pre; std::string str(first, last); if (std::string const* ptr = find(macro, str.c_str())) { out << *ptr; } else { while (first != last) detail::print_char(*first++, out.get()); } out << post; } void cond_phrase_action_pre::operator()(iterator first, iterator last) const { std::string str(first, last); conditions.push_back(find(macro, str.c_str())); out.push(); // save the stream } void cond_phrase_action_post::operator()(iterator first, iterator last) const { bool symbol_found = conditions.back(); conditions.pop_back(); if (first == last || !symbol_found) { out.pop(); // restore the stream } else { std::string save; out.swap(save); out.pop(); // restore the stream out << save; // print the body } } void list_action::operator()(iterator first, iterator last) const { BOOST_ASSERT(!list_marks.empty()); // there must be at least one item in the stack out << list_buffer.str(); list_buffer.clear(); 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>"); } list_indent = -1; // reset } void list_format_action::operator()(iterator first, iterator last) const { int new_indent = 0; while (first != last && (*first == ' ' || *first == '\t')) { char mark = *first++; if (mark == ' ') { ++new_indent; } else // must be a tab { BOOST_ASSERT(mark == '\t'); // hardcoded tab to 4 for now new_indent = ((new_indent + 4) / 4) * 4; } } char mark = *first; BOOST_ASSERT(mark == '#' || mark == '*'); // expecting a mark if (list_indent == -1) // the very start { BOOST_ASSERT(new_indent == 0); } if (new_indent > list_indent) { list_indent = new_indent; list_marks.push(mark_type(mark, list_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.swap(str); std::string::size_type pos = str.rfind("\n</listitem>"); BOOST_ASSERT(pos <= str.size()); str.erase(str.begin()+pos, str.end()); out << str; } out << std::string((mark == '#') ? "<orderedlist>\n" : "<itemizedlist>\n"); } else if (new_indent < list_indent) { BOOST_ASSERT(!list_marks.empty()); list_indent = new_indent; while (!list_marks.empty() && (list_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 == list_indent { boost::spirit::file_position const pos = first.get_position(); detail::outerr(pos.file,pos.line) << "Illegal change of list style near column " << pos.column << ".\n"; detail::outwarn(pos.file,pos.line) << "Ignoring change of list style" << std::endl; } } void span::operator()(iterator first, iterator last) const { out << "<phrase role=\"" << name << "\">"; while (first != last) detail::print_char(*first++, out.get()); out << "</phrase>"; } void unexpected_char::operator()(char) const { out << '#'; // print out an unexpected character } void anchor_action::operator()(iterator first, iterator last) const { out << "<anchor id=\""; while (first != last) detail::print_char(*first++, out.get()); out << "\" />\n"; } void do_macro_action::operator()(std::string const& str) const { if (str == quickbook_get_date) { char strdate[64]; strftime(strdate, sizeof(strdate), "%Y-%b-%d", current_time); phrase << strdate; } else if (str == quickbook_get_time) { char strdate[64]; strftime(strdate, sizeof(strdate), "%I:%M:%S %p", current_time); phrase << strdate; } else { phrase << str; } } void space::operator()(char ch) const { detail::print_space(ch, out.get()); } void space::operator()(iterator first, iterator last) const { while (first != last) detail::print_space(*first++, out.get()); } void pre_escape_back::operator()(iterator first, iterator last) const { escape_actions.phrase.push(); // save the stream } void post_escape_back::operator()(iterator first, iterator last) const { out << escape_actions.phrase.str(); escape_actions.phrase.pop(); // restore the stream } void code_action::operator()(iterator first, iterator last) const { std::string save; phrase.swap(save); // preprocess the code section to remove the initial indentation std::string program(first, last); detail::unindent(program); if (program.size() == 0) return; // Nothing left to do here. The program is empty. iterator first_(program.begin(), program.end()); iterator last_(program.end(), program.end()); first_.set_position(first.get_position()); // print the code with syntax coloring if (source_mode == "c++") { parse(first_, last_, cpp_p); } else if (source_mode == "python") { parse(first_, last_, python_p); } std::string str; temp.swap(str); phrase.swap(save); // // We must not place a \n after the <programlisting> tag // otherwise PDF output starts code blocks with a blank line: // out << "<programlisting>"; out << str; out << "</programlisting>\n"; } void inline_code_action::operator()(iterator first, iterator last) const { std::string save; out.swap(save); // print the code with syntax coloring if (source_mode == "c++") { parse(first, last, cpp_p); } else if (source_mode == "python") { parse(first, last, python_p); } std::string str; temp.swap(str); out.swap(save); out << "<code>"; out << str; out << "</code>"; } void raw_char_action::operator()(char ch) const { phrase << ch; } void raw_char_action::operator()(iterator first, iterator /*last*/) const { phrase << *first; } void plain_char_action::operator()(char ch) const { detail::print_char(ch, phrase.get()); } void plain_char_action::operator()(iterator first, iterator /*last*/) const { detail::print_char(*first, phrase.get()); } void image_action::operator()(iterator first, iterator last) const { fs::path const img_path(std::string(first, last)); std::string attr_text; if(fs::extension(img_path) == ".svg") { // // SVG's need special handling: // // 1) We must set the "format" attribute, otherwise // HTML generation produces code that will not display // the image at all. // 2) We need to set the "contentwidth" and "contentdepth" // attributes, otherwise the image will be displayed inside // a tiny box with scrollbars (Firefox), or else cropped to // fit in a tiny box (IE7). // attr_text = " format=\"SVG\""; // // Image paths are relative to the html subdirectory: // fs::path img; if(img_path.root_path().empty()) img = "html" / img_path; // relative path else img = img_path; // absolute path // // Now load the SVG file: // std::string svg_text; fs::ifstream fs(img); char c; while(fs.get(c) && fs.good()) svg_text.push_back(c); // // Extract the svg header from the file: // std::string::size_type a, b; a = svg_text.find("<svg"); b = svg_text.find('>', a); svg_text = (a == std::string::npos) ? "" : svg_text.substr(a, b - a); // // Now locate the "width" and "height" attributes // and borrow their values: // a = svg_text.find("width"); a = svg_text.find('=', a); a = svg_text.find('\"', a); b = svg_text.find('\"', a + 1); if(a != std::string::npos) { attr_text.append(" contentwidth="); attr_text.append(svg_text.begin() + a, svg_text.begin() + b + 1); } a = svg_text.find("height"); a = svg_text.find('=', a); a = svg_text.find('\"', a); b = svg_text.find('\"', a + 1); if(a != std::string::npos) { attr_text.append(" contentdepth="); attr_text.append(svg_text.begin() + a, svg_text.begin() + b + 1); } } phrase << "<inlinemediaobject>";
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -