Giter Site home page Giter Site logo

ggabriel96 / opzioni Goto Github PK

View Code? Open in Web Editor NEW
30.0 2.0 0.0 1.16 MB

The wanna-be-simplest command line arguments library for C++

Home Page: https://ggabriel96.github.io/opzioni/

License: Boost Software License 1.0

C++ 98.18% Meson 1.48% Makefile 0.33%
cli terminal options arguments parameters command-line parser command-line-parser cpp cpp20

opzioni's Introduction

opzioni

opzioni is a command line arguments parser library for C++.

Goals

The goals of this library, in order of importance, are:

  1. Be as simple and enjoyable as possible.

    This mainly targets the user of the library, but also includes the user of the command line tool built with it.

  2. constexpr-all-the-things.

    Most of the time, all the information needed to build a command line interface is available at compile-time, so we should take advantage of that.

  3. If it compiles, it works.

    That's utopic, but that's what is being strived for. It's also very closely related to the previous goal. We should be able to detect most errors at compile-time and provide decent diagnostics.

  4. Try not to repeat yourself.

    When specifying a CLI, if some information was already given to the library, that same information should not be needed again. For example, if the type of an argument was already specified, the user should not be asked to tell the type again. Unfortunately that is very hard, so some places still require duplicate information.

  5. Be bleeding-edge.

    This library requires C++20. That limits a lot its potential users, but also allows for the use of the new and powerful features of C++. It also helps to accomplish the previous goals.

Disclaimer

  • This is a personal project with no promise of maintainability for the time being.

    I started it to learn more about C++ and its new features.

  • Although it is not in early development, since I'm working on it for months and iterated over it many times, it is not stable or production-ready.

  • There are many unit tests missing.

  • I frequently changed the interface of the library and I'm not afraid of changing it radically again if I think it would improve the UX.

    Another example is the names of the namespaces and what is in them.

  • There is a lot of polish and optimization work to do.

  • There is a whole documentation to write.

Sneak peek

The code below is a fully working example, taken from examples/hello.cpp, only reformatted and with quotes changed to angle brackets in the #include. Feel free to take a look at the other, more complex, examples in the same directory.

#include <iostream>
#include <string_view>

#include <opzioni.hpp>

int main(int argc, char const *argv[]) {
  using namespace opzioni;

  constexpr auto hello =
    Program("hello")
      .version("0.1")
      .intro("Greeting people since the dawn of computing")
      .add(Pos("name").help("Your name please, so I can greet you"))
      .add(Help())
      .add(Version());

  auto const args = hello(argc, argv);
  std::string_view const name = args["name"];
  std::cout << "Hello, " << name << "!\n";
}

That gives us:

  1. Automatic help with --help or -h

    $ ./build/examples/hello -h
    hello 0.1
    
    Greeting people since the dawn of computing
    
    Usage:
        hello <name> [--help] [--version]
    
    Positionals:
        name             Your name please, so I can greet you
    
    Options & Flags:
        -h, --help       Display this information
        -V, --version    Display the software version
    
  2. Automatic version with --version or -V

    $ ./build/examples/hello -V
    hello 0.1
    
  3. Automatic error handling

    $ ./build/examples/hello Gabriel Galli
    Unexpected positional argument `Galli`. This program expects 1 positional arguments
    
    Usage:
        hello <name> [--help] [--version]
    
  4. And finally:

    $ ./build/examples/hello "Gabriel Galli"
    Hello, Gabriel Galli!
    

Getting started

opzioni is not published anywhere yet. Meanwhile, it is kinda straightforward to build it locally, since just a simple conda environment is enough to bootstrap a development environment. The build system is the awesome Meson.

  1. Download and install conda if you haven't already. Just grab a suitable installer from here and run it. There's also an install guide here.

  2. Clone this repository:

    git clone https://github.com/ggabriel96/opzioni.git
  3. Create the conda environment:

    conda env create -f environment.yml
  4. Activate the newly created conda environment:

    conda activate opzioni
  5. Build it!

    make

