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