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