#pragma once ///@file #include "comparator.hh" #include #include #include #include namespace nix { int levenshteinDistance(std::string_view first, std::string_view second); /** * A potential suggestion for the cli interface. */ class Suggestion { public: /// The smaller the better int distance; std::string suggestion; std::string to_string() const; GENERATE_CMP(Suggestion, me->distance, me->suggestion) }; class Suggestions { public: std::set suggestions; std::string to_string() const; Suggestions trim( int limit = 5, int maxDistance = 2 ) const; static Suggestions bestMatches ( std::set allMatches, std::string query ); Suggestions& operator+=(const Suggestions & other); }; std::ostream & operator<<(std::ostream & str, const Suggestion &); std::ostream & operator<<(std::ostream & str, const Suggestions &); /** * Either a value of type `T`, or some suggestions */ template class OrSuggestions { public: using Raw = std::variant; Raw raw; T* operator ->() { return &**this; } T& operator *() { return std::get(raw); } operator bool() const noexcept { return std::holds_alternative(raw); } OrSuggestions(T t) : raw(t) { } OrSuggestions() : raw(Suggestions{}) { } static OrSuggestions failed(const Suggestions & s) { auto res = OrSuggestions(); res.raw = s; return res; } static OrSuggestions failed() { return OrSuggestions::failed(Suggestions{}); } const Suggestions & getSuggestions() { static Suggestions noSuggestions; if (const auto & suggestions = std::get_if(&raw)) return *suggestions; else return noSuggestions; } }; }