Browse Source

Add HTML output.

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

Closes: #9
main
tastytea 2 months ago
parent
commit
37c2fe1bb1
Signed by: tastytea GPG Key ID: CFC39497F1B26E07
  1. 6
      man/epubgrep.1.adoc
  2. 6
      src/main.cpp
  3. 3
      src/options.cpp
  4. 1
      src/options.hpp
  5. 76
      src/output.cpp
  6. 4
      src/output.hpp

6
man/epubgrep.1.adoc

@ -2,7 +2,7 @@
:doctype: manpage
:Author: tastytea
:Email: tastytea@tastytea.de
:Date: 2021-06-07
:Date: 2021-06-08
:Revision: 0.0.0
:man source: epubgrep
: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
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
[source,shellsession]

6
src/main.cpp

@ -223,7 +223,7 @@ int main(int argc, char *argv[])
std::async(std::launch::async, search_file, filepath));
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,
input_files.size() == 1);
@ -238,6 +238,10 @@ int main(int argc, char *argv[])
{
output::json_all(matches_all);
}
else if (opts.html)
{
output::html_all(matches_all, opts);
}
else
{
for (const auto &matches : matches_all)

3
src/options.cpp

@ -95,6 +95,8 @@ options parse_options(int argc, char *argv[])
translate("Enable debug output.") .str().data())
("json",
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");
@ -235,6 +237,7 @@ options parse_again(const po::variables_map &vm)
opts.ignore_archive_errors = vm.count("ignore-archive-errors") > 0;
opts.debug = vm.count("debug") > 0;
opts.json = vm.count("json") > 0;
opts.html = vm.count("html") > 0;
if (vm.count("regexp") > 0)
{

1
src/options.hpp

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

76
src/output.cpp

@ -24,6 +24,7 @@
#include <nlohmann/json.hpp>
#include <termcolor/termcolor.hpp>
#include <cstdint>
#include <iostream>
#include <sstream>
@ -131,4 +132,79 @@ void json_all(const std::vector<std::vector<search::match>> &matches_all)
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

4
src/output.hpp

@ -32,6 +32,10 @@ void print_matches(const std::vector<search::match> &matches,
//! Print all matches as JSON.
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
#endif // EPUBGREP_OUTPUT_HPP
Loading…
Cancel
Save