25 : userSettingCommand(commandController_)
32 settings.push_back(std::move(info));
38 [](
auto& info) {
return info.setting.get(); }));
44 return info.setting->getFullName(); });
45 return (it !=
end(settings)) ? it->setting.get() :
nullptr;
52 :
Command(commandController_,
"user_setting")
56void UserSettings::Cmd::execute(std::span<const TclObject> tokens, TclObject& result)
58 checkNumArgs(tokens, AtLeast{2},
"subcommand ?arg ...?");
59 executeSubCommand(tokens[1].getString(),
60 "create", [&]{
create(tokens, result); },
61 "destroy", [&]{ destroy(tokens, result); },
62 "info", [&]{ info(tokens, result); });
65void UserSettings::Cmd::create(std::span<const TclObject> tokens, TclObject& result)
67 checkNumArgs(tokens, AtLeast{5}, Prefix{2},
"type name ?arg ...?");
68 const auto& type = tokens[2].getString();
69 const auto& settingName = tokens[3].getString();
71 auto& controller = checked_cast<GlobalCommandController&>(getCommandController());
72 if (controller.getSettingsManager().findSetting(settingName)) {
73 throw CommandException(
74 "There already exists a setting with this name: ", settingName);
78 if (type ==
"string") {
79 return createString(tokens);
80 }
else if (type ==
"boolean") {
81 return createBoolean(tokens);
82 }
else if (type ==
"integer") {
83 return createInteger(tokens);
84 }
else if (type ==
"float") {
85 return createFloat(tokens);
86 }
else if (type ==
"enum") {
87 return createEnum(tokens);
89 throw CommandException(
90 "Invalid setting type '", type,
"', expected "
91 "'string', 'boolean', 'integer', 'float' or 'enum'.");
94 auto& userSettings =
OUTER(UserSettings, userSettingCommand);
95 userSettings.addSetting(getInfo());
100UserSettings::Info UserSettings::Cmd::createString(std::span<const TclObject> tokens)
const
102 checkNumArgs(tokens, 6, Prefix{3},
"name description initial-value");
103 const auto& sName = tokens[3].getString();
104 const auto& desc = tokens[4].getString();
105 const auto& initVal = tokens[5].getString();
108 return {std::make_unique<StringSetting>(getCommandController(), sName,
113UserSettings::Info UserSettings::Cmd::createBoolean(std::span<const TclObject> tokens)
const
115 checkNumArgs(tokens, 6, Prefix{3},
"name description initial-value");
116 const auto& sName = tokens[3].getString();
117 const auto& desc = tokens[4].getString();
118 const auto& initVal = tokens[5].getBoolean(getInterpreter());
121 return {std::make_unique<BooleanSetting>(getCommandController(), sName,
126UserSettings::Info UserSettings::Cmd::createInteger(std::span<const TclObject> tokens)
const
128 checkNumArgs(tokens, 8, Prefix{3},
"name description initial-value min-value max-value");
129 auto& interp = getInterpreter();
130 const auto& sName = tokens[3].getString();
131 const auto& desc = tokens[4].getString();
132 const auto& initVal = tokens[5].getInt(interp);
133 const auto& minVal = tokens[6].getInt(interp);
134 const auto& maxVal = tokens[7].getInt(interp);
137 return {std::make_unique<IntegerSetting>(getCommandController(), sName,
138 view, initVal, minVal, maxVal),
142UserSettings::Info UserSettings::Cmd::createFloat(std::span<const TclObject> tokens)
const
144 checkNumArgs(tokens, 8, Prefix{3},
"name description initial-value min-value max-value");
145 auto& interp = getInterpreter();
146 const auto& sName = tokens[3].getString();
147 const auto& desc = tokens[4].getString();
148 const auto& initVal = tokens[5].getDouble(interp);
149 const auto& minVal = tokens[6].getDouble(interp);
150 const auto& maxVal = tokens[7].getDouble(interp);
153 return {std::make_unique<FloatSetting>(getCommandController(), sName,
154 view, initVal, minVal, maxVal),
158UserSettings::Info UserSettings::Cmd::createEnum(std::span<const TclObject> tokens)
const
160 checkNumArgs(tokens, 7, Prefix{3},
"name description initial-value allowed-values-list");
161 const auto& sName = tokens[3].getString();
162 const auto& desc = tokens[4].getString();
163 const auto& initStr = tokens[5].getString();
164 const auto& list = tokens[6];
169 if (s == initStr) initVal = i;
170 return EnumSettingBase::MapEntry{std::string(s), i++};
173 throw CommandException(
174 "Initial value '", initStr,
"' "
175 "must be one of the allowed values '",
176 list.getString(),
'\'');
180 return {std::make_unique<EnumSetting<int>>(
181 getCommandController(), sName,
view, initVal, std::move(map)),
185void UserSettings::Cmd::destroy(std::span<const TclObject> tokens, TclObject& )
187 checkNumArgs(tokens, 3,
"name");
188 const auto& settingName = tokens[2].getString();
190 auto& userSettings =
OUTER(UserSettings, userSettingCommand);
191 auto*
setting = userSettings.findSetting(settingName);
193 throw CommandException(
194 "There is no user setting with this name: ", settingName);
196 userSettings.deleteSetting(*
setting);
199void UserSettings::Cmd::info(std::span<const TclObject> , TclObject& result)
const
201 result.addListElements(getSettingNames());
204std::string UserSettings::Cmd::help(std::span<const TclObject> tokens)
const
206 if (tokens.size() < 2) {
208 "Manage user-defined settings.\n"
210 "User defined settings are mainly used in Tcl scripts "
211 "to create variables (=settings) that are persistent over "
212 "different openMSX sessions.\n"
214 " user_setting create <type> <name> <description> <init-value> [<min-value> <max-value>]\n"
215 " user_setting destroy <name>\n"
216 " user_setting info\n"
218 "Use 'help user_setting <subcommand>' to see more info "
219 "on a specific subcommand.";
221 assert(tokens.size() >= 2);
222 if (tokens[1] ==
"create") {
224 "user_setting create <type> <name> <description> <init-value> [<min-value> <max-value> | <value-list>]\n"
226 "Create a user defined setting. The extra arguments have the following meaning:\n"
227 " <type> The type for the setting, must be 'string', 'boolean', 'integer' or 'float'.\n"
228 " <name> The name for the setting.\n"
229 " <description> A (short) description for this setting.\n"
230 " This text can be queried via 'help set <setting>'.\n"
231 " <init-value> The initial value for the setting.\n"
232 " This value is only used the very first time the setting is created, otherwise the value is taken from previous openMSX sessions.\n"
233 " <min-value> This parameter is only required for 'integer' and 'float' setting types.\n"
234 " Together with max-value this parameter defines the range of valid values.\n"
235 " <max-value> See min-value.\n"
236 " <value-list> Enum settings have no min and max but instead have a list of possible values";
238 }
else if (tokens[1] ==
"destroy") {
240 "user_setting destroy <name>\n"
242 "Remove a previously defined user setting. This only "
243 "removes the setting from the current openMSX session, "
244 "the value of this setting is still preserved for "
247 }
else if (tokens[1] ==
"info") {
249 "user_setting info\n"
251 "Returns a list of all user defined settings that are "
252 "active in this openMSX session.";
255 return "No such subcommand, see 'help user_setting'.";
259void UserSettings::Cmd::tabCompletion(std::vector<std::string>& tokens)
const
261 using namespace std::literals;
262 if (tokens.size() == 2) {
263 static constexpr std::array cmds = {
264 "create"sv,
"destroy"sv,
"info"sv,
266 completeString(tokens, cmds);
267 }
else if ((tokens.size() == 3) && (tokens[1] ==
"create")) {
268 static constexpr std::array types = {
269 "string"sv,
"boolean"sv,
"integer"sv,
"float"sv,
"enum"sv
271 completeString(tokens, types);
272 }
else if ((tokens.size() == 3) && (tokens[1] ==
"destroy")) {
273 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:
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)