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