Skip to content

Commit 967bfe0

Browse files
authored
Set the default configuration file output as TOML (#435)
* Set the default configuration file output as TOML * update formatting
1 parent d8a5bdc commit 967bfe0

File tree

6 files changed

+415
-102
lines changed

6 files changed

+415
-102
lines changed

README.md

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -679,39 +679,39 @@ app.set_config(option_name="",
679679
required=false)
680680
```
681681

682-
If this is called with no arguments, it will remove the configuration file option (like `set_help_flag`). Setting a configuration option is special. If it is present, it will be read along with the normal command line arguments. The file will be read if it exists, and does not throw an error unless `required` is `true`. Configuration files are in `ini` format by default, The reader can also accept many files in [TOML] format 🆕. (other formats can be added by an adept user, some variations are available through customization points in the default formatter). An example of a file:
682+
If this is called with no arguments, it will remove the configuration file option (like `set_help_flag`). Setting a configuration option is special. If it is present, it will be read along with the normal command line arguments. The file will be read if it exists, and does not throw an error unless `required` is `true`. Configuration files are in [TOML] format by default 🚧, though the default reader can also accept files in INI format as well 🆕. It should be noted that CLI11 does not contain a full TOML parser but can read strings from most TOML file and run them through the CLI11 parser. Other formats can be added by an adept user, some variations are available through customization points in the default formatter. An example of a TOML file 🆕:
683683

684684
```ini
685-
; Comments are supported, using a ;
686-
; The default section is [default], case insensitive
685+
# Comments are supported, using a #
686+
# The default section is [default], case insensitive
687687

688688
value = 1
689689
str = "A string"
690-
vector = 1 2 3
691-
str_vector = "one" "two" "and three"
690+
vector = [1,2,3]
691+
str_vector = ["one","two","and three"]
692692

693-
; Sections map to subcommands
693+
# Sections map to subcommands
694694
[subcommand]
695695
in_subcommand = Wow
696696
sub.subcommand = true
697697
```
698-
or equivalently in TOML 🆕
699-
```toml
700-
# Comments are supported, using a #
701-
# The default section is [default], case insensitive
698+
or equivalently in INI format
699+
```ini
700+
; Comments are supported, using a ;
701+
; The default section is [default], case insensitive
702702

703703
value = 1
704704
str = "A string"
705-
vector = [1,2,3]
706-
str_vector = ["one","two","and three"]
705+
vector = 1 2 3
706+
str_vector = "one" "two" "and three"
707707

708-
# Sections map to subcommands
708+
; Sections map to subcommands
709709
[subcommand]
710710
in_subcommand = Wow
711711
sub.subcommand = true
712712
```
713713

714-
Spaces before and after the name and argument are ignored. Multiple arguments are separated by spaces. One set of quotes will be removed, preserving spaces (the same way the command line works). Boolean options can be `true`, `on`, `1`, `yes`, `enable`; or `false`, `off`, `0`, `no`, `disable` (case insensitive). Sections (and `.` separated names) are treated as subcommands (note: this does not necessarily mean that subcommand was passed, it just sets the "defaults"). You cannot set positional-only arguments. 🆕 Subcommands can be triggered from config files if the `configurable` flag was set on the subcommand. Then use `[subcommand]` notation will trigger a subcommand and cause it to act as if it were on the command line.
714+
Spaces before and after the name and argument are ignored. Multiple arguments are separated by spaces. One set of quotes will be removed, preserving spaces (the same way the command line works). Boolean options can be `true`, `on`, `1`, `yes`, `enable`; or `false`, `off`, `0`, `no`, `disable` (case insensitive). Sections (and `.` separated names) are treated as subcommands (note: this does not necessarily mean that subcommand was passed, it just sets the "defaults"). You cannot set positional-only arguments. 🆕 Subcommands can be triggered from configuration files if the `configurable` flag was set on the subcommand. Then the use of `[subcommand]` notation will trigger a subcommand and cause it to act as if it were on the command line.
715715

716716
To print a configuration file from the passed
717717
arguments, use `.config_to_str(default_also=false, prefix="", write_description=false)`, where `default_also` will also show any defaulted arguments, `prefix` will add a prefix, and `write_description` will include option descriptions. See [Config files](https://cliutils.github.io/CLI11/book/chapters/config.html) for some additional details.
@@ -744,7 +744,7 @@ The App class was designed allow toolkits to subclass it, to provide preset defa
744744
but before run behavior, while
745745
still giving the user freedom to `callback` on the main app.
746746

747-
The most important parse function is `parse(std::vector<std::string>)`, which takes a reversed list of arguments (so that `pop_back` processes the args in the correct order). `get_help_ptr` and `get_config_ptr` give you access to the help/config option pointers. The standard `parse` manually sets the name from the first argument, so it should not be in this vector. You can also use `parse(string, bool)` to split up and parse a string; the optional bool should be set to true if you are
747+
The most important parse function is `parse(std::vector<std::string>)`, which takes a reversed list of arguments (so that `pop_back` processes the args in the correct order). `get_help_ptr` and `get_config_ptr` give you access to the help/config option pointers. The standard `parse` manually sets the name from the first argument, so it should not be in this vector. You can also use `parse(string, bool)` to split up and parse a string; the optional boolean should be set to true if you are
748748
including the program name in the string, and false otherwise.
749749

750750
Also, in a related note, the `App` you get a pointer to is stored in the parent `App` in a `shared_ptr`s (similar to `Option`s) and are deleted when the main `App` goes out of scope unless the object has another owner.

book/chapters/config.md

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -41,39 +41,39 @@ If it is needed to get the configuration file name used this can be obtained via
4141

4242
## Configure file format
4343

44-
Here is an example configuration file, in INI format:
44+
Here is an example configuration file, in [TOML](https://github.com/toml-lang/toml) format:
4545

4646
```ini
47-
; Comments are supported, using a ;
48-
; The default section is [default], case insensitive
47+
# Comments are supported, using a #
48+
# The default section is [default], case insensitive
4949

5050
value = 1
5151
str = "A string"
52-
vector = 1 2 3
52+
vector = [1,2,3]
5353

54-
; Section map to subcommands
54+
# Section map to subcommands
5555
[subcommand]
5656
in_subcommand = Wow
57-
sub.subcommand = true
57+
[subcommand.sub]
58+
subcommand = true # could also be give as sub.subcommand=true
5859
```
5960

6061
Spaces before and after the name and argument are ignored. Multiple arguments are separated by spaces. One set of quotes will be removed, preserving spaces (the same way the command line works). Boolean options can be `true`, `on`, `1`, `y`, `t`, `+`, `yes`, `enable`; or `false`, `off`, `0`, `no`, `n`, `f`, `-`, `disable`, (case insensitive). Sections (and `.` separated names) are treated as subcommands (note: this does not necessarily mean that subcommand was passed, it just sets the "defaults". If a subcommand is set to `configurable` then passing the subcommand using `[sub]` in a configuration file will trigger the subcommand.)
6162

62-
CLI11 also supports configuration file in [TOML](https://github.com/toml-lang/toml) format.
63+
CLI11 also supports configuration file in INI format.
6364

64-
```toml
65-
# Comments are supported, using a #
66-
# The default section is [default], case insensitive
65+
```ini
66+
; Comments are supported, using a ;
67+
; The default section is [default], case insensitive
6768

6869
value = 1
6970
str = "A string"
70-
vector = [1,2,3]
71+
vector = 1 2 3
7172

72-
# Section map to subcommands
73+
; Section map to subcommands
7374
[subcommand]
7475
in_subcommand = Wow
75-
[subcommand.sub]
76-
subcommand = true # could also be give as sub.subcommand=true
76+
sub.subcommand = true
7777
```
7878

7979
The main differences are in vector notation and comment character. Note: CLI11 is not a full TOML parser as it just reads values as strings. It is possible (but not recommended) to mix notation.
@@ -83,16 +83,16 @@ The main differences are in vector notation and comment character. Note: CLI11
8383
To print a configuration file from the passed arguments, use `.config_to_str(default_also=false, prefix="", write_description=false)`, where `default_also` will also show any defaulted arguments, `prefix` will add a prefix, and `write_description` will include option descriptions.
8484

8585
### Customization of configure file output
86-
The default config parser/generator has some customization points that allow variations on the INI format. The default formatter has a base configuration that matches the INI format. It defines 5 characters that define how different aspects of the configuration are handled
86+
The default config parser/generator has some customization points that allow variations on the TOML format. The default formatter has a base configuration that matches the TOML format. It defines 5 characters that define how different aspects of the configuration are handled
8787
```cpp
8888
/// the character used for comments
89-
char commentChar = ';';
89+
char commentChar = '#';
9090
/// the character used to start an array '\0' is a default to not use
91-
char arrayStart = '\0';
91+
char arrayStart = '[';
9292
/// the character used to end an array '\0' is a default to not use
93-
char arrayEnd = '\0';
93+
char arrayEnd = ']';
9494
/// the character used to separate elements in an array
95-
char arraySeparator = ' ';
95+
char arraySeparator = ',';
9696
/// the character used separate the name from the value
9797
char valueDelimiter = '=';
9898
```
@@ -111,11 +111,11 @@ auto config_base=app.get_config_formatter_base();
111111
config_base->valueSeparator(':');
112112
```
113113
114-
The default configuration file will read TOML files, but will write out files in the INI format. To specify outputting TOML formatted files use
114+
The default configuration file will read INI files, but will write out files in the TOML format. To specify outputting INI formatted files use
115115
```cpp
116-
app.config_formatter(std::make_shared<CLI::ConfigTOML>());
116+
app.config_formatter(std::make_shared<CLI::ConfigINI>());
117117
```
118-
which makes use of a predefined modification of the ConfigBase class which INI also uses.
118+
which makes use of a predefined modification of the ConfigBase class which TOML also uses.
119119

120120
## Custom formats
121121

include/CLI/App.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ class App {
247247
Option *config_ptr_{nullptr};
248248

249249
/// This is the formatter for help printing. Default provided. INHERITABLE (same pointer)
250-
std::shared_ptr<Config> config_formatter_{new ConfigINI()};
250+
std::shared_ptr<Config> config_formatter_{new ConfigTOML()};
251251

252252
///@}
253253

include/CLI/Config.hpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,11 @@ inline std::vector<ConfigItem> ConfigBase::from_config(std::istream &input) cons
167167
std::string section = "default";
168168

169169
std::vector<ConfigItem> output;
170-
bool defaultArray = (arrayStart == '\0' || arrayStart == ' ') && arrayStart == arrayEnd;
171-
char aStart = (defaultArray) ? '[' : arrayStart;
172-
char aEnd = (defaultArray) ? ']' : arrayEnd;
173-
char aSep = (defaultArray && arraySeparator == ' ') ? ',' : arraySeparator;
170+
bool isDefaultArray = (arrayStart == '[' && arrayEnd == ']' && arraySeparator == ',');
171+
bool isINIArray = (arrayStart == '\0' || arrayStart == ' ') && arrayStart == arrayEnd;
172+
char aStart = (isINIArray) ? '[' : arrayStart;
173+
char aEnd = (isINIArray) ? ']' : arrayEnd;
174+
char aSep = (isINIArray && arraySeparator == ' ') ? ',' : arraySeparator;
174175

175176
while(getline(input, line)) {
176177
std::vector<std::string> items_buffer;
@@ -212,9 +213,9 @@ inline std::vector<ConfigItem> ConfigBase::from_config(std::istream &input) cons
212213
std::string item = detail::trim_copy(line.substr(pos + 1));
213214
if(item.size() > 1 && item.front() == aStart && item.back() == aEnd) {
214215
items_buffer = detail::split_up(item.substr(1, item.length() - 2), aSep);
215-
} else if(defaultArray && item.find_first_of(aSep) != std::string::npos) {
216+
} else if((isDefaultArray || isINIArray) && item.find_first_of(aSep) != std::string::npos) {
216217
items_buffer = detail::split_up(item, aSep);
217-
} else if(defaultArray && item.find_first_of(' ') != std::string::npos) {
218+
} else if((isDefaultArray || isINIArray) && item.find_first_of(' ') != std::string::npos) {
218219
items_buffer = detail::split_up(item);
219220
} else {
220221
items_buffer = {item};

include/CLI/ConfigFwd.hpp

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -71,17 +71,17 @@ class Config {
7171
virtual ~Config() = default;
7272
};
7373

74-
/// This converter works with INI/TOML files; to write proper TOML files use ConfigTOML
74+
/// This converter works with INI/TOML files; to write INI files use ConfigINI
7575
class ConfigBase : public Config {
7676
protected:
7777
/// the character used for comments
78-
char commentChar = ';';
78+
char commentChar = '#';
7979
/// the character used to start an array '\0' is a default to not use
80-
char arrayStart = '\0';
80+
char arrayStart = '[';
8181
/// the character used to end an array '\0' is a default to not use
82-
char arrayEnd = '\0';
82+
char arrayEnd = ']';
8383
/// the character used to separate elements in an array
84-
char arraySeparator = ' ';
84+
char arraySeparator = ',';
8585
/// the character used separate the name from the value
8686
char valueDelimiter = '=';
8787

@@ -113,18 +113,18 @@ class ConfigBase : public Config {
113113
}
114114
};
115115

116-
/// the default Config is the INI file format
117-
using ConfigINI = ConfigBase;
116+
/// the default Config is the TOML file format
117+
using ConfigTOML = ConfigBase;
118118

119-
/// ConfigTOML generates a TOML compliant output
120-
class ConfigTOML : public ConfigINI {
119+
/// ConfigINI generates a "standard" INI compliant output
120+
class ConfigINI : public ConfigTOML {
121121

122122
public:
123-
ConfigTOML() {
124-
commentChar = '#';
125-
arrayStart = '[';
126-
arrayEnd = ']';
127-
arraySeparator = ',';
123+
ConfigINI() {
124+
commentChar = ';';
125+
arrayStart = '\0';
126+
arrayEnd = '\0';
127+
arraySeparator = ' ';
128128
valueDelimiter = '=';
129129
}
130130
};

0 commit comments

Comments
 (0)