mirror of
https://github.com/GothenburgBitFactory/timewarrior.git
synced 2025-07-07 20:06:39 +02:00
#9 TI-1: Move static functions (un)setConfigVariable(...) to Rules
This commit is contained in:
parent
9d29a14d64
commit
0688e3ba07
3 changed files with 233 additions and 223 deletions
219
src/Rules.cpp
219
src/Rules.cpp
|
@ -1,6 +1,6 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2015 - 2016, Paul Beckingham, Federico Hernandez.
|
||||
// Copyright 2015 - 2018, Thomas Lauf, Paul Beckingham, Federico Hernandez.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -34,6 +34,7 @@
|
|||
#include <cassert>
|
||||
#include <cerrno>
|
||||
#include <inttypes.h>
|
||||
#include <JSON.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Rules::Rules ()
|
||||
|
@ -492,3 +493,219 @@ std::string Rules::parseGroup (const std::vector <std::string>& tokens)
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Note that because this function does not recurse with includes, it therefore
|
||||
// only sees the top-level settings. This has the desirable effect of adding as
|
||||
// an override any setting which resides in an imported file.
|
||||
bool Rules::setConfigVariable (
|
||||
Database& database,
|
||||
const Rules& rules,
|
||||
std::string name,
|
||||
std::string value,
|
||||
bool confirmation /* = false */)
|
||||
{
|
||||
// Read config file as lines of text.
|
||||
std::vector <std::string> lines;
|
||||
File::read (rules.file (), lines);
|
||||
|
||||
bool change = false;
|
||||
|
||||
if (rules.has (name))
|
||||
{
|
||||
// No change.
|
||||
if (rules.get (name) == value)
|
||||
return false;
|
||||
|
||||
// If there is a non-comment line containing the entry in flattened form:
|
||||
// a.b.c = value
|
||||
bool found = false;
|
||||
for (auto& line : lines)
|
||||
{
|
||||
auto comment = line.find ('#');
|
||||
auto pos = line.find (name);
|
||||
if (pos != std::string::npos &&
|
||||
(comment == std::string::npos || comment > pos))
|
||||
{
|
||||
found = true;
|
||||
|
||||
// Modify value
|
||||
if (! confirmation ||
|
||||
confirm (format ("Are you sure you want to change the value of '{1}' from '{2}' to '{3}'?",
|
||||
name,
|
||||
rules.get (name),
|
||||
value)))
|
||||
{
|
||||
auto before = line;
|
||||
line = line.substr (0, pos) + name + " = " + value;
|
||||
|
||||
database.recordConfigAction (before, line);
|
||||
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If it was not found, then retry in hierarchical form∴
|
||||
// a:
|
||||
// b:
|
||||
// c = value
|
||||
if (! found)
|
||||
{
|
||||
auto leaf = split (name, '.').back () + ":";
|
||||
for (auto& line : lines)
|
||||
{
|
||||
auto comment = line.find ('#');
|
||||
auto pos = line.find (leaf);
|
||||
if (pos != std::string::npos &&
|
||||
(comment == std::string::npos || comment > pos))
|
||||
{
|
||||
found = true;
|
||||
|
||||
// Remove name
|
||||
if (! confirmation ||
|
||||
confirm (format ("Are you sure you want to change the value of '{1}' from '{2}' to '{3}'?",
|
||||
name,
|
||||
rules.get (name),
|
||||
value)))
|
||||
{
|
||||
auto before = line;
|
||||
line = line.substr (0, pos) + leaf + " " + value;
|
||||
|
||||
database.recordConfigAction (before, line);
|
||||
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (! found)
|
||||
{
|
||||
// Remove name
|
||||
if (! confirmation ||
|
||||
confirm (format ("Are you sure you want to change the value of '{1}' from '{2}' to '{3}'?",
|
||||
name,
|
||||
rules.get (name),
|
||||
value)))
|
||||
{
|
||||
// Add blank line required by rules.
|
||||
if (lines.empty () || lines.back ().empty ())
|
||||
lines.push_back ("");
|
||||
|
||||
// Add new line.
|
||||
lines.push_back (name + " = " + json::encode (value));
|
||||
|
||||
database.recordConfigAction ("", lines.back ());
|
||||
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! confirmation ||
|
||||
confirm (format ("Are you sure you want to add '{1}' with a value of '{2}'?", name, value)))
|
||||
{
|
||||
// TODO Ideally, this would locate an existing hierarchy and insert the
|
||||
// new leaf/value properly. But that's non-trivial.
|
||||
|
||||
// Add blank line required by rules.
|
||||
if (lines.empty () || lines.back ().empty ())
|
||||
lines.push_back ("");
|
||||
|
||||
// Add new line.
|
||||
lines.push_back (name + " = " + json::encode (value));
|
||||
|
||||
database.recordConfigAction ("", lines.back ());
|
||||
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (change)
|
||||
File::write (rules.file (), lines);
|
||||
|
||||
return change;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Removes lines from configuration but leaves comments intact.
|
||||
//
|
||||
// Return codes:
|
||||
// 0 - found and removed
|
||||
// 1 - found and not removed
|
||||
// 2 - not found
|
||||
int Rules::unsetConfigVariable (
|
||||
Database& database,
|
||||
const Rules& rules,
|
||||
std::string name,
|
||||
bool confirmation /* = false */)
|
||||
{
|
||||
// Setting not found.
|
||||
if (! rules.has (name))
|
||||
return 2;
|
||||
|
||||
// Read config file as lines of text.
|
||||
std::vector <std::string> lines;
|
||||
File::read (rules.file (), lines);
|
||||
|
||||
// If there is a non-comment line containing the entry in flattened form:
|
||||
// a.b.c = value
|
||||
bool found = false;
|
||||
bool change = false;
|
||||
for (auto& line : lines)
|
||||
{
|
||||
auto comment = line.find ('#');
|
||||
auto pos = line.find (name);
|
||||
if (pos != std::string::npos &&
|
||||
(comment == std::string::npos || comment > pos))
|
||||
{
|
||||
found = true;
|
||||
|
||||
// Remove name
|
||||
if (! confirmation ||
|
||||
confirm (format ("Are you sure you want to remove '{1}'?", name)))
|
||||
{
|
||||
database.recordConfigAction (line, "");
|
||||
|
||||
line = "";
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If it was not found, then retry in hierarchical form∴
|
||||
// a:
|
||||
// b:
|
||||
// c = value
|
||||
if (! found)
|
||||
{
|
||||
auto leaf = split (name, '.').back () + ":";
|
||||
for (auto& line : lines)
|
||||
{
|
||||
auto comment = line.find ('#');
|
||||
auto pos = line.find (leaf);
|
||||
if (pos != std::string::npos &&
|
||||
(comment == std::string::npos || comment > pos))
|
||||
{
|
||||
found = true;
|
||||
|
||||
// Remove name
|
||||
if (! confirmation ||
|
||||
confirm (format ("Are you sure you want to remove '{1}'?", name)))
|
||||
{
|
||||
line = "";
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (change)
|
||||
File::write (rules.file (), lines);
|
||||
|
||||
if (change && found)
|
||||
return 0;
|
||||
else if (found)
|
||||
return 1;
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
|
13
src/Rules.h
13
src/Rules.h
|
@ -1,6 +1,6 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2015 - 2016, Paul Beckingham, Federico Hernandez.
|
||||
// Copyright 2015 - 2018, Thomas Lauf, Paul Beckingham, Federico Hernandez.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -31,6 +31,7 @@
|
|||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <Database.h>
|
||||
|
||||
class Rules
|
||||
{
|
||||
|
@ -54,6 +55,16 @@ public:
|
|||
|
||||
std::string dump () const;
|
||||
|
||||
static bool setConfigVariable (Database& database,
|
||||
const Rules& rules,
|
||||
std::string name,
|
||||
std::string value,
|
||||
bool confirmation /* = false */);
|
||||
static int unsetConfigVariable (Database& database,
|
||||
const Rules& rules,
|
||||
std::string name,
|
||||
bool confirmation /* = false */);
|
||||
|
||||
private:
|
||||
void parse (const std::string&, int next = 1);
|
||||
void parseRule (const std::string&);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2015 - 2018, Paul Beckingham, Federico Hernandez.
|
||||
// Copyright 2015 - 2018, Thomas Lauf, Paul Beckingham, Federico Hernandez.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -32,224 +32,6 @@
|
|||
#include <commands.h>
|
||||
#include <iostream>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Note that because this function does not recurse with includes, it therefore
|
||||
// only sees the top-level settings. This has the desirable effect of adding as
|
||||
// an override any setting which resides in an imported file.
|
||||
static bool setConfigVariable (
|
||||
Database& database,
|
||||
const Rules& rules,
|
||||
std::string name,
|
||||
std::string value,
|
||||
bool confirmation /* = false */)
|
||||
{
|
||||
// Read config file as lines of text.
|
||||
std::vector <std::string> lines;
|
||||
File::read (rules.file (), lines);
|
||||
|
||||
bool change = false;
|
||||
|
||||
if (rules.has (name))
|
||||
{
|
||||
// No change.
|
||||
if (rules.get (name) == value)
|
||||
return false;
|
||||
|
||||
// If there is a non-comment line containing the entry in flattened form:
|
||||
// a.b.c = value
|
||||
bool found = false;
|
||||
for (auto& line : lines)
|
||||
{
|
||||
auto comment = line.find ('#');
|
||||
auto pos = line.find (name);
|
||||
if (pos != std::string::npos &&
|
||||
(comment == std::string::npos || comment > pos))
|
||||
{
|
||||
found = true;
|
||||
|
||||
// Modify value
|
||||
if (! confirmation ||
|
||||
confirm (format ("Are you sure you want to change the value of '{1}' from '{2}' to '{3}'?",
|
||||
name,
|
||||
rules.get (name),
|
||||
value)))
|
||||
{
|
||||
auto before = line;
|
||||
line = line.substr (0, pos) + name + " = " + value;
|
||||
|
||||
database.recordConfigAction (before, line);
|
||||
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If it was not found, then retry in hierarchical form∴
|
||||
// a:
|
||||
// b:
|
||||
// c = value
|
||||
if (! found)
|
||||
{
|
||||
auto leaf = split (name, '.').back () + ":";
|
||||
for (auto& line : lines)
|
||||
{
|
||||
auto comment = line.find ('#');
|
||||
auto pos = line.find (leaf);
|
||||
if (pos != std::string::npos &&
|
||||
(comment == std::string::npos || comment > pos))
|
||||
{
|
||||
found = true;
|
||||
|
||||
// Remove name
|
||||
if (! confirmation ||
|
||||
confirm (format ("Are you sure you want to change the value of '{1}' from '{2}' to '{3}'?",
|
||||
name,
|
||||
rules.get (name),
|
||||
value)))
|
||||
{
|
||||
auto before = line;
|
||||
line = line.substr (0, pos) + leaf + " " + value;
|
||||
|
||||
database.recordConfigAction (before, line);
|
||||
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (! found)
|
||||
{
|
||||
// Remove name
|
||||
if (! confirmation ||
|
||||
confirm (format ("Are you sure you want to change the value of '{1}' from '{2}' to '{3}'?",
|
||||
name,
|
||||
rules.get (name),
|
||||
value)))
|
||||
{
|
||||
// Add blank line required by rules.
|
||||
if (lines.empty () || lines.back ().empty ())
|
||||
lines.push_back ("");
|
||||
|
||||
// Add new line.
|
||||
lines.push_back (name + " = " + json::encode (value));
|
||||
|
||||
database.recordConfigAction ("", lines.back ());
|
||||
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! confirmation ||
|
||||
confirm (format ("Are you sure you want to add '{1}' with a value of '{2}'?", name, value)))
|
||||
{
|
||||
// TODO Ideally, this would locate an existing hierarchy and insert the
|
||||
// new leaf/value properly. But that's non-trivial.
|
||||
|
||||
// Add blank line required by rules.
|
||||
if (lines.empty () || lines.back ().empty ())
|
||||
lines.push_back ("");
|
||||
|
||||
// Add new line.
|
||||
lines.push_back (name + " = " + json::encode (value));
|
||||
|
||||
database.recordConfigAction ("", lines.back ());
|
||||
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (change)
|
||||
File::write (rules.file (), lines);
|
||||
|
||||
return change;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Removes lines from configuration but leaves comments intact.
|
||||
//
|
||||
// Return codes:
|
||||
// 0 - found and removed
|
||||
// 1 - found and not removed
|
||||
// 2 - not found
|
||||
static int unsetConfigVariable (
|
||||
Database& database,
|
||||
const Rules& rules,
|
||||
std::string name,
|
||||
bool confirmation /* = false */)
|
||||
{
|
||||
// Setting not found.
|
||||
if (! rules.has (name))
|
||||
return 2;
|
||||
|
||||
// Read config file as lines of text.
|
||||
std::vector <std::string> lines;
|
||||
File::read (rules.file (), lines);
|
||||
|
||||
// If there is a non-comment line containing the entry in flattened form:
|
||||
// a.b.c = value
|
||||
bool found = false;
|
||||
bool change = false;
|
||||
for (auto& line : lines)
|
||||
{
|
||||
auto comment = line.find ('#');
|
||||
auto pos = line.find (name);
|
||||
if (pos != std::string::npos &&
|
||||
(comment == std::string::npos || comment > pos))
|
||||
{
|
||||
found = true;
|
||||
|
||||
// Remove name
|
||||
if (! confirmation ||
|
||||
confirm (format ("Are you sure you want to remove '{1}'?", name)))
|
||||
{
|
||||
database.recordConfigAction (line, "");
|
||||
|
||||
line = "";
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If it was not found, then retry in hierarchical form∴
|
||||
// a:
|
||||
// b:
|
||||
// c = value
|
||||
if (! found)
|
||||
{
|
||||
auto leaf = split (name, '.').back () + ":";
|
||||
for (auto& line : lines)
|
||||
{
|
||||
auto comment = line.find ('#');
|
||||
auto pos = line.find (leaf);
|
||||
if (pos != std::string::npos &&
|
||||
(comment == std::string::npos || comment > pos))
|
||||
{
|
||||
found = true;
|
||||
|
||||
// Remove name
|
||||
if (! confirmation ||
|
||||
confirm (format ("Are you sure you want to remove '{1}'?", name)))
|
||||
{
|
||||
line = "";
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (change)
|
||||
File::write (rules.file (), lines);
|
||||
|
||||
if (change && found)
|
||||
return 0;
|
||||
else if (found)
|
||||
return 1;
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// timew config name value Set name=value
|
||||
// timew config name '' Set name=''
|
||||
|
@ -302,7 +84,7 @@ int CmdConfig (
|
|||
value += words[i];
|
||||
}
|
||||
|
||||
change = setConfigVariable (database, rules, name, value, confirmation);
|
||||
change = Rules::setConfigVariable (database, rules, name, value, confirmation);
|
||||
|
||||
if (!change)
|
||||
{
|
||||
|
@ -313,7 +95,7 @@ int CmdConfig (
|
|||
else
|
||||
{
|
||||
bool found = false;
|
||||
rc = unsetConfigVariable (database, rules, name, confirmation);
|
||||
rc = Rules::unsetConfigVariable (database, rules, name, confirmation);
|
||||
if (rc == 0)
|
||||
{
|
||||
change = true;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue