Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions include/sharg/detail/format_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -357,8 +357,6 @@ class format_help_base : public format_base
print_legal();

derived_t().print_footer();

std::exit(EXIT_SUCCESS); // program should not continue from here
}

/*!\brief Adds a print_section call to parser_set_up_calls.
Expand Down
12 changes: 3 additions & 9 deletions include/sharg/detail/format_help.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,17 +241,17 @@ class format_help : public format_help_base<format_help>
assert(it != str.end());
if (*it == 'I')
{
if (is_terminal())
if (input_is_terminal())
result.append("\033[4m");
}
else if (*it == 'B')
{
if (is_terminal())
if (input_is_terminal())
result.append("\033[1m");
}
else if (*it == 'P')
{
if (is_terminal())
if (input_is_terminal())
result.append("\033[0m");
}
else
Expand Down Expand Up @@ -422,8 +422,6 @@ class format_short_help : public format_help
print_synopsis();

print_line("Try -h or --help for more information.\n", true);

std::exit(EXIT_SUCCESS);
}
};

Expand All @@ -450,8 +448,6 @@ class format_version : public format_help

print_header();
print_version();

std::exit(EXIT_SUCCESS); // program should not continue from here
}
};

Expand Down Expand Up @@ -526,8 +522,6 @@ DAMAGE.)"};
<< in_bold("This program contains SeqAn code licensed under the following terms:\n")
<< std::string(80, '-') << '\n'
<< seqan_license << '\n';

std::exit(EXIT_SUCCESS);
}
};

Expand Down
36 changes: 34 additions & 2 deletions include/sharg/detail/format_man.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#pragma once

#include <sharg/detail/format_base.hpp>
#include <sharg/test/tmp_filename.hpp>

namespace sharg::detail
{
Expand All @@ -38,6 +39,9 @@ class format_man : public format_help_base<format_man>
//!\brief Befriend the base class to give access to the private member functions.
friend base_type;

//!\brief Whether to call man and open the man page.
bool open_man_page{false};

public:
/*!\name Constructors, destructor and assignment
* \{
Expand All @@ -52,10 +56,38 @@ class format_man : public format_help_base<format_man>
//!\copydoc sharg::detail::format_help_base::format_help_base
format_man(std::vector<std::string> const & names,
update_notifications const version_updates,
bool const advanced = false) :
base_type{names, version_updates, advanced} {};
bool const advanced = false,
bool const open_man_page = false) :
base_type{names, version_updates, advanced},
open_man_page{open_man_page} {};
//!\}

/*!\brief Initiates the printing of the man page to std::cout or opens it in man.
* \param[in] parser_meta The meta information that are needed for a detailed man page.
*/
void parse(parser_meta_data & parser_meta)
{
if (!open_man_page)
return base_type::parse(parser_meta);

sharg::test::tmp_filename tmp_file{parser_meta.app_name.c_str()};

{
std::ofstream out{tmp_file.get_path()};
std::streambuf * coutbuf = std::cout.rdbuf();
std::cout.rdbuf(out.rdbuf());

base_type::parse(parser_meta);

std::cout.rdbuf(coutbuf);
}

std::string command{"/usr/bin/man -l "};
command += tmp_file.get_path().c_str();
if (std::system(command.c_str()) != 0)
throw sharg::parser_error{"Unexpected failure."}; // LCOV_EXCL_LINE
}

