From 97b1def525c42db2257359e2b6d8800e9376b94a Mon Sep 17 00:00:00 2001 From: Jonas Nilsson Date: Mon, 18 Dec 2017 11:47:18 +0100 Subject: [PATCH 1/6] Added basic support for writing description to config string. --- include/CLI/App.hpp | 23 +++++++++++++++++------ tests/IniTest.cpp | 25 +++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/include/CLI/App.hpp b/include/CLI/App.hpp index 816969dfe..64ee29280 100644 --- a/include/CLI/App.hpp +++ b/include/CLI/App.hpp @@ -809,35 +809,46 @@ class App { /// Produce a string that could be read in as a config of the current values of the App. Set default_also to include /// default arguments. Prefix will add a string to the beginning of each option. - std::string config_to_str(bool default_also = false, std::string prefix = "") const { + std::string config_to_str(bool default_also = false, std::string prefix = "", bool write_description = false) const { std::stringstream out; for(const Option_p &opt : options_) { // Only process option with a long-name and configurable if(!opt->lnames_.empty() && opt->get_configurable()) { std::string name = prefix + opt->lnames_[0]; + std::string value; // Non-flags if(opt->get_expected() != 0) { // If the option was found on command line if(opt->count() > 0) - out << name << "=" << detail::inijoin(opt->results()) << std::endl; + value = detail::inijoin(opt->results()); // If the option has a default and is requested by optional argument else if(default_also && !opt->defaultval_.empty()) - out << name << "=" << opt->defaultval_ << std::endl; + value = opt->defaultval_; // Flag, one passed } else if(opt->count() == 1) { - out << name << "=true" << std::endl; + value = "true"; // Flag, multiple passed } else if(opt->count() > 1) { - out << name << "=" << opt->count() << std::endl; + value = std::to_string(opt->count()); // Flag, not present } else if(opt->count() == 0 && default_also) { - out << name << "=false" << std::endl; + value = "false"; + } + + if (value.size() != 0) { + if (write_description and opt->description_.size() != 0) { + if (out.tellp() != 0) { + out << std::endl; + } + out << "; " << opt->description_ << std::endl; + } + out << name << "=" << value << std::endl; } } } diff --git a/tests/IniTest.cpp b/tests/IniTest.cpp index 1e032cc7c..53d706278 100644 --- a/tests/IniTest.cpp +++ b/tests/IniTest.cpp @@ -575,6 +575,31 @@ TEST_F(TApp, IniOutputNoConfigurable) { EXPECT_EQ("simple=3\n", str); } +TEST_F(TApp, IniOutputShortSingleDescription) { + std::string flag = "some_flag"; + std::string description = "Some short description."; + app.add_flag("--" + flag, description); + + run(); + + std::string str = app.config_to_str(true, "", true); + EXPECT_THAT(str, HasSubstr("; " + description + "\n" + flag + "=false\n")); +} + +TEST_F(TApp, IniOutputShortDoubleDescription) { + std::string flag1 = "flagnr1"; + std::string flag2 = "flagnr2"; + std::string description1 = "First description."; + std::string description2 = "Second description."; + app.add_flag("--" + flag1, description1); + app.add_flag("--" + flag2, description2); + + run(); + + std::string str = app.config_to_str(true, "", true); + EXPECT_EQ(str, "; " + description1 + "\n" + flag1 + "=false\n\n; " + description2 + "\n" + flag2 + "=false\n"); +} + TEST_F(TApp, IniOutputVector) { std::vector v; From 44b4801f6b1a6c03766c2858e8a2bafca66dd17e Mon Sep 17 00:00:00 2001 From: Jonas Nilsson Date: Wed, 20 Dec 2017 11:45:53 +0100 Subject: [PATCH 2/6] Changed "and" to "&&" for non compliant compilers (MSVC). --- include/CLI/App.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/CLI/App.hpp b/include/CLI/App.hpp index 64ee29280..7d00e798d 100644 --- a/include/CLI/App.hpp +++ b/include/CLI/App.hpp @@ -842,7 +842,7 @@ class App { } if (value.size() != 0) { - if (write_description and opt->description_.size() != 0) { + if (write_description && opt->description_.size() != 0) { if (out.tellp() != 0) { out << std::endl; } From 987ea1f64e17f56994c25f888e467d908553f4fb Mon Sep 17 00:00:00 2001 From: Jonas Nilsson Date: Thu, 21 Dec 2017 08:55:24 +0100 Subject: [PATCH 3/6] Minor changes. --- include/CLI/App.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/CLI/App.hpp b/include/CLI/App.hpp index 64ee29280..8249703d3 100644 --- a/include/CLI/App.hpp +++ b/include/CLI/App.hpp @@ -842,11 +842,11 @@ class App { } if (value.size() != 0) { - if (write_description and opt->description_.size() != 0) { + if (write_description && opt->has_description()) { if (out.tellp() != 0) { out << std::endl; } - out << "; " << opt->description_ << std::endl; + out << "; " << opt->get_description() << std::endl; } out << name << "=" << value << std::endl; } From b10b9c8291d162ebf3a8bde37ddd806f403d71a3 Mon Sep 17 00:00:00 2001 From: Henry Fredrick Schreiner Date: Sat, 23 Dec 2017 09:47:52 -0600 Subject: [PATCH 4/6] Run clang-format script --- include/CLI/App.hpp | 11 ++++++----- tests/IniTest.cpp | 20 ++++++++++---------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/include/CLI/App.hpp b/include/CLI/App.hpp index 8249703d3..8516bcdff 100644 --- a/include/CLI/App.hpp +++ b/include/CLI/App.hpp @@ -809,7 +809,8 @@ class App { /// Produce a string that could be read in as a config of the current values of the App. Set default_also to include /// default arguments. Prefix will add a string to the beginning of each option. - std::string config_to_str(bool default_also = false, std::string prefix = "", bool write_description = false) const { + std::string + config_to_str(bool default_also = false, std::string prefix = "", bool write_description = false) const { std::stringstream out; for(const Option_p &opt : options_) { @@ -840,10 +841,10 @@ class App { } else if(opt->count() == 0 && default_also) { value = "false"; } - - if (value.size() != 0) { - if (write_description && opt->has_description()) { - if (out.tellp() != 0) { + + if(value.size() != 0) { + if(write_description && opt->has_description()) { + if(out.tellp() != 0) { out << std::endl; } out << "; " << opt->get_description() << std::endl; diff --git a/tests/IniTest.cpp b/tests/IniTest.cpp index 53d706278..2021e34a6 100644 --- a/tests/IniTest.cpp +++ b/tests/IniTest.cpp @@ -576,14 +576,14 @@ TEST_F(TApp, IniOutputNoConfigurable) { } TEST_F(TApp, IniOutputShortSingleDescription) { - std::string flag = "some_flag"; - std::string description = "Some short description."; - app.add_flag("--" + flag, description); - - run(); - - std::string str = app.config_to_str(true, "", true); - EXPECT_THAT(str, HasSubstr("; " + description + "\n" + flag + "=false\n")); + std::string flag = "some_flag"; + std::string description = "Some short description."; + app.add_flag("--" + flag, description); + + run(); + + std::string str = app.config_to_str(true, "", true); + EXPECT_THAT(str, HasSubstr("; " + description + "\n" + flag + "=false\n")); } TEST_F(TApp, IniOutputShortDoubleDescription) { @@ -593,9 +593,9 @@ TEST_F(TApp, IniOutputShortDoubleDescription) { std::string description2 = "Second description."; app.add_flag("--" + flag1, description1); app.add_flag("--" + flag2, description2); - + run(); - + std::string str = app.config_to_str(true, "", true); EXPECT_EQ(str, "; " + description1 + "\n" + flag1 + "=false\n\n; " + description2 + "\n" + flag2 + "=false\n"); } From 78ed99568552f49e47a43920f55fdfab1e4ee1ad Mon Sep 17 00:00:00 2001 From: Henry Fredrick Schreiner Date: Sat, 23 Dec 2017 14:17:38 -0600 Subject: [PATCH 5/6] Add multiline ini comments --- include/CLI/App.hpp | 2 +- include/CLI/StringTools.hpp | 16 ++++++++++++++++ tests/HelpersTest.cpp | 14 ++++++++++++++ tests/IniTest.cpp | 13 +++++++++++++ 4 files changed, 44 insertions(+), 1 deletion(-) diff --git a/include/CLI/App.hpp b/include/CLI/App.hpp index 8516bcdff..39900c6dc 100644 --- a/include/CLI/App.hpp +++ b/include/CLI/App.hpp @@ -847,7 +847,7 @@ class App { if(out.tellp() != 0) { out << std::endl; } - out << "; " << opt->get_description() << std::endl; + out << "; " << detail::fix_newlines("; ", opt->get_description()) << std::endl; } out << name << "=" << value << std::endl; } diff --git a/include/CLI/StringTools.hpp b/include/CLI/StringTools.hpp index 64b8603f3..ded9eaa6c 100644 --- a/include/CLI/StringTools.hpp +++ b/include/CLI/StringTools.hpp @@ -187,5 +187,21 @@ inline std::vector split_up(std::string str) { return output; } +/// Add a leader to the beginning of all new lines (nothing is added +/// at the start of the first line). `"; "` would be for ini files +/// +/// Can't use Regex, or this would be a subs. +inline std::string fix_newlines(std::string leader, std::string input) { + std::string::size_type n = 0; + while(n != std::string::npos && n < input.size()) { + n = input.find('\n', n); + if(n != std::string::npos) { + input = input.substr(0, n + 1) + leader + input.substr(n + 1); + n += leader.size(); + } + } + return input; +} + } // namespace detail } // namespace CLI diff --git a/tests/HelpersTest.cpp b/tests/HelpersTest.cpp index e64a12e03..3f29cc384 100644 --- a/tests/HelpersTest.cpp +++ b/tests/HelpersTest.cpp @@ -359,3 +359,17 @@ TEST(Types, LexicalCastString) { CLI::detail::lexical_cast(input, output); EXPECT_EQ(input, output); } + +TEST(FixNewLines, BasicCheck) { + std::string input = "one\ntwo"; + std::string output = "one\n; two"; + std::string result = CLI::detail::fix_newlines("; ", input); + EXPECT_EQ(result, output); +} + +TEST(FixNewLines, EdgesCheck) { + std::string input = "\none\ntwo\n"; + std::string output = "\n; one\n; two\n; "; + std::string result = CLI::detail::fix_newlines("; ", input); + EXPECT_EQ(result, output); +} diff --git a/tests/IniTest.cpp b/tests/IniTest.cpp index 2021e34a6..f3812153f 100644 --- a/tests/IniTest.cpp +++ b/tests/IniTest.cpp @@ -600,6 +600,19 @@ TEST_F(TApp, IniOutputShortDoubleDescription) { EXPECT_EQ(str, "; " + description1 + "\n" + flag1 + "=false\n\n; " + description2 + "\n" + flag2 + "=false\n"); } +TEST_F(TApp, IniOutputMultiLineDescription) { + std::string flag = "some_flag"; + std::string description = "Some short description.\nThat has lines."; + app.add_flag("--" + flag, description); + + run(); + + std::string str = app.config_to_str(true, "", true); + EXPECT_THAT(str, HasSubstr("; Some short description.\n")); + EXPECT_THAT(str, HasSubstr("; That has lines.\n")); + EXPECT_THAT(str, HasSubstr(flag + "=false\n")); +} + TEST_F(TApp, IniOutputVector) { std::vector v; From 9e183646c57bd50d755fff467d4d436c99fcedaa Mon Sep 17 00:00:00 2001 From: Henry Fredrick Schreiner Date: Sat, 23 Dec 2017 19:18:19 -0600 Subject: [PATCH 6/6] A few fixes for failing tests --- include/CLI/App.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/CLI/App.hpp b/include/CLI/App.hpp index 39900c6dc..038f39297 100644 --- a/include/CLI/App.hpp +++ b/include/CLI/App.hpp @@ -842,9 +842,9 @@ class App { value = "false"; } - if(value.size() != 0) { + if(!value.empty()) { if(write_description && opt->has_description()) { - if(out.tellp() != 0) { + if(static_cast(out.tellp()) != 0) { out << std::endl; } out << "; " << detail::fix_newlines("; ", opt->get_description()) << std::endl;