openMSX
SettingsManager.cc
Go to the documentation of this file.
1#include "SettingsManager.hh"
2
3#include "CommandException.hh"
5#include "MSXException.hh"
6#include "SettingsConfig.hh"
7#include "TclObject.hh"
8
9#include "outer.hh"
10#include "view.hh"
11#include "vla.hh"
12
13#include <cassert>
14
15namespace 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
45BaseSetting* 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
64BaseSetting* 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 ranges::copy(prefix, fullname);
69 ranges::copy(baseName, fullname.subspan(prefix.size()));
70 return findSetting(std::string_view(fullname.data(), size)); // TODO simplify in c++23
71}
72
73// Helper functions for setting commands
74
75BaseSetting& 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
83std::vector<std::string> SettingsManager::getTabSettingNames() const
84{
85 std::vector<std::string> result;
86 result.reserve(settings.size() * 2);
87 for (const 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 if (const auto* savedValue = config.getValueForSetting(s->getBaseName())) {
106 try {
107 s->setValue(TclObject(*savedValue));
108 } catch (MSXException&) {
109 // ignore error, instead set default value
110 s->setValue(s->getDefaultValue());
111 }
112 } else {
113 s->setValue(s->getDefaultValue());
114 }
115 }
116}
117
118
119// class SettingInfo
120
121SettingsManager::SettingInfo::SettingInfo(InfoCommand& openMSXInfoCommand)
122 : InfoTopic(openMSXInfoCommand, "setting")
123{
124}
125
126void SettingsManager::SettingInfo::execute(
127 std::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 const 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
155std::string SettingsManager::SettingInfo::help(std::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
163void SettingsManager::SettingInfo::tabCompletion(std::vector<std::string>& tokens) const
164{
165 if (tokens.size() == 3) {
166 // complete setting name
167 const auto& manager = OUTER(SettingsManager, settingInfo);
168 completeString(tokens, manager.getTabSettingNames());
169 }
170}
171
172
173// class SetCompleter
174
175SettingsManager::SetCompleter::SetCompleter(
176 CommandController& commandController_)
177 : CommandCompleter(commandController_, "set")
178{
179}
180
181std::string SettingsManager::SetCompleter::help(std::span<const TclObject> tokens) const
182{
183 if (tokens.size() == 2) {
184 const auto& manager = OUTER(SettingsManager, setCompleter);
185 return std::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
194void SettingsManager::SetCompleter::tabCompletion(std::vector<std::string>& tokens) const
195{
196 const 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 (const auto* setting = manager.findSetting(tokens[1])) {
206 setting->tabCompletion(tokens);
207 }
208 break;
209 }
210}
211
212
213// class SettingCompleter
214
215SettingsManager::SettingCompleter::SettingCompleter(
216 CommandController& commandController_, SettingsManager& manager_,
217 const std::string& name_)
218 : CommandCompleter(commandController_, name_)
219 , manager(manager_)
220{
221}
222
223std::string SettingsManager::SettingCompleter::help(std::span<const TclObject> /*tokens*/) const
224{
225 return {}; // TODO
226}
227
228void SettingsManager::SettingCompleter::tabCompletion(std::vector<std::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
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.
void loadSettings(const SettingsConfig &config) const
void unregisterSetting(BaseSetting &setting)
SettingsManager(GlobalCommandController &commandController)
void registerSetting(BaseSetting &setting)
constexpr double e
Definition Math.hh:21
This file implemented 3 utility functions:
Definition Autofire.cc:11
constexpr auto copy(InputRange &&range, OutputIter out)
Definition ranges.hh:252
constexpr auto transform(Range &&range, UnaryOp op)
Definition view.hh:520
#define OUTER(type, member)
Definition outer.hh:42
std::string strCat()
Definition strCat.hh:703
TemporaryString tmpStrCat(Ts &&... ts)
Definition strCat.hh:742
#define VLA(TYPE, NAME, LENGTH)
Definition vla.hh:12
constexpr auto end(const zstring_view &x)