Skip to content

Commit

Permalink
Add generic findCloseStringMatch and use it also match block names
Browse files Browse the repository at this point in the history
  • Loading branch information
halfgaar committed May 4, 2024
1 parent 469e33f commit b5c72ca
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 22 deletions.
38 changes: 16 additions & 22 deletions configfileparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,28 +94,10 @@ bool ConfigFileParser::testKeyValidity(const std::string &key, const std::string
std::ostringstream oss;
oss << "Config key '" << key << "' is not valid (here).";

// Maybe the user made a typo
auto alternative = validKeys.end();
unsigned int alternative_distance = UINT_MAX;
auto alternative = findCloseStringMatch(validKeys.begin(), validKeys.end(), key);

for (auto possible_key = validKeys.begin(); possible_key != validKeys.end(); ++possible_key)
{
unsigned int distance = distanceBetweenStrings(key, *possible_key);
// We only want to suggest options that look a bit like the unknown
// one. Experimentally I found 50% of the total length a decent
// cutoff.
//
// The mathemathical formula "distance/length < 0.5" can be
// approximated with integers as "distance*2/length < 1"
if ((distance * 2) / key.length() < 1 && distance < alternative_distance)
{
alternative = possible_key;
alternative_distance = distance;
}
}
if (alternative != validKeys.end())
{
// It might indeed have been a typo.
// The space before the question mark is to make copying using mouse-double-click possible.
oss << " Did you mean: " << *alternative << " ?";
}
Expand Down Expand Up @@ -401,6 +383,8 @@ void ConfigFileParser::loadFile(bool test)
std::shared_ptr<BridgeConfig> curBridge;
Settings tmpSettings;

const std::set<std::string> blockNames {"listen", "bridge"};

// Then once we know the config file is valid, process it.
for (std::string &line : lines)
{
Expand All @@ -409,19 +393,29 @@ void ConfigFileParser::loadFile(bool test)
if (std::regex_match(line, matches, block_regex_start))
{
const std::string &key = matches[1].str();
if (key == "listen")
if (testKeyValidity(key, "listen", blockNames))
{
curParseLevel = ConfigParseLevel::Listen;
curListener = std::make_shared<Listener>();
}
else if (key == "bridge")
else if (testKeyValidity(key, "bridge", blockNames))
{
curParseLevel = ConfigParseLevel::Bridge;
curBridge = std::make_unique<BridgeConfig>();
}
else
{
throw ConfigFileException(formatString("'%s' is not a valid block.", key.c_str()));
std::ostringstream oss;
oss << "'" << key << "' is not a valid block.";

auto alt = findCloseStringMatch(blockNames.begin(), blockNames.end(), key);

if (alt != blockNames.end())
{
oss << " Did you mean: " << *alt << " ?";
}

throw ConfigFileException(oss.str());
}

continue;
Expand Down
26 changes: 26 additions & 0 deletions utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,32 @@ std::string protocolVersionString(ProtocolVersion p);

unsigned int distanceBetweenStrings(const std::string &stringA, const std::string &stringB);

template<typename it>
it findCloseStringMatch(it first, it last, const std::string &s)
{
it alternative = last;
unsigned int alternative_distance = UINT_MAX;

for (auto possible_key = first; possible_key != last; ++possible_key)
{
unsigned int distance = distanceBetweenStrings(s, *possible_key);

// We only want to suggest options that look a bit like the unknown
// one. Experimentally I found 50% of the total length a decent
// cutoff.
//
// The mathemathical formula "distance/length < 0.5" can be
// approximated with integers as "distance*2/length < 1"
if ((distance * 2) / s.length() < 1 && distance < alternative_distance)
{
alternative = possible_key;
alternative_distance = distance;
}
}

return alternative;
}

uint32_t ageFromTimePoint(const std::chrono::time_point<std::chrono::steady_clock> &point);
std::chrono::time_point<std::chrono::steady_clock> timepointFromAge(const uint32_t age);

Expand Down

0 comments on commit b5c72ca

Please sign in to comment.