Add HTML output.
continuous-integration/drone/push Build is passing
Details
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:
parent
a77b90c8b1
commit
37c2fe1bb1
|
@ -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]
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue