openMSX
SettingsManager.cc
Go to the documentation of this file.
1 #include "SettingsManager.hh"
2 #include "SettingsConfig.hh"
4 #include "MSXException.hh"
5 #include "TclObject.hh"
6 #include "CommandException.hh"
7 #include "outer.hh"
8 #include "view.hh"
9 #include "vla.hh"
10 #include <cassert>
11 #include <cstring>
12 
13 using std::string;
14 
15 namespace openmsx {
16 
17 // SettingsManager implementation:
18 
20  : settingInfo (commandController.getOpenMSXInfoCommand())
21  , setCompleter (commandController)
22  , incrCompleter (commandController, *this, "incr")
23  , unsetCompleter(commandController, *this, "unset")
24 {
25 }
26 
28 {
29  assert(settings.empty());
30 }
31 
33 {
34  assert(!settings.contains(setting.getFullNameObj()));
35  settings.emplace_noDuplicateCheck(&setting);
36 }
37 
39 {
40  const auto& name = setting.getFullNameObj();
41  assert(settings.contains(name));
42  settings.erase(name);
43 }
44 
45 BaseSetting* SettingsManager::findSetting(std::string_view name) const
46 {
47  if (auto it = settings.find(name); it != end(settings)) {
48  return *it;
49  }
50  if (name.starts_with("::")) {
51  // try without leading ::
52  if (auto it = settings.find(name.substr(2)); it != end(settings)) {
53  return *it;
54  }
55  } else {
56  // try adding ::
57  if (auto it = settings.find(tmpStrCat("::", name)); it != end(settings)) {
58  return *it;
59  }
60  }
61  return nullptr;
62 }
63 
64 BaseSetting* SettingsManager::findSetting(std::string_view prefix, std::string_view baseName) const
65 {
66  auto size = prefix.size() + baseName.size();
67  VLA(char, fullname, size);
68  memcpy(&fullname[0], prefix .data(), prefix .size());
69  memcpy(&fullname[prefix.size()], baseName.data(), baseName.size());
70  return findSetting(std::string_view(fullname, size));
71 }
72 
73 // Helper functions for setting commands
74 
75 BaseSetting& SettingsManager::getByName(std::string_view cmd, std::string_view name) const
76 {
77  if (auto* setting = findSetting(name)) {
78  return *setting;
79  }
80  throw CommandException(cmd, ": ", name, ": no such setting");
81 }
82 
83 std::vector<string> SettingsManager::getTabSettingNames() const
84 {
85  std::vector<string> result;
86  result.reserve(settings.size() * 2);
87  for (auto* s : settings) {
88  std::string_view name = s->getFullName();
89  result.emplace_back(name);
90  if (name.starts_with("::")) {
91  result.emplace_back(name.substr(2));
92  } else {
93  result.push_back(strCat("::", name));
94  }
95  }
96  return result;
97 }
98 
100 {
101  // restore default values or load new values
102  for (auto* s : settings) {
103  if (!s->needLoadSave()) continue;
104 
105  s->setValue(s->getRestoreValue());
106 
107  if (const auto* savedValue = config.getValueForSetting(s->getFullName())) {
108  try {
109  s->setValue(TclObject(*savedValue));
110  } catch (MSXException&) {
111  // ignore, keep default value
112  }
113  }
114  }
115 }
116 
117 
118 // class SettingInfo
119 
120 SettingsManager::SettingInfo::SettingInfo(InfoCommand& openMSXInfoCommand)
121  : InfoTopic(openMSXInfoCommand, "setting")
122 {
123 }
124 
125 void SettingsManager::SettingInfo::execute(
126  std::span<const TclObject> tokens, TclObject& result) const
127 {
128  auto& manager = OUTER(SettingsManager, settingInfo);
129  switch (tokens.size()) {
130  case 2:
131  result.addListElements(view::transform(
132  manager.settings,
133  [](auto* p) { return p->getFullNameObj(); }));
134  break;
135  case 3: {
136  const auto& settingName = tokens[2].getString();
137  auto* setting = manager.findSetting(settingName);
138  if (!setting) {
139  throw CommandException("No such setting: ", settingName);
140  }
141  try {
142  setting->info(result);
143  } catch (MSXException& e) {
144  throw CommandException(e.getMessage());
145 
146  }
147  break;
148  }
149  default:
150  throw CommandException("Too many parameters.");
151  }
152 }
153 
154 string SettingsManager::SettingInfo::help(std::span<const TclObject> /*tokens*/) const
155 {
156  return "openmsx_info setting : "
157  "returns list of all settings\n"
158  "openmsx_info setting <name> : "
159  "returns info on a specific setting\n";
160 }
161 
162 void SettingsManager::SettingInfo::tabCompletion(std::vector<string>& tokens) const
163 {
164  if (tokens.size() == 3) {
165  // complete setting name
166  auto& manager = OUTER(SettingsManager, settingInfo);
167  completeString(tokens, manager.getTabSettingNames());
168  }
169 }
170 
171 
172 // class SetCompleter
173 
174 SettingsManager::SetCompleter::SetCompleter(
175  CommandController& commandController_)
176  : CommandCompleter(commandController_, "set")
177 {
178 }
179 
180 string SettingsManager::SetCompleter::help(std::span<const TclObject> tokens) const
181 {
182  if (tokens.size() == 2) {
183  auto& manager = OUTER(SettingsManager, setCompleter);
184  return string(manager.getByName("set", tokens[1].getString()).getDescription());
185  }
186  return "Set or query the value of a openMSX setting or Tcl variable\n"
187  " set <setting> shows current value\n"
188  " set <setting> <value> set a new value\n"
189  "Use 'help set <setting>' to get more info on a specific\n"
190  "openMSX setting.\n";
191 }
192 
193 void SettingsManager::SetCompleter::tabCompletion(std::vector<string>& tokens) const
194 {
195  auto& manager = OUTER(SettingsManager, setCompleter);
196  switch (tokens.size()) {
197  case 2: {
198  // complete setting name
199  completeString(tokens, manager.getTabSettingNames(), false); // case insensitive
200  break;
201  }
202  case 3:
203  // complete setting value
204  if (auto* setting = manager.findSetting(tokens[1])) {
205  setting->tabCompletion(tokens);
206  }
207  break;
208  }
209 }
210 
211 
212 // class SettingCompleter
213 
214 SettingsManager::SettingCompleter::SettingCompleter(
215  CommandController& commandController_, SettingsManager& manager_,
216  const string& name_)
217  : CommandCompleter(commandController_, name_)
218  , manager(manager_)
219 {
220 }
221 
222 string SettingsManager::SettingCompleter::help(std::span<const TclObject> /*tokens*/) const
223 {
224  return {}; // TODO
225 }
226 
227 void SettingsManager::SettingCompleter::tabCompletion(std::vector<string>& tokens) const
228 {
229  if (tokens.size() == 2) {
230  // complete setting name
231  completeString(tokens, manager.getTabSettingNames());
232  }
233 }
234 
235 } // namespace openmsx
BaseSetting * setting
Definition: Interpreter.cc:27
void info(TclObject &result) const
For SettingInfo.
Definition: Setting.cc:27
virtual void tabCompletion(std::vector< std::string > &tokens) const =0
Complete a partly typed value.
const std::string * getValueForSetting(std::string_view setting) const
BaseSetting * findSetting(std::string_view name) const
Find the setting with given name.
SettingsManager(const SettingsManager &)=delete
void unregisterSetting(BaseSetting &setting)
void loadSettings(const SettingsConfig &config)
void registerSetting(BaseSetting &setting)
constexpr double e
Definition: Math.hh:18
This file implemented 3 utility functions:
Definition: Autofire.cc:9
size_t size(std::string_view utf8)
constexpr auto transform(Range &&range, UnaryOp op)
Definition: view.hh:378
#define OUTER(type, member)
Definition: outer.hh:41
TemporaryString tmpStrCat(Ts &&... ts)
Definition: strCat.hh:617
std::string strCat(Ts &&...ts)
Definition: strCat.hh:549
#define VLA(TYPE, NAME, LENGTH)
Definition: vla.hh:10
constexpr auto end(const zstring_view &x)