diff options
Diffstat (limited to 'tools/quickbook/src/syntax_highlight.cpp')
-rw-r--r-- | tools/quickbook/src/syntax_highlight.cpp | 400 |
1 files changed, 238 insertions, 162 deletions
diff --git a/tools/quickbook/src/syntax_highlight.cpp b/tools/quickbook/src/syntax_highlight.cpp index 2e790f5bb1..e618c07dd6 100644 --- a/tools/quickbook/src/syntax_highlight.cpp +++ b/tools/quickbook/src/syntax_highlight.cpp @@ -14,7 +14,9 @@ #include <boost/spirit/include/classic_loops.hpp> #include "grammar.hpp" #include "grammar_impl.hpp" // Just for context stuff. Should move? -#include "actions_class.hpp" +#include "state.hpp" +#include "actions.hpp" +#include "utils.hpp" #include "files.hpp" #include "input_path.hpp" @@ -22,102 +24,100 @@ namespace quickbook { namespace cl = boost::spirit::classic; - // quickbook::actions is used in a few places here, as 'escape_actions'. - // It's named differently to distinguish it from the syntax highlighting - // actions, declared below. - - // Syntax Highlight Actions - - struct span + template <typename T, typename Value> + struct member_action_value { - // Decorates c++ code fragments + typedef void(T::*member_function)(Value); - span(char const* name, collector& out) - : name(name), out(out) {} + T& l; + member_function mf; - void operator()(parse_iterator first, parse_iterator last) const; + member_action_value(T& l, member_function mf) : l(l), mf(mf) {} - char const* name; - collector& out; + void operator()(Value v) const { + (l.*mf)(v); + } }; - struct span_start + template <typename T> + struct member_action { - span_start(char const* name, collector& out) - : name(name), out(out) {} + typedef void(T::*member_function)(parse_iterator, parse_iterator); - void operator()(parse_iterator first, parse_iterator last) const; + T& l; + member_function mf; - char const* name; - collector& out; - }; + member_action(T& l, member_function mf) : l(l), mf(mf) {} - struct span_end - { - span_end(collector& out) - : out(out) {} - - void operator()(parse_iterator first, parse_iterator last) const; - - collector& out; + void operator()(parse_iterator first, parse_iterator last) const { + (l.*mf)(first, last); + } }; - struct unexpected_char + template <typename T, typename Arg1> + struct member_action1 { - // Handles unexpected chars in c++ syntax + typedef void(T::*member_function)(parse_iterator, parse_iterator, Arg1); - unexpected_char( - collector& out - , quickbook::actions& escape_actions) - : out(out) - , escape_actions(escape_actions) {} + T& l; + member_function mf; - void operator()(parse_iterator first, parse_iterator last) const; - - collector& out; - quickbook::actions& escape_actions; - }; + member_action1(T& l, member_function mf) : l(l), mf(mf) {} - struct plain_char - { - // Prints a single plain char. - // Converts '<' to "<"... etc See utils.hpp + struct impl + { + member_action1 a; + Arg1 value; - plain_char(collector& out) - : out(out) {} + impl(member_action1& a, Arg1 value) : + a(a), value(value) + {} - void operator()(char ch) const; - void operator()(parse_iterator first, parse_iterator last) const; + void operator()(parse_iterator first, parse_iterator last) const { + (a.l.*a.mf)(first, last, value); + } + }; - collector& out; + impl operator()(Arg1 a1) { + return impl(*this, a1); + } }; - struct pre_escape_back - { - // Escapes back from code to quickbook (Pre) - - pre_escape_back(actions& escape_actions) - : escape_actions(escape_actions) {} - - void operator()(parse_iterator first, parse_iterator last) const; - - actions& escape_actions; - }; + // Syntax Highlight Actions - struct post_escape_back + struct syntax_highlight_actions { - // Escapes back from code to quickbook (Post) - - post_escape_back(collector& out, actions& escape_actions) - : out(out), escape_actions(escape_actions) {} - - void operator()(parse_iterator first, parse_iterator last) const; - - collector& out; - actions& escape_actions; + quickbook::collector out; + quickbook::state& state; + do_macro_action do_macro_impl; + + // State + bool support_callouts; + string_ref marked_text; + + syntax_highlight_actions(quickbook::state& state, bool is_block) : + out(), state(state), + do_macro_impl(out, state), + support_callouts(is_block && (qbk_version_n >= 107u || + state.current_file->is_code_snippets)), + marked_text() + {} + + void span(parse_iterator, parse_iterator, char const*); + void span_start(parse_iterator, parse_iterator, char const*); + void span_end(parse_iterator, parse_iterator); + void unexpected_char(parse_iterator, parse_iterator); + void plain_char(parse_iterator, parse_iterator); + void pre_escape_back(parse_iterator, parse_iterator); + void post_escape_back(parse_iterator, parse_iterator); + void do_macro(std::string const&); + + void mark_text(parse_iterator, parse_iterator); + void callout(parse_iterator, parse_iterator); }; - void span::operator()(parse_iterator first, parse_iterator last) const + void syntax_highlight_actions::span(parse_iterator first, + parse_iterator last, char const* name) { out << "<phrase role=\"" << name << "\">"; while (first != last) @@ -125,27 +125,30 @@ namespace quickbook out << "</phrase>"; } - void span_start::operator()(parse_iterator first, parse_iterator last) const + void syntax_highlight_actions::span_start(parse_iterator first, + parse_iterator last, char const* name) { out << "<phrase role=\"" << name << "\">"; while (first != last) detail::print_char(*first++, out.get()); } - void span_end::operator()(parse_iterator first, parse_iterator last) const + void syntax_highlight_actions::span_end(parse_iterator first, + parse_iterator last) { while (first != last) detail::print_char(*first++, out.get()); out << "</phrase>"; } - void unexpected_char::operator()(parse_iterator first, parse_iterator last) const + void syntax_highlight_actions::unexpected_char(parse_iterator first, + parse_iterator last) { - file_position const pos = escape_actions.current_file->position_of(first.base()); + file_position const pos = state.current_file->position_of(first.base()); - detail::outwarn(escape_actions.current_file->path, pos.line) + detail::outwarn(state.current_file->path, pos.line) << "in column:" << pos.column - << ", unexpected character: " << detail::utf8(first, last) + << ", unexpected character: " << std::string(first.base(), last.base()) << "\n"; // print out an unexpected character @@ -155,26 +158,42 @@ namespace quickbook out << "</phrase>"; } - void plain_char::operator()(char ch) const + void syntax_highlight_actions::plain_char(parse_iterator first, + parse_iterator last) { - detail::print_char(ch, out.get()); + while (first != last) + detail::print_char(*first++, out.get()); } - void plain_char::operator()(parse_iterator first, parse_iterator last) const + void syntax_highlight_actions::pre_escape_back(parse_iterator, + parse_iterator) { - while (first != last) - detail::print_char(*first++, out.get()); + state.phrase.push(); // save the stream + } + + void syntax_highlight_actions::post_escape_back(parse_iterator, + parse_iterator) + { + out << state.phrase.str(); + state.phrase.pop(); // restore the stream + } + + void syntax_highlight_actions::do_macro(std::string const& v) + { + do_macro_impl(v); } - void pre_escape_back::operator()(parse_iterator, parse_iterator) const + void syntax_highlight_actions::mark_text(parse_iterator first, + parse_iterator last) { - escape_actions.phrase.push(); // save the stream + marked_text = string_ref(first.base(), last.base()); } - void post_escape_back::operator()(parse_iterator, parse_iterator) const + void syntax_highlight_actions::callout(parse_iterator, parse_iterator) { - out << escape_actions.phrase.str(); - escape_actions.phrase.pop(); // restore the stream + out << state.add_callout(qbk_value(state.current_file, + marked_text.begin(), marked_text.end())); + marked_text.clear(); } // Syntax @@ -225,45 +244,63 @@ namespace quickbook } // Grammar for C++ highlighting - struct cpp_highlight - : public cl::grammar<cpp_highlight> + struct cpp_highlight : public cl::grammar<cpp_highlight> { - cpp_highlight(collector& out, actions& escape_actions) - : out(out), escape_actions(escape_actions) {} + cpp_highlight(syntax_highlight_actions& actions) + : actions(actions) {} template <typename Scanner> struct definition { definition(cpp_highlight const& self) - : g(self.escape_actions.grammar()) + : g(self.actions.state.grammar()) { + member_action1<syntax_highlight_actions, char const*> + span(self.actions, &syntax_highlight_actions::span), + span_start(self.actions, &syntax_highlight_actions::span_start); + member_action<syntax_highlight_actions> + span_end(self.actions, &syntax_highlight_actions::span_end), + unexpected_char(self.actions, &syntax_highlight_actions::unexpected_char), + plain_char(self.actions, &syntax_highlight_actions::plain_char), + pre_escape_back(self.actions, &syntax_highlight_actions::pre_escape_back), + post_escape_back(self.actions, &syntax_highlight_actions::post_escape_back), + mark_text(self.actions, &syntax_highlight_actions::mark_text), + callout(self.actions, &syntax_highlight_actions::callout); + member_action_value<syntax_highlight_actions, std::string const&> + do_macro(self.actions, &syntax_highlight_actions::do_macro); + error_action error(self.actions.state); + program = - *( (+cl::space_p) [plain_char(self.out)] + *( (+cl::space_p) [plain_char] | macro | escape - | preprocessor [span("preprocessor", self.out)] + | preprocessor [span("preprocessor")] + | cl::eps_p(ph::var(self.actions.support_callouts)) + >> ( line_callout [callout] + | inline_callout [callout] + ) | comment - | keyword [span("keyword", self.out)] - | identifier [span("identifier", self.out)] - | special [span("special", self.out)] - | string_ [span("string", self.out)] - | char_ [span("char", self.out)] - | number [span("number", self.out)] - | cl::repeat_p(1)[cl::anychar_p] - [unexpected_char(self.out, self.escape_actions)] + | keyword [span("keyword")] + | identifier [span("identifier")] + | special [span("special")] + | string_ [span("string")] + | char_ [span("char")] + | number [span("number")] + | u8_codepoint_p [unexpected_char] ) ; macro = // must not be followed by alpha or underscore - cl::eps_p(self.escape_actions.macro + cl::eps_p(self.actions.state.macro >> (cl::eps_p - (cl::alpha_p | '_'))) - >> self.escape_actions.macro [do_macro_action(self.out, self.escape_actions)] + >> self.actions.state.macro + [do_macro] ; escape = - cl::str_p("``") [pre_escape_back(self.escape_actions)] + cl::str_p("``") [pre_escape_back] >> ( ( @@ -275,29 +312,46 @@ namespace quickbook ) | ( - cl::eps_p [self.escape_actions.error] + cl::eps_p [error] >> *cl::anychar_p ) - ) [post_escape_back(self.out, self.escape_actions)] + ) [post_escape_back] ; preprocessor = '#' >> *cl::space_p >> ((cl::alpha_p | '_') >> *(cl::alnum_p | '_')) ; + inline_callout + = cl::confix_p( + "/*<" >> *cl::space_p, + (*cl::anychar_p) [mark_text], + ">*/" + ) + ; + + line_callout + = cl::confix_p( + "/*<<" >> *cl::space_p, + (*cl::anychar_p) [mark_text], + ">>*/" + ) + >> *cl::space_p + ; + comment - = cl::str_p("//") [span_start("comment", self.out)] + = cl::str_p("//") [span_start("comment")] >> *( escape | (+(cl::anychar_p - (cl::eol_p | "``"))) - [plain_char(self.out)] + [plain_char] ) - >> cl::eps_p [span_end(self.out)] - | cl::str_p("/*") [span_start("comment", self.out)] + >> cl::eps_p [span_end] + | cl::str_p("/*") [span_start("comment")] >> *( escape | (+(cl::anychar_p - (cl::str_p("*/") | "``"))) - [plain_char(self.out)] + [plain_char] ) - >> (!cl::str_p("*/")) [span_end(self.out)] + >> (!cl::str_p("*/")) [span_end] ; keyword @@ -308,7 +362,7 @@ namespace quickbook = +cl::chset_p("~!%^&*()+={[}]:;,<.>?/|\\-") ; - string_char = ('\\' >> cl::anychar_p) | (cl::anychar_p - '\\'); + string_char = ('\\' >> u8_codepoint_p) | (cl::anychar_p - '\\'); string_ = !cl::as_lower_d['l'] >> cl::confix_p('"', *string_char, '"') @@ -333,7 +387,9 @@ namespace quickbook } cl::rule<Scanner> - program, macro, preprocessor, comment, special, string_, + program, macro, preprocessor, + inline_callout, line_callout, comment, + special, string_, char_, number, identifier, keyword, escape, string_char; @@ -343,50 +399,63 @@ namespace quickbook start() const { return program; } }; - collector& out; - actions& escape_actions; + syntax_highlight_actions& actions; }; // Grammar for Python highlighting // See also: The Python Reference Manual // http://docs.python.org/ref/ref.html - struct python_highlight - : public cl::grammar<python_highlight> + struct python_highlight : public cl::grammar<python_highlight> { - python_highlight(collector& out, actions& escape_actions) - : out(out), escape_actions(escape_actions) {} + python_highlight(syntax_highlight_actions& actions) + : actions(actions) {} template <typename Scanner> struct definition { definition(python_highlight const& self) - : g(self.escape_actions.grammar()) + : g(self.actions.state.grammar()) { + member_action1<syntax_highlight_actions, char const*> + span(self.actions, &syntax_highlight_actions::span), + span_start(self.actions, &syntax_highlight_actions::span_start); + member_action<syntax_highlight_actions> + span_end(self.actions, &syntax_highlight_actions::span_end), + unexpected_char(self.actions, &syntax_highlight_actions::unexpected_char), + plain_char(self.actions, &syntax_highlight_actions::plain_char), + pre_escape_back(self.actions, &syntax_highlight_actions::pre_escape_back), + post_escape_back(self.actions, &syntax_highlight_actions::post_escape_back), + mark_text(self.actions, &syntax_highlight_actions::mark_text), + callout(self.actions, &syntax_highlight_actions::callout); + member_action_value<syntax_highlight_actions, std::string const&> + do_macro(self.actions, &syntax_highlight_actions::do_macro); + error_action error(self.actions.state); + program = - *( (+cl::space_p) [plain_char(self.out)] + *( (+cl::space_p) [plain_char] | macro | escape | comment - | keyword [span("keyword", self.out)] - | identifier [span("identifier", self.out)] - | special [span("special", self.out)] - | string_ [span("string", self.out)] - | number [span("number", self.out)] - | cl::repeat_p(1)[cl::anychar_p] - [unexpected_char(self.out, self.escape_actions)] + | keyword [span("keyword")] + | identifier [span("identifier")] + | special [span("special")] + | string_ [span("string")] + | number [span("number")] + | u8_codepoint_p [unexpected_char] ) ; macro = // must not be followed by alpha or underscore - cl::eps_p(self.escape_actions.macro + cl::eps_p(self.actions.state.macro >> (cl::eps_p - (cl::alpha_p | '_'))) - >> self.escape_actions.macro [do_macro_action(self.out, self.escape_actions)] + >> self.actions.state.macro + [do_macro] ; escape = - cl::str_p("``") [pre_escape_back(self.escape_actions)] + cl::str_p("``") [pre_escape_back] >> ( ( @@ -398,19 +467,19 @@ namespace quickbook ) | ( - cl::eps_p [self.escape_actions.error] + cl::eps_p [error] >> *cl::anychar_p ) - ) [post_escape_back(self.out, self.escape_actions)] + ) [post_escape_back] ; comment - = cl::str_p("#") [span_start("comment", self.out)] + = cl::str_p("#") [span_start("comment")] >> *( escape | (+(cl::anychar_p - (cl::eol_p | "``"))) - [plain_char(self.out)] + [plain_char] ) - >> cl::eps_p [span_end(self.out)] + >> cl::eps_p [span_end] ; keyword @@ -429,7 +498,7 @@ namespace quickbook = ! string_prefix >> (long_string | short_string) ; - string_char = ('\\' >> cl::anychar_p) | (cl::anychar_p - '\\'); + string_char = ('\\' >> u8_codepoint_p) | (cl::anychar_p - '\\'); short_string = cl::confix_p('\'', * string_char, '\'') | @@ -468,40 +537,47 @@ namespace quickbook start() const { return program; } }; - collector& out; - actions& escape_actions; + syntax_highlight_actions& actions; }; // Grammar for plain text (no actual highlighting) - struct teletype_highlight - : public cl::grammar<teletype_highlight> + struct teletype_highlight : public cl::grammar<teletype_highlight> { - teletype_highlight(collector& out, actions& escape_actions) - : out(out), escape_actions(escape_actions) {} + teletype_highlight(syntax_highlight_actions& actions) + : actions(actions) {} template <typename Scanner> struct definition { definition(teletype_highlight const& self) - : g(self.escape_actions.grammar()) + : g(self.actions.state.grammar()) { + member_action<syntax_highlight_actions> + plain_char(self.actions, &syntax_highlight_actions::plain_char), + pre_escape_back(self.actions, &syntax_highlight_actions::pre_escape_back), + post_escape_back(self.actions, &syntax_highlight_actions::post_escape_back); + member_action_value<syntax_highlight_actions, std::string const&> + do_macro(self.actions, &syntax_highlight_actions::do_macro); + error_action error(self.actions.state); + program = *( macro | escape - | cl::repeat_p(1)[cl::anychar_p] [plain_char(self.out)] + | u8_codepoint_p [plain_char] ) ; macro = // must not be followed by alpha or underscore - cl::eps_p(self.escape_actions.macro + cl::eps_p(self.actions.state.macro >> (cl::eps_p - (cl::alpha_p | '_'))) - >> self.escape_actions.macro [do_macro_action(self.out, self.escape_actions)] + >> self.actions.state.macro + [do_macro] ; escape = - cl::str_p("``") [pre_escape_back(self.escape_actions)] + cl::str_p("``") [pre_escape_back] >> ( ( @@ -513,10 +589,10 @@ namespace quickbook ) | ( - cl::eps_p [self.escape_actions.error] + cl::eps_p [error] >> *cl::anychar_p ) - ) [post_escape_back(self.out, self.escape_actions)] + ) [post_escape_back] ; } @@ -528,32 +604,32 @@ namespace quickbook start() const { return program; } }; - collector& out; - actions& escape_actions; + syntax_highlight_actions& actions; }; std::string syntax_highlight( parse_iterator first, parse_iterator last, - actions& escape_actions, - std::string const& source_mode) + quickbook::state& state, + std::string const& source_mode, + bool is_block) { - quickbook::collector temp; + syntax_highlight_actions syn_actions(state, is_block); // print the code with syntax coloring if (source_mode == "c++") { - cpp_highlight cpp_p(temp, escape_actions); + cpp_highlight cpp_p(syn_actions); boost::spirit::classic::parse(first, last, cpp_p); } else if (source_mode == "python") { - python_highlight python_p(temp, escape_actions); + python_highlight python_p(syn_actions); boost::spirit::classic::parse(first, last, python_p); } else if (source_mode == "teletype") { - teletype_highlight teletype_p(temp, escape_actions); + teletype_highlight teletype_p(syn_actions); boost::spirit::classic::parse(first, last, teletype_p); } else @@ -562,7 +638,7 @@ namespace quickbook } std::string str; - temp.swap(str); + syn_actions.out.swap(str); return str; } |