private:
//!\brief Prints a help page header in man page format to std::cout.
void print_header()
Expand Down
23 changes: 20 additions & 3 deletions include/sharg/detail/terminal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,16 @@ namespace sharg::detail
{

// ----------------------------------------------------------------------------
// Function is_terminal()
// Function input_is_terminal()
// ----------------------------------------------------------------------------

/*!\brief Check whether we are printing to a terminal.
/*!\brief Check whether the input is a terminal.
* \ingroup parser
* \return True if code is run in a terminal, false otherwise.
* \details
* For example "./some_binary --help | less" will return false. "./some_binary --help" will return true.
*/
inline bool is_terminal()
inline bool input_is_terminal()
{
#ifndef _WIN32
return isatty(STDIN_FILENO);
Expand All @@ -44,6 +46,21 @@ inline bool is_terminal()
#endif
}

/*!\brief Check whether the output is interactive.
* \ingroup parser
* \return True if code is run in a terminal, false otherwise.
* \details
* For example "./some_binary --help | less" will return false. "./some_binary --help" will return true.
*/
inline bool output_is_terminal()
{
#ifndef _WIN32
return isatty(STDOUT_FILENO);
#else
return false;
#endif
}

// ----------------------------------------------------------------------------
// Function get_terminal_size()
// ----------------------------------------------------------------------------
Expand Down
6 changes: 3 additions & 3 deletions include/sharg/detail/version_check.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ class version_checker
* * ASK: Ask the user or default the decision once a day.
*
* If the cookie content is "ASK" and the timestamp is older than a day we ask the user,
* if possible (sharg::detail::is_terminal()), what he wants to do, set the according cookie for the next time
* if possible (sharg::detail::input_is_terminal()), what he wants to do, set the according cookie for the next time
* and continue. If we cannot ask the user, the default kicks in (do the check).
*/
bool decide_if_check_is_performed(update_notifications developer_approval, std::optional<bool> user_approval)
Expand Down Expand Up @@ -336,7 +336,7 @@ class version_checker
// nor did the the cookie tell us what to do. We will now ask the user if possible or do the check by default.
write_cookie("ASK"); // Ask again next time when we read the cookie, if this is not overwritten.

if (detail::is_terminal()) // LCOV_EXCL_START
if (detail::input_is_terminal()) // LCOV_EXCL_START
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also do the same for cerr

{
std::cerr << R"(
#######################################################################
Expand Down Expand Up @@ -385,7 +385,7 @@ class version_checker
}
}
}
else // if !detail::is_terminal()
else // if !detail::input_is_terminal()
{
return false; // default: do not check version today, if you cannot ask the user
}
Expand Down
15 changes: 13 additions & 2 deletions include/sharg/parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,10 @@ class parser
},
format);
parse_was_called = true;

// Exit after parsing any special format.
if (!std::holds_alternative<detail::format_parse>(format))
std::exit(EXIT_SUCCESS);
}

/*!\brief Returns a reference to the sub-parser instance if
Expand Down Expand Up @@ -754,6 +758,7 @@ class parser
executable_name.emplace_back(argv[0]);

bool special_format_was_set{false};
bool const use_man = detail::output_is_terminal() && !system("which /usr/bin/man > /dev/null 2>&1");

for (int i = 1, argv_len = argc; i < argv_len; ++i) // start at 1 to skip binary name
{
Expand Down Expand Up @@ -789,12 +794,18 @@ class parser

if (arg == "-h" || arg == "--help")
{
format = detail::format_help{subcommands, version_check_dev_decision, false};
if (use_man)
format = detail::format_man{subcommands, version_check_dev_decision, false, true};
else
format = detail::format_help{subcommands, version_check_dev_decision, false};
special_format_was_set = true;
}
else if (arg == "-hh" || arg == "--advanced-help")
{
format = detail::format_help{subcommands, version_check_dev_decision, true};
if (use_man)
format = detail::format_man{subcommands, version_check_dev_decision, true, true};
else
format = detail::format_help{subcommands, version_check_dev_decision, true};
special_format_was_set = true;
}
else if (arg == "--version")
Expand Down
2 changes: 1 addition & 1 deletion test/unit/detail/version_check_test.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ TEST_F(version_check, option_on)
}

// Note that we cannot test interactiveness because google test captures std::cin and thus
// sharg::detail::is_terminal() is always false
// sharg::detail::input_is_terminal() is always false
TEST_F(version_check, option_implicitely_on)
{
char const * argv[2] = {app_name.c_str(), "-f"};
Expand Down