21 : userSettingCommand(commandController_)
28 settings.push_back(std::move(info));
34 [](
auto& info) {
return info.setting.get(); }));
40 return info.setting->getFullName(); });
41 return (it !=
end(settings)) ? it->setting.get() :
nullptr;
48 :
Command(commandController_,
"user_setting")
52void UserSettings::Cmd::execute(std::span<const TclObject> tokens, TclObject& result)
54 checkNumArgs(tokens, AtLeast{2},
"subcommand ?arg ...?");
55 executeSubCommand(tokens[1].getString(),
56 "create", [&]{
create(tokens, result); },
57 "destroy", [&]{ destroy(tokens, result); },
58 "info", [&]{ info(tokens, result); });
63 checkNumArgs(tokens, AtLeast{5}, Prefix{2},
"type name ?arg ...?");
64 const auto& type = tokens[2].getString();
65 const auto& settingName = tokens[3].getString();
67 auto& controller = checked_cast<GlobalCommandController&>(getCommandController());
68 if (controller.getSettingsManager().findSetting(settingName)) {
69 throw CommandException(
70 "There already exists a setting with this name: ", settingName);
74 if (type ==
"string") {
75 return createString(tokens);
76 }
else if (type ==
"boolean") {
77 return createBoolean(tokens);
78 }
else if (type ==
"integer") {
79 return createInteger(tokens);
80 }
else if (type ==
"float") {
81 return createFloat(tokens);
82 }
else if (type ==
"enum") {
83 return createEnum(tokens);
85 throw CommandException(
86 "Invalid setting type '", type,
"', expected "
87 "'string', 'boolean', 'integer', 'float' or 'enum'.");
90 auto& userSettings =
OUTER(UserSettings, userSettingCommand);
91 userSettings.addSetting(getInfo());
98 checkNumArgs(tokens, 6, Prefix{3},
"name description initial-value");
99 const auto& sName = tokens[3].getString();
100 const auto& desc = tokens[4].getString();
101 const auto& initVal = tokens[5].getString();
104 return {std::make_unique<StringSetting>(getCommandController(), sName,
111 checkNumArgs(tokens, 6, Prefix{3},
"name description initial-value");
112 const auto& sName = tokens[3].getString();
113 const auto& desc = tokens[4].getString();
114 const auto& initVal = tokens[5].getBoolean(getInterpreter());
117 return {std::make_unique<BooleanSetting>(getCommandController(), sName,
124 checkNumArgs(tokens, 8, Prefix{3},
"name description initial-value min-value max-value");
125 auto& interp = getInterpreter();
126 const auto& sName = tokens[3].getString();
127 const auto& desc = tokens[4].getString();
128 const auto& initVal = tokens[5].getInt(interp);
129 const auto& minVal = tokens[6].getInt(interp);
130 const auto& maxVal = tokens[7].getInt(interp);
133 return {std::make_unique<IntegerSetting>(getCommandController(), sName,
134 view, initVal, minVal, maxVal),
140 checkNumArgs(tokens, 8, Prefix{3},
"name description initial-value min-value max-value");
141 auto& interp = getInterpreter();
142 const auto& sName = tokens[3].getString();
143 const auto& desc = tokens[4].getString();
144 const auto& initVal = tokens[5].getDouble(interp);
145 const auto& minVal = tokens[6].getDouble(interp);
146 const auto& maxVal = tokens[7].getDouble(interp);
149 return {std::make_unique<FloatSetting>(getCommandController(), sName,
150 view, initVal, minVal, maxVal),
156 checkNumArgs(tokens, 7, Prefix{3},
"name description initial-value allowed-values-list");
157 const auto& sName = tokens[3].getString();
158 const auto& desc = tokens[4].getString();
159 const auto& initStr = tokens[5].getString();
160 const auto& list = tokens[6];
165 if (s == initStr) initVal = i;
166 return EnumSettingBase::MapEntry{std::string(s), i++};
169 throw CommandException(
170 "Initial value '", initStr,
"' "
171 "must be one of the allowed values '",
172 list.getString(),
'\'');
176 return {std::make_unique<EnumSetting<int>>(
177 getCommandController(), sName,
view, initVal, std::move(map)),
181void UserSettings::Cmd::destroy(std::span<const TclObject> tokens, TclObject& )
183 checkNumArgs(tokens, 3,
"name");
184 const auto& settingName = tokens[2].getString();
186 auto& userSettings =
OUTER(UserSettings, userSettingCommand);
187 auto*
setting = userSettings.findSetting(settingName);
189 throw CommandException(
190 "There is no user setting with this name: ", settingName);
192 userSettings.deleteSetting(*
setting);
195void UserSettings::Cmd::info(std::span<const TclObject> , TclObject& result)
197 result.addListElements(getSettingNames());
200std::string UserSettings::Cmd::help(std::span<const TclObject> tokens)
const
202 if (tokens.size() < 2) {
204 "Manage user-defined settings.\n"
206 "User defined settings are mainly used in Tcl scripts "
207 "to create variables (=settings) that are persistent over "
208 "different openMSX sessions.\n"
210 " user_setting create <type> <name> <description> <init-value> [<min-value> <max-value>]\n"
211 " user_setting destroy <name>\n"
212 " user_setting info\n"
214 "Use 'help user_setting <subcommand>' to see more info "
215 "on a specific subcommand.";
217 assert(tokens.size() >= 2);
218 if (tokens[1] ==
"create") {
220 "user_setting create <type> <name> <description> <init-value> [<min-value> <max-value> | <value-list>]\n"
222 "Create a user defined setting. The extra arguments have the following meaning:\n"
223 " <type> The type for the setting, must be 'string', 'boolean', 'integer' or 'float'.\n"
224 " <name> The name for the setting.\n"
225 " <description> A (short) description for this setting.\n"
226 " This text can be queried via 'help set <setting>'.\n"
227 " <init-value> The initial value for the setting.\n"
228 " This value is only used the very first time the setting is created, otherwise the value is taken from previous openMSX sessions.\n"
229 " <min-value> This parameter is only required for 'integer' and 'float' setting types.\n"
230 " Together with max-value this parameter defines the range of valid values.\n"
231 " <max-value> See min-value.\n"
232 " <value-list> Enum settings have no min and max but instead have a list of possible values";
234 }
else if (tokens[1] ==
"destroy") {
236 "user_setting destroy <name>\n"
238 "Remove a previously defined user setting. This only "
239 "removes the setting from the current openMSX session, "
240 "the value of this setting is still preserved for "
243 }
else if (tokens[1] ==
"info") {
245 "user_setting info\n"
247 "Returns a list of all user defined settings that are "
248 "active in this openMSX session.";
251 return "No such subcommand, see 'help user_setting'.";
255void UserSettings::Cmd::tabCompletion(std::vector<std::string>& tokens)
const
257 using namespace std::literals;
258 if (tokens.size() == 2) {
259 static constexpr std::array cmds = {
260 "create"sv,
"destroy"sv,
"info"sv,
262 completeString(tokens, cmds);
263 }
else if ((tokens.size() == 3) && (tokens[1] ==
"create")) {
264 static constexpr std::array types = {
265 "string"sv,
"boolean"sv,
"integer"sv,
"float"sv,
"enum"sv
267 completeString(tokens, types);
268 }
else if ((tokens.size() == 3) && (tokens[1] ==
"destroy")) {
269 completeString(tokens, getSettingNames());
void deleteSetting(Setting &setting)
void addSetting(Info &&info)
Setting * findSetting(std::string_view name) const
UserSettings(CommandController &commandController)
std::unique_ptr< IDEDevice > create(const DeviceConfig &config)
This file implemented 3 utility functions:
AmdFlash::SectorInfo Info
auto find(InputRange &&range, const T &value)
constexpr auto transform(Range &&range, UnaryOp op)
#define OUTER(type, member)
auto make_string_storage(std::string_view sv)
Take a string_view, make a copy of it, and return a pair of.
auto to_vector(Range &&range) -> std::vector< detail::ToVectorType< T, decltype(std::begin(range))> >
void move_pop_back(VECTOR &v, typename VECTOR::iterator it)
Erase the pointed to element from the given vector.
auto rfind_unguarded(RANGE &range, const VAL &val, Proj proj={})
Similar to the find(_if)_unguarded functions above, but searches from the back to front.
constexpr auto end(const zstring_view &x)