Rework option parsing, change --no-filename.
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
Options are now better accessible, --no-filename accepts the values filesystem, in-epub or all.
This commit is contained in:
parent
c376ce8466
commit
e64591f204
@ -58,9 +58,11 @@ Print _NUMBER_ words of context around matches.
|
||||
*--nocolor*::
|
||||
Do not color matches.
|
||||
|
||||
*--no-filename*::
|
||||
Suppress the mentioning of EPUB file names on output. File names inside the
|
||||
EPUB, chapters and page numbers will still be output.
|
||||
*--no-filename* _WHICH_::
|
||||
|
||||
Suppress the mentioning of file names on output. _WHICH_ is ‘filesystem’ for the
|
||||
file names on your file systems, ‘in-epub’ for the file names inside the EPUB or
|
||||
‘all’. Chapters and page numbers will still be output.
|
||||
|
||||
*-r*, *--recursive*:
|
||||
Read all files under each directory, recursively, following symbolic links only
|
||||
|
99
src/main.cpp
99
src/main.cpp
@ -21,8 +21,6 @@
|
||||
|
||||
#include <boost/locale/generator.hpp>
|
||||
#include <boost/locale/message.hpp>
|
||||
#include <boost/program_options/errors.hpp>
|
||||
#include <boost/program_options/variables_map.hpp>
|
||||
#include <fmt/format.h>
|
||||
#include <fmt/ostream.h> // For compatibility with fmt 4.
|
||||
#include <termcolor/termcolor.hpp>
|
||||
@ -42,7 +40,6 @@
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
namespace po = boost::program_options;
|
||||
using namespace epubgrep;
|
||||
|
||||
using boost::locale::translate;
|
||||
@ -63,10 +60,10 @@ int main(int argc, char *argv[])
|
||||
cout.imbue(std::locale());
|
||||
cerr.imbue(std::locale());
|
||||
|
||||
po::variables_map vm;
|
||||
options::options opts;
|
||||
try
|
||||
{
|
||||
vm = options::parse_options(argc, argv);
|
||||
opts = options::parse_options(argc, argv);
|
||||
}
|
||||
catch (std::exception &e)
|
||||
{ // Exceptions we can't recover from or ones we don't know.
|
||||
@ -75,7 +72,7 @@ int main(int argc, char *argv[])
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (vm.count("help") + vm.count("version") > 0)
|
||||
if (opts.help || opts.version)
|
||||
{
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@ -83,31 +80,26 @@ int main(int argc, char *argv[])
|
||||
int return_code{EXIT_SUCCESS};
|
||||
|
||||
vector<fs::path> input_files;
|
||||
if (vm.count("input-file") == 0)
|
||||
if (opts.input_file.empty())
|
||||
{
|
||||
cout << "NO INPUT FILE\n";
|
||||
// TODO: Read data from stdin.
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
for (const auto &filepath : vm["input-file"].as<vector<string>>())
|
||||
for (const auto &filepath : opts.input_file)
|
||||
{
|
||||
if (vm.count("recursive") + vm.count("dereference-recursive") == 0)
|
||||
if (!opts.recursive && !opts.dereference_recursive)
|
||||
{
|
||||
|
||||
input_files.emplace_back(filepath);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool follow_symlinks{false};
|
||||
if (vm.count("dereference-recursive") > 0)
|
||||
{
|
||||
follow_symlinks = true;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
auto files_in_dir{
|
||||
files::list_recursive(filepath, follow_symlinks)};
|
||||
files::list_recursive(filepath,
|
||||
opts.dereference_recursive)};
|
||||
input_files.insert(input_files.end(), files_in_dir.begin(),
|
||||
files_in_dir.end());
|
||||
}
|
||||
@ -130,45 +122,25 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
search::options opts;
|
||||
if (vm.count("basic-regexp") > 0)
|
||||
{
|
||||
opts.regex = search::regex_kind::basic;
|
||||
}
|
||||
if (vm.count("extended-regexp") > 0)
|
||||
{
|
||||
opts.regex = search::regex_kind::extended;
|
||||
}
|
||||
if (vm.count("perl-regexp") > 0)
|
||||
{
|
||||
opts.regex = search::regex_kind::perl;
|
||||
}
|
||||
if (vm.count("grep") > 0)
|
||||
{
|
||||
opts.grep_like = true;
|
||||
}
|
||||
if (vm.count("ignore-case") > 0)
|
||||
{
|
||||
opts.ignore_case = true;
|
||||
}
|
||||
if (vm.count("raw") > 0)
|
||||
{
|
||||
opts.raw = true;
|
||||
}
|
||||
opts.context = vm["context"].as<std::uint64_t>();
|
||||
search::settings search_settings;
|
||||
search_settings.regex = opts.regex;
|
||||
search_settings.grep_like = opts.grep;
|
||||
search_settings.ignore_case = opts.ignore_case;
|
||||
search_settings.raw = opts.raw;
|
||||
search_settings.context = opts.context;
|
||||
|
||||
vector<vector<search::match>> matches_all;
|
||||
vector<std::future<int>> futurepool;
|
||||
|
||||
auto search_file{
|
||||
[&vm, &matches_all, &opts](fs::path filepath)
|
||||
[&opts, &matches_all, &search_settings](fs::path filepath)
|
||||
{
|
||||
for (const auto ®ex : vm["regexp"].as<vector<string>>())
|
||||
for (const auto ®ex : opts.regexp)
|
||||
{
|
||||
try
|
||||
{
|
||||
matches_all.emplace_back(
|
||||
search::search(filepath, regex, opts));
|
||||
search::search(filepath, regex, search_settings));
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
@ -231,43 +203,54 @@ int main(int argc, char *argv[])
|
||||
fs::path last_epub;
|
||||
for (const auto &match : matches_file)
|
||||
{
|
||||
if (input_files.size() <= 1 || vm.count("no-filename") == 0)
|
||||
if (input_files.size() > 1 && !opts.no_fn_fs)
|
||||
{
|
||||
if (match.epub_filepath != last_epub)
|
||||
{
|
||||
if (vm.count("nocolor") == 0)
|
||||
if (!opts.nocolor)
|
||||
{
|
||||
cout << termcolor::yellow;
|
||||
}
|
||||
|
||||
cout << format(translate(" In {0:s}: \n").str().data(),
|
||||
fs::relative(match.epub_filepath));
|
||||
last_epub = match.epub_filepath;
|
||||
|
||||
if (vm.count("nocolor") == 0)
|
||||
if (!opts.nocolor)
|
||||
{
|
||||
cout << termcolor::reset;
|
||||
}
|
||||
}
|
||||
}
|
||||
cout << match.filepath;
|
||||
|
||||
vector<string> prefix;
|
||||
if (!opts.no_fn_epub)
|
||||
{
|
||||
prefix.emplace_back(match.filepath);
|
||||
}
|
||||
if (!match.headline.empty())
|
||||
{
|
||||
cout << ", " << match.headline;
|
||||
prefix.emplace_back(match.headline);
|
||||
}
|
||||
if (!match.page.empty())
|
||||
{
|
||||
cout << ", page " << match.page;
|
||||
prefix.emplace_back("page " + match.page);
|
||||
}
|
||||
for (const auto &part : prefix)
|
||||
{
|
||||
cout << part;
|
||||
if (part != *(prefix.rbegin()))
|
||||
{
|
||||
cout << ", ";
|
||||
}
|
||||
}
|
||||
cout << ": " << match.context.first;
|
||||
if (vm.count("nocolor") == 0)
|
||||
if (!opts.nocolor)
|
||||
{
|
||||
cout << termcolor::bright_magenta << match.text
|
||||
<< termcolor::reset;
|
||||
cout << termcolor::bright_magenta;
|
||||
}
|
||||
else
|
||||
cout << match.text;
|
||||
if (!opts.nocolor)
|
||||
{
|
||||
cout << match.text;
|
||||
cout << termcolor::reset;
|
||||
}
|
||||
cout << match.context.second << '\n';
|
||||
}
|
||||
|
@ -31,7 +31,9 @@
|
||||
#include <exception>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace epubgrep::options
|
||||
{
|
||||
@ -41,7 +43,7 @@ namespace po = boost::program_options;
|
||||
using boost::locale::translate;
|
||||
using std::cout;
|
||||
|
||||
po::variables_map parse_options(int argc, char *argv[])
|
||||
options parse_options(int argc, char *argv[])
|
||||
{
|
||||
po::options_description options_visible(translate("Available options"));
|
||||
// clang-format off
|
||||
@ -73,9 +75,9 @@ po::variables_map parse_options(int argc, char *argv[])
|
||||
translate("Print NUMBER words of context around matches.")
|
||||
.str().data())
|
||||
("nocolor", translate("Do not color matches.") .str().data())
|
||||
("no-filename",
|
||||
translate("Suppress the mentioning of EPUB file names on output.")
|
||||
.str().data())
|
||||
("no-filename",po::value<std::string>()->value_name(translate("WHICH")),
|
||||
translate("Suppress the mentioning of file names on output. "
|
||||
"WHICH is ‘filesystem’, ‘in-epub’ or ‘all’.").str().data())
|
||||
("recursive,r",
|
||||
translate("Read all files under each directory, recursively.")
|
||||
.str().data())
|
||||
@ -139,7 +141,7 @@ po::variables_map parse_options(int argc, char *argv[])
|
||||
"conditions.\n");
|
||||
}
|
||||
|
||||
return vm;
|
||||
return parse_again(vm);
|
||||
}
|
||||
|
||||
fs::path get_config_path()
|
||||
@ -172,4 +174,62 @@ fs::path get_config_path()
|
||||
return "epubgrep.conf";
|
||||
}
|
||||
|
||||
options parse_again(const po::variables_map &vm)
|
||||
{
|
||||
options opts;
|
||||
|
||||
opts.help = vm.count("help") > 0;
|
||||
opts.version = vm.count("version") > 0;
|
||||
if (vm.count("basic-regexp") > 0)
|
||||
{
|
||||
opts.regex = regex_kind::basic;
|
||||
}
|
||||
if (vm.count("extended-regexp") > 0)
|
||||
{
|
||||
opts.regex = regex_kind::extended;
|
||||
}
|
||||
if (vm.count("perl-regexp") > 0)
|
||||
{
|
||||
opts.regex = regex_kind::perl;
|
||||
}
|
||||
opts.grep = vm.count("grep") > 0;
|
||||
opts.ignore_case = vm.count("ignore-case") > 0;
|
||||
opts.nocolor = vm.count("nocolor") > 0;
|
||||
if (vm.count("no-filename") > 0)
|
||||
{
|
||||
if (vm["no-filename"].as<std::string>() == "filesystem")
|
||||
{
|
||||
opts.no_fn_fs = true;
|
||||
}
|
||||
else if (vm["no-filename"].as<std::string>() == "in-epub")
|
||||
{
|
||||
opts.no_fn_epub = true;
|
||||
}
|
||||
else if (vm["no-filename"].as<std::string>() == "all")
|
||||
{
|
||||
opts.no_fn_fs = true;
|
||||
opts.no_fn_epub = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error{"'--no-filename' must be either "
|
||||
"‘filesystem’, ‘in-epub’ or ‘all’."};
|
||||
}
|
||||
}
|
||||
opts.recursive = vm.count("recursive") > 0;
|
||||
opts.dereference_recursive = vm.count("dereference-recursive") > 0;
|
||||
|
||||
if (vm.count("regexp") > 0)
|
||||
{
|
||||
opts.regexp = vm["regexp"].as<std::vector<std::string>>();
|
||||
}
|
||||
|
||||
if (vm.count("input-file") > 0)
|
||||
{
|
||||
opts.input_file = vm["input-file"].as<std::vector<std::string>>();
|
||||
}
|
||||
|
||||
return opts;
|
||||
}
|
||||
|
||||
} // namespace epubgrep::options
|
||||
|
@ -21,13 +21,43 @@
|
||||
|
||||
#include <boost/program_options/variables_map.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace epubgrep::options
|
||||
{
|
||||
|
||||
namespace po = boost::program_options;
|
||||
|
||||
enum class regex_kind
|
||||
{
|
||||
basic,
|
||||
extended,
|
||||
perl
|
||||
};
|
||||
|
||||
struct options
|
||||
{
|
||||
bool help{false};
|
||||
bool version{false};
|
||||
regex_kind regex{regex_kind::basic};
|
||||
bool grep{false};
|
||||
bool ignore_case{false};
|
||||
std::vector<std::string> regexp;
|
||||
bool raw{false};
|
||||
std::uint64_t context{0};
|
||||
bool nocolor{false};
|
||||
bool no_fn_fs{false};
|
||||
bool no_fn_epub{false};
|
||||
bool recursive{false};
|
||||
bool dereference_recursive{false};
|
||||
std::vector<std::string> input_file;
|
||||
};
|
||||
|
||||
//! Parse options and return them.
|
||||
[[nodiscard]] po::variables_map parse_options(int argc, char *argv[]);
|
||||
[[nodiscard]] options parse_options(int argc, char *argv[]);
|
||||
|
||||
/*!
|
||||
* @brief Returns the path of the config file.
|
||||
@ -38,6 +68,9 @@ namespace po = boost::program_options;
|
||||
*/
|
||||
[[nodiscard]] fs::path get_config_path();
|
||||
|
||||
//! Parse variables map and return nice options struct.
|
||||
[[nodiscard]] options parse_again(const po::variables_map &vm);
|
||||
|
||||
} // namespace epubgrep::options
|
||||
|
||||
#endif // EPUBGREP_OPTIONS_HPP
|
||||
|
@ -32,23 +32,23 @@ namespace epubgrep::search
|
||||
using std::string;
|
||||
|
||||
std::vector<match> search(const fs::path &filepath, std::string_view regex,
|
||||
const options &opts)
|
||||
const settings &opts)
|
||||
{
|
||||
boost::regex::flag_type flags{};
|
||||
|
||||
switch (opts.regex)
|
||||
{
|
||||
case regex_kind::basic:
|
||||
case options::regex_kind::basic:
|
||||
{
|
||||
flags = opts.grep_like ? boost::regex::grep : boost::regex::basic;
|
||||
break;
|
||||
}
|
||||
case regex_kind::extended:
|
||||
case options::regex_kind::extended:
|
||||
{
|
||||
flags = opts.grep_like ? boost::regex::egrep : boost::regex::extended;
|
||||
break;
|
||||
}
|
||||
case regex_kind::perl:
|
||||
case options::regex_kind::perl:
|
||||
{
|
||||
flags = boost::regex::perl;
|
||||
break;
|
||||
|
@ -18,6 +18,7 @@
|
||||
#define EPUBGREP_SEARCH_HPP
|
||||
|
||||
#include "fs-compat.hpp"
|
||||
#include "options.hpp"
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
@ -42,16 +43,9 @@ struct match
|
||||
std::string page; //!< The page number, if available.
|
||||
};
|
||||
|
||||
enum class regex_kind
|
||||
struct settings
|
||||
{
|
||||
basic,
|
||||
extended,
|
||||
perl
|
||||
};
|
||||
|
||||
struct options
|
||||
{
|
||||
regex_kind regex{regex_kind::basic};
|
||||
options::regex_kind regex{options::regex_kind::basic};
|
||||
bool grep_like{false};
|
||||
bool ignore_case{false};
|
||||
bool raw{false};
|
||||
@ -61,7 +55,7 @@ struct options
|
||||
//! Search file, return matches.
|
||||
[[nodiscard]] std::vector<match> search(const fs::path &filepath,
|
||||
std::string_view regex,
|
||||
const options &opts);
|
||||
const settings &opts);
|
||||
|
||||
//! Strip HTML, remove newlines, condense spaces.
|
||||
void cleanup_text(std::string &text);
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "fs-compat.hpp"
|
||||
#include "options.hpp"
|
||||
#include "search.hpp"
|
||||
|
||||
#include <catch.hpp>
|
||||
@ -21,13 +22,13 @@ SCENARIO("Searching works")
|
||||
SECTION("search() doesn't fail and returns the right lines")
|
||||
{
|
||||
std::vector<epubgrep::search::match> matches;
|
||||
epubgrep::search::options opts;
|
||||
epubgrep::search::settings opts;
|
||||
|
||||
WHEN("We search for ‘📙+\\w?’ using extended regular expressions")
|
||||
{
|
||||
try
|
||||
{
|
||||
opts.regex = epubgrep::search::regex_kind::extended;
|
||||
opts.regex = epubgrep::options::regex_kind::extended;
|
||||
matches = epubgrep::search::search(zipfile, "📙+\\w?", opts);
|
||||
}
|
||||
catch (const std::exception &)
|
||||
@ -104,7 +105,7 @@ SCENARIO("Searching works")
|
||||
try
|
||||
{
|
||||
opts.context = 1;
|
||||
opts.regex = epubgrep::search::regex_kind::extended;
|
||||
opts.regex = epubgrep::options::regex_kind::extended;
|
||||
matches = epubgrep::search::search(
|
||||
zipfile, R"(work\s[\w]+\.\W[\w']+\Wstay)", opts);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user