Note that the Makefile is just a shortcut to the actual commands. Feel free to inspect it and not use it.

License

opzioni's license is the Boost Software License (BSL) 1.0.

This means you are free to use this library as you wish and see fit.

It is only needed to provide a copy of the license if the source is also being distributed.

In other words, there is no need to bundle opzioni's license with your binary.

Acknowledgements

Thank you to JetBrains for supporting this project by providing free access to its products as part of the Open Source Licenses program.

opzioni's People

Contributors

dependabot[bot] avatar ggabriel96 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

opzioni's Issues

General checks and error reporting

  • error when trying to add an argument with duplicated name or abbreviation
  • error when trying to add an argument with gather and assign action (this is impossible!?)
  • error when trying to add a required argument with a default value
  • error when default_value and set_value are not of same type
  • check that name of Program and Arg is non-empty and only characters, - or _ (gotta make up the specific rule) - #55

Allow users to access Arg attributes in help strings

Using something like: https://godbolt.org/z/85d7oM

Apparently it is not an error to provide fmt::args that do not exist in the format string.

If the user can access these attributes, we should not automatically add them to the arguments description because then they'll duplicate or won't be in the format the user desires. But I wanted to give the option to auto-add them because I like them present and find it tedious to add everything (and be consistent).

Parsing allows multiple dashes

We currently allow users to pass an option --opt as ----opt or with as many dashes as they like (as long as it is more than 2).

Proposal:

  • raise error if more than 2 dashes
  • cover "all dashes" case in is_two_dashes (when all coming arguments are considered positional)

Rename `Arg::csv_of`

Arg::csv_of should have std::string_view as default type, but then it makes a little less sense to write csv_of without a template argument. So it should be only Arg::csv.

Refactor `split_arg`

The function split_arg is a mess and has a not-so-meaningful name. Its name should be clearer about what it does and the code should be simpler.

Fix opzioni::convert

  1. try to specify an argument which has a std::vector<std::string> as default value
  2. get an error because it is not a built-in type
  3. add std::vector<std::string> as built-in type
  4. no suitable converter will be found
  5. try to add a converter
  6. find out there is one for std::vector<int> already and the code for std::vector<std::string> will be identical except for value_type
  7. try to write a generic templatized convert
  8. fail

The return of templated Arg?

The idea

After #1 is merged, we are able to specify the desired type after all parsing and assignment is done, when requesting the argument value.
Additionally, in order for conversion to work for some type T, we only need the opzioni::convert<T> function to exist.
We can then add back a type parameter to Arg, which would default to std::string, and use std::variant to allow our users to tell us the type, default value, even the converter (no more inserting into library namespace), etc, in the definition of the argument.

To "support unsupported types" like we did with std::any, e.g. arbitrary user-defined types, we can do everything as a std::string argument and, at the end, the user would use something like args["foo"].as<MyType>(). Users will only have to define the conversion for MyType (as usual) or they can get its value as a string.

There is a proof-of-concept in variant.cpp.
We can also use the following snippet to maintain an explicit list of types with built-in support for parsing and conversion:

template <typename ...>
struct type_list;

template <typename ...>
struct variant_of;

template <typename ...Ts>
struct variant_of<type_list<Ts...>> {
  using type = std::variant<Ts...>;
};

using builtin_types = type_list<int, float, double>;
using variant = variant_of<builtin_types>::type;

The problem

In order to get the value out of the variant without explicitly asking for the type, we need:

constexpr std::variant<...> v = ...;
constexpr auto val = std::get<v.index()>(v);

Note that the variables are constexpr. But the actual final values of the map will be set at runtime because they will be provided by the user and constexpr implies const (so we cannot update it at runtime).

The solution

After much thought, I decided to accept the reality that it is not possible to 100% avoid asking the user for the type of the argument in the argument definition and when getting its value out after parsing. So I decided that I will minimize the times the user needs to tell the library the type of an argument in its definition. Instead, it will most likely be necessary when getting its value out.

This has been successfully implemented by #12 ๐ŸŽ‰

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.