Add HTML output.
continuous-integration/drone/push Build is passing Details

Prints a simple HTML document with tables wrapped in articles to stdout.

Closes: #9
This commit is contained in:
tastytea 2021-06-08 16:55:35 +02:00
parent a77b90c8b1
commit 37c2fe1bb1
Signed by: tastytea
GPG Key ID: CFC39497F1B26E07
6 changed files with 94 additions and 2 deletions

View File

@ -2,7 +2,7 @@
:doctype: manpage :doctype: manpage
:Author: tastytea :Author: tastytea
:Email: tastytea@tastytea.de :Email: tastytea@tastytea.de
:Date: 2021-06-07 :Date: 2021-06-08
:Revision: 0.0.0 :Revision: 0.0.0
:man source: epubgrep :man source: epubgrep
:man manual: General Commands Manual :man manual: General Commands Manual
@ -88,6 +88,10 @@ program. There will be an object named `generator` with the property
`epubgrep`. The value is the version of the program, as string. The matches are `epubgrep`. The value is the version of the program, as string. The matches are
in an array named `matches`. I will try not to break the API. 😊 in an array named `matches`. I will try not to break the API. 😊
*--html*::
Output HTML instead of plain text. HTML will only be output at the end of the
program.
== USAGE == USAGE
[source,shellsession] [source,shellsession]

View File

@ -223,7 +223,7 @@ int main(int argc, char *argv[])
std::async(std::launch::async, search_file, filepath)); std::async(std::launch::async, search_file, filepath));
DEBUGLOG << "Launched new thread"; DEBUGLOG << "Launched new thread";
if (!matches_all.empty() && !opts.json) if (!matches_all.empty() && !opts.json && !opts.html)
{ {
output::print_matches(matches_all[0], opts, output::print_matches(matches_all[0], opts,
input_files.size() == 1); input_files.size() == 1);
@ -238,6 +238,10 @@ int main(int argc, char *argv[])
{ {
output::json_all(matches_all); output::json_all(matches_all);
} }
else if (opts.html)
{
output::html_all(matches_all, opts);
}
else else
{ {
for (const auto &matches : matches_all) for (const auto &matches : matches_all)

View File

@ -95,6 +95,8 @@ options parse_options(int argc, char *argv[])
translate("Enable debug output.") .str().data()) translate("Enable debug output.") .str().data())
("json", ("json",
translate("Output JSON instead of plain text.") .str().data()) translate("Output JSON instead of plain text.") .str().data())
("html",
translate("Output HTML instead of plain text.") .str().data())
; ;
po::options_description options_hidden("Hidden options"); po::options_description options_hidden("Hidden options");
@ -235,6 +237,7 @@ options parse_again(const po::variables_map &vm)
opts.ignore_archive_errors = vm.count("ignore-archive-errors") > 0; opts.ignore_archive_errors = vm.count("ignore-archive-errors") > 0;
opts.debug = vm.count("debug") > 0; opts.debug = vm.count("debug") > 0;
opts.json = vm.count("json") > 0; opts.json = vm.count("json") > 0;
opts.html = vm.count("html") > 0;
if (vm.count("regexp") > 0) if (vm.count("regexp") > 0)
{ {

View File

@ -58,6 +58,7 @@ struct options
bool ignore_archive_errors{false}; bool ignore_archive_errors{false};
bool debug{false}; bool debug{false};
bool json{false}; bool json{false};
bool html{false};
//! For the debug output. //! For the debug output.
friend std::ostream &operator<<(std::ostream &out, const options &opts); friend std::ostream &operator<<(std::ostream &out, const options &opts);

View File

@ -24,6 +24,7 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <termcolor/termcolor.hpp> #include <termcolor/termcolor.hpp>
#include <cstdint>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
@ -131,4 +132,79 @@ void json_all(const std::vector<std::vector<search::match>> &matches_all)
cout << json.dump() << '\n'; cout << json.dump() << '\n';
} }
void html_all(const std::vector<std::vector<search::match>> &matches_all,
const options::options &opts)
{
std::uint64_t count{1};
cout << "<!DOCTYPE html>\n"
<< "<html><head><title>epubgrep output</title>"
"<style>article { margin: 1em; }</style>"
"</head><body>\n\n";
for (const auto &matches : matches_all)
{
const auto identifier{
[&opts, count, &matches]
{
if (opts.no_fn_fs)
{
return format(translate("File {0:d}").str(), count);
}
return fs::relative(matches[0].filepath_epub).string();
}()};
// Start article, table and print table header.
cout << format(R"(<article aria-labelledby="file_{0:d}">)", count)
<< "\n <table>\n"
<< format(R"( <caption id="file_{0:d}">{1:s}</caption>)", count,
identifier)
<< '\n'
<< " <tr>\n";
if (!opts.no_fn_epub)
{
cout << format(R"( <th id="file_path_{0:d}">{1:s}</th>)",
count, translate("File path (in EPUB file)"))
<< '\n';
}
cout << format(R"( <th id="headline_{0:d}">{1:s}</th>)", count,
translate("Last headline"))
<< '\n'
<< format(R"( <th id="page_{0:d}">{1:s}</th>)", count,
translate("Page number"))
<< '\n'
<< format(R"( <th id="match_{0:d}">{1:s}</th>)", count,
translate("Match"))
<< "\n </tr>\n";
for (const auto &match : matches)
{
cout << " <tr>\n";
if (!opts.no_fn_epub)
{
cout << format(
R"( <td headers="file_path_{0:d}">{1:s}</td>)", count,
match.filepath_inside)
<< '\n';
}
cout << format(R"( <td headers="headline_{0:d}">{1:s}</td>)",
count, match.headline)
<< '\n';
cout << format(R"( <td headers="page_{0:d}">{1:s}</td>)",
count, match.page)
<< '\n';
cout << format(R"( <td headers="match_{0:d}">{1:s})"
R"(<strong>{2:s}</strong>{3:s}</td>)",
count, match.context.first, match.text,
match.context.second)
<< '\n';
cout << " </tr>\n";
}
cout << " </table>\n</article>\n\n";
++count;
}
cout << "</body></html>\n";
}
} // namespace epubgrep::output } // namespace epubgrep::output

View File

@ -32,6 +32,10 @@ void print_matches(const std::vector<search::match> &matches,
//! Print all matches as JSON. //! Print all matches as JSON.
void json_all(const std::vector<std::vector<search::match>> &matches_all); void json_all(const std::vector<std::vector<search::match>> &matches_all);
//! Print all matches as HTML.
void html_all(const std::vector<std::vector<search::match>> &matches_all,
const options::options &opts);
} // namespace epubgrep::output } // namespace epubgrep::output
#endif // EPUBGREP_OUTPUT_HPP #endif // EPUBGREP_OUTPUT_HPP