From cd3758bb328ff425bb06f18c81d3c353b508a336 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 9 Nov 2021 13:01:13 +0200 Subject: Add --ascii-tree for translating UTF-8 tree(1) output to ASCII --- cli/cli/bootstrap/cli/options.cxx | 10 ++++++++ cli/cli/bootstrap/cli/options.hxx | 10 ++++++++ cli/cli/bootstrap/cli/options.ixx | 18 +++++++++++++ cli/cli/context.cxx | 53 +++++++++++++++++++++++++++++++++++++++ cli/cli/context.hxx | 9 ++++--- cli/cli/html.cxx | 10 +++++++- cli/cli/man.cxx | 10 +++++++- cli/cli/options.cli | 7 ++++++ cli/cli/source.cxx | 10 ++++++++ cli/cli/txt.cxx | 5 +++- 10 files changed, 136 insertions(+), 6 deletions(-) (limited to 'cli/cli') diff --git a/cli/cli/bootstrap/cli/options.cxx b/cli/cli/bootstrap/cli/options.cxx index 56dd24f..e66ae63 100644 --- a/cli/cli/bootstrap/cli/options.cxx +++ b/cli/cli/bootstrap/cli/options.cxx @@ -715,6 +715,7 @@ options () page_usage_specified_ (false), option_length_ (0), option_length_specified_ (false), + ascii_tree_ (), ansi_color_ (), exclude_base_ (), include_base_last_ (), @@ -856,6 +857,7 @@ options (int& argc, page_usage_specified_ (false), option_length_ (0), option_length_specified_ (false), + ascii_tree_ (), ansi_color_ (), exclude_base_ (), include_base_last_ (), @@ -1000,6 +1002,7 @@ options (int start, page_usage_specified_ (false), option_length_ (0), option_length_specified_ (false), + ascii_tree_ (), ansi_color_ (), exclude_base_ (), include_base_last_ (), @@ -1144,6 +1147,7 @@ options (int& argc, page_usage_specified_ (false), option_length_ (0), option_length_specified_ (false), + ascii_tree_ (), ansi_color_ (), exclude_base_ (), include_base_last_ (), @@ -1290,6 +1294,7 @@ options (int start, page_usage_specified_ (false), option_length_ (0), option_length_specified_ (false), + ascii_tree_ (), ansi_color_ (), exclude_base_ (), include_base_last_ (), @@ -1432,6 +1437,7 @@ options (::cli::scanner& s, page_usage_specified_ (false), option_length_ (0), option_length_specified_ (false), + ascii_tree_ (), ansi_color_ (), exclude_base_ (), include_base_last_ (), @@ -1613,6 +1619,8 @@ print_usage (::std::ostream& os, ::cli::usage_para p) os << "--option-length Indent option descriptions characters when" << ::std::endl << " printing usage." << ::std::endl; + os << "--ascii-tree Convert UTF-8 tree(1) output to ASCII." << ::std::endl; + os << "--ansi-color Use ANSI color escape sequences when printing" << ::std::endl << " usage." << ::std::endl; @@ -1859,6 +1867,8 @@ struct _cli_options_map_init _cli_options_map_["--option-length"] = &::cli::thunk< options, std::size_t, &options::option_length_, &options::option_length_specified_ >; + _cli_options_map_["--ascii-tree"] = + &::cli::thunk< options, bool, &options::ascii_tree_ >; _cli_options_map_["--ansi-color"] = &::cli::thunk< options, bool, &options::ansi_color_ >; _cli_options_map_["--exclude-base"] = diff --git a/cli/cli/bootstrap/cli/options.hxx b/cli/cli/bootstrap/cli/options.hxx index 35108fa..3ae86c6 100644 --- a/cli/cli/bootstrap/cli/options.hxx +++ b/cli/cli/bootstrap/cli/options.hxx @@ -785,6 +785,15 @@ class options option_length_specified (bool); const bool& + ascii_tree () const; + + bool& + ascii_tree (); + + void + ascii_tree (const bool&); + + const bool& ansi_color () const; bool& @@ -1566,6 +1575,7 @@ class options bool page_usage_specified_; std::size_t option_length_; bool option_length_specified_; + bool ascii_tree_; bool ansi_color_; bool exclude_base_; bool include_base_last_; diff --git a/cli/cli/bootstrap/cli/options.ixx b/cli/cli/bootstrap/cli/options.ixx index ee4cbdb..8c22d51 100644 --- a/cli/cli/bootstrap/cli/options.ixx +++ b/cli/cli/bootstrap/cli/options.ixx @@ -895,6 +895,24 @@ option_length_specified (bool x) } inline const bool& options:: +ascii_tree () const +{ + return this->ascii_tree_; +} + +inline bool& options:: +ascii_tree () +{ + return this->ascii_tree_; +} + +inline void options:: +ascii_tree (const bool& x) +{ + this->ascii_tree_ = x; +} + +inline const bool& options:: ansi_color () const { return this->ansi_color_; diff --git a/cli/cli/context.cxx b/cli/cli/context.cxx index 54bb988..2833861 100644 --- a/cli/cli/context.cxx +++ b/cli/cli/context.cxx @@ -296,6 +296,59 @@ process_link_target (const string& tg) return found ? r : tg; } +void context:: +preprocess_ascii_tree (string& s) +{ + // tree --charset=UTF-8 uses the following box-drawing characters (see + // color.c): + // + // CHAR UTF-8 ASCII + //---------------------------- + // + // | E29482 | + // + // -- E29480 - + // + // |- E2949C | + // + // |_ E29494 ` + // + // C2A0 + // + // Note that here we rely on the fact that neither E2 nor C2 can appear as + // continuation bytes. + // + for (size_t i (0); i != s.size (); ++i) + { + i = s.find_first_of ("\xE2\xC2", i); + + if (i == string::npos) + break; + + if (s[i] == '\xE2') + { + if (s[i + 1] == '\x94') + { + const char* r; + switch (s[i + 2]) + { + case '\x80': r = "-"; break; + case '\x82': + case '\x9c': r = "|"; break; + case '\x94': r = "`"; break; + default: continue; + } + + s.replace (i, 3, r); + } + } + else + { + if (s[i + 1] == '\xA0') + s.replace (i, 2, " "); + } + } +} string context:: translate_arg (string const& s, std::set& set) diff --git a/cli/cli/context.hxx b/cli/cli/context.hxx index 66dcb24..19bfa51 100644 --- a/cli/cli/context.hxx +++ b/cli/cli/context.hxx @@ -153,10 +153,13 @@ public: string process_link_target (const string&); - // Translate and format the documentation string. Translate converts - // the -style constructs to \i{arg}. Format converts the string - // to the output format. + // Preprocess, translate, and format the documentation string. Translate + // converts the -style constructs to \i{arg}. Format converts the + // string to the output format. // + static void + preprocess_ascii_tree (string&); + static string translate_arg (string const&, std::set&); diff --git a/cli/cli/html.cxx b/cli/cli/html.cxx index b374b91..48eb5e3 100644 --- a/cli/cli/html.cxx +++ b/cli/cli/html.cxx @@ -127,13 +127,16 @@ namespace // n > 2 - arg string, short string, long string // size_t n (ds.size ()); - const string& d ( + string d ( n == 1 ? (cd_ == cd_short ? first_sentence (ds[0]) : ds[0]) : (n == 2 ? (cd_ == cd_short ? first_sentence (ds[1]) : ds[1]) : ds[cd_ == cd_short ? 1 : 2])); + if (options.ascii_tree ()) + preprocess_ascii_tree (d); + std::set arg_set; if (n > 1) translate_arg (ds[0], arg_set); @@ -211,6 +214,8 @@ namespace if (type != "bool" || doc.size () >= 3) { + // Note: we naturally assume this doesn't need --ascii-tree treatment. + // string s ( translate_arg ( doc.size () > 0 ? doc[0] : string (""), arg_set)); @@ -236,6 +241,9 @@ namespace d = (cd_ == cd_short ? first_sentence (doc[1]) : doc[1]); } + if (options.ascii_tree ()) + preprocess_ascii_tree (d); + // Format the documentation string. // d = format (o.scope (), escape_html (translate (d, arg_set)), false); diff --git a/cli/cli/man.cxx b/cli/cli/man.cxx index df703e8..d446b2a 100644 --- a/cli/cli/man.cxx +++ b/cli/cli/man.cxx @@ -91,13 +91,16 @@ namespace // n > 2 - arg string, short string, long string // size_t n (ds.size ()); - const string& d ( + string d ( n == 1 ? (cd_ == cd_short ? first_sentence (ds[0]) : ds[0]) : (n == 2 ? (cd_ == cd_short ? first_sentence (ds[1]) : ds[1]) : ds[cd_ == cd_short ? 1 : 2])); + if (options.ascii_tree ()) + preprocess_ascii_tree (d); + std::set arg_set; if (n > 1) translate_arg (ds[0], arg_set); @@ -149,6 +152,8 @@ namespace if (type != "bool" || doc.size () >= 3) { + // Note: we naturally assume this doesn't need --ascii-tree treatment. + // string s ( translate_arg ( doc.size () > 0 ? doc[0] : string (""), arg_set)); @@ -174,6 +179,9 @@ namespace d = (cd_ == cd_short ? first_sentence (doc[1]) : doc[1]); } + if (options.ascii_tree ()) + preprocess_ascii_tree (d); + // Format the documentation string. // d = format (o.scope (), translate (d, arg_set), false); diff --git a/cli/cli/options.cli b/cli/cli/options.cli index 9273845..3a3089b 100644 --- a/cli/cli/options.cli +++ b/cli/cli/options.cli @@ -257,6 +257,13 @@ class options files, and would like their usage to have the same indentation level." }; + bool --ascii-tree + { + "Convert UTF-8 \cb{tree(1)} output to ASCII. Specifically, box-drawing + characters used in the \cb{--charset=UTF-8} output are replaced with + ASCII characters used in the \cb{--charset=ASCII} output." + }; + bool --ansi-color { "Use ANSI color escape sequences when printing usage. By \"color\" we diff --git a/cli/cli/source.cxx b/cli/cli/source.cxx index b6df839..1b9e832 100644 --- a/cli/cli/source.cxx +++ b/cli/cli/source.cxx @@ -278,6 +278,9 @@ namespace : (n == 1 ? ds[0] : ds[1]); // Else, use common (no first sentence). } + if (options.ascii_tree ()) + preprocess_ascii_tree (d); + std::set arg_set; if (n > 1 && options.ansi_color ()) translate_arg (ds[0], arg_set); @@ -345,6 +348,8 @@ namespace { l++; // ' ' seperator + // Note: we naturally assume this doesn't need --ascii-tree treatment. + // string s (doc.size () > 0 ? doc[0] : string ("")); if (options.ansi_color ()) @@ -439,6 +444,8 @@ namespace os << ' '; l++; + // Note: we naturally assume this doesn't need --ascii-tree treatment. + // string s (doc.size () > 0 ? doc[0] : string ("")); if (color) @@ -475,6 +482,9 @@ namespace } } + if (options.ascii_tree ()) + preprocess_ascii_tree (d); + // Format the documentation string. // if (color) diff --git a/cli/cli/txt.cxx b/cli/cli/txt.cxx index 16de45a..1e9094d 100644 --- a/cli/cli/txt.cxx +++ b/cli/cli/txt.cxx @@ -164,13 +164,16 @@ namespace // n > 2 - arg string, short string, long string // size_t n (ds.size ()); - const string& d ( + string d ( n == 1 ? (cd_ == cd_short ? first_sentence (ds[0]) : ds[0]) : (n == 2 ? (cd_ == cd_short ? first_sentence (ds[1]) : ds[1]) : ds[cd_ == cd_short ? 1 : 2])); + if (options.ascii_tree ()) + preprocess_ascii_tree (d); + std::set arg_set; if (n > 1 && options.ansi_color ()) translate_arg (ds[0], arg_set); -- cgit v1.1