Skip to content

Commit 59c5575

Browse files
committed
[FEATURE] Open man page
1 parent b066bf6 commit 59c5575

File tree

3 files changed

+58
-4
lines changed

3 files changed

+58
-4
lines changed

include/sharg/detail/format_man.hpp

+34-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#pragma once
1414

1515
#include <sharg/detail/format_base.hpp>
16+
#include <sharg/test/tmp_filename.hpp>
1617

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

42+
//!\brief Whether to call man and open the man page.
43+
bool open_man_page{false};
44+
4145
public:
4246
/*!\name Constructors, destructor and assignment
4347
* \{
@@ -52,10 +56,38 @@ class format_man : public format_help_base<format_man>
5256
//!\copydoc sharg::detail::format_help_base::format_help_base
5357
format_man(std::vector<std::string> const & names,
5458
update_notifications const version_updates,
55-
bool const advanced = false) :
56-
base_type{names, version_updates, advanced} {};
59+
bool const advanced = false,
60+
bool const open_man_page = false) :
61+
base_type{names, version_updates, advanced},
62+
open_man_page{open_man_page} {};
5763
//!\}
5864

65+
/*!\brief Initiates the printing of the man page to std::cout or opens it in man.
66+
* \param[in] parser_meta The meta information that are needed for a detailed man page.
67+
*/
68+
void parse(parser_meta_data & parser_meta)
69+
{
70+
if (!open_man_page)
71+
return base_type::parse(parser_meta);
72+
73+
sharg::test::tmp_filename tmp_file{parser_meta.app_name.c_str()};
74+
75+
{
76+
std::ofstream out{tmp_file.get_path()};
77+
std::streambuf * coutbuf = std::cout.rdbuf();
78+
std::cout.rdbuf(out.rdbuf());
79+
80+
base_type::parse(parser_meta);
81+
82+
std::cout.rdbuf(coutbuf);
83+
}
84+
85+
std::string command{"/usr/bin/man -l "};
86+
command += tmp_file.get_path().c_str();
87+
if (std::system(command.c_str()) != 0)
88+
throw sharg::parser_error{"Unexpected failure."}; // LCOV_EXCL_LINE
89+
}
90+
5991
private:
6092
//!\brief Prints a help page header in man page format to std::cout.
6193
void print_header()

include/sharg/detail/terminal.hpp

+15
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,21 @@ inline bool input_is_terminal()
4646
#endif
4747
}
4848

49+
/*!\brief Check whether the output is interactive.
50+
* \ingroup parser
51+
* \return True if code is run in a terminal, false otherwise.
52+
* \details
53+
* For example "./some_binary --help | less" will return false. "./some_binary --help" will return true.
54+
*/
55+
inline bool output_is_terminal()
56+
{
57+
#ifndef _WIN32
58+
return isatty(STDOUT_FILENO);
59+
#else
60+
return false;
61+
#endif
62+
}
63+
4964
// ----------------------------------------------------------------------------
5065
// Function get_terminal_size()
5166
// ----------------------------------------------------------------------------

include/sharg/parser.hpp

+9-2
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,7 @@ class parser
758758
executable_name.emplace_back(argv[0]);
759759

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

762763
for (int i = 1, argv_len = argc; i < argv_len; ++i) // start at 1 to skip binary name
763764
{
@@ -793,12 +794,18 @@ class parser
793794

794795
if (arg == "-h" || arg == "--help")
795796
{
796-
format = detail::format_help{subcommands, version_check_dev_decision, false};
797+
if (use_man)
798+
format = detail::format_man{subcommands, version_check_dev_decision, false, true};
799+
else
800+
format = detail::format_help{subcommands, version_check_dev_decision, false};
797801
special_format_was_set = true;
798802
}
799803
else if (arg == "-hh" || arg == "--advanced-help")
800804
{
801-
format = detail::format_help{subcommands, version_check_dev_decision, true};
805+
if (use_man)
806+
format = detail::format_man{subcommands, version_check_dev_decision, true, true};
807+
else
808+
format = detail::format_help{subcommands, version_check_dev_decision, true};
802809
special_format_was_set = true;
803810
}
804811
else if (arg == "--version")

0 commit comments

Comments
 (0)