mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-11 21:27:01 -04:00
Change tabs to two spaces.
This commit is contained in:
+537
-537
File diff suppressed because it is too large
Load Diff
@@ -21,39 +21,39 @@
|
||||
// ----------------------------------------------------------------------------- : new_card
|
||||
|
||||
SCRIPT_FUNCTION(new_card) {
|
||||
SCRIPT_PARAM(GameP, game);
|
||||
CardP new_card = intrusive(new Card(*game));
|
||||
// set field values
|
||||
SCRIPT_PARAM(ScriptValueP, input);
|
||||
ScriptValueP it = input->makeIterator(input);
|
||||
ScriptValueP key;
|
||||
while (ScriptValueP v = it->next(&key)) {
|
||||
assert(key);
|
||||
String name = key->toString();
|
||||
// find value to update
|
||||
IndexMap<FieldP,ValueP>::const_iterator value_it = new_card->data.find(name);
|
||||
if (value_it == new_card->data.end()) {
|
||||
throw ScriptError(format_string(_("Card doesn't have a field named '%s'"),name));
|
||||
}
|
||||
Value* value = value_it->get();
|
||||
// set the value
|
||||
if (TextValue* tvalue = dynamic_cast<TextValue*>(value)) {
|
||||
tvalue->value = v->toString();
|
||||
} else if (ChoiceValue* cvalue = dynamic_cast<ChoiceValue*>(value)) {
|
||||
cvalue->value = v->toString();
|
||||
} else if (PackageChoiceValue* pvalue = dynamic_cast<PackageChoiceValue*>(value)) {
|
||||
pvalue->package_name = v->toString();
|
||||
} else if (ColorValue* cvalue = dynamic_cast<ColorValue*>(value)) {
|
||||
cvalue->value = (AColor)*v;
|
||||
} else {
|
||||
throw ScriptError(format_string(_("Can not set value '%s', it is not of the right type"),name));
|
||||
}
|
||||
}
|
||||
SCRIPT_RETURN(new_card);
|
||||
SCRIPT_PARAM(GameP, game);
|
||||
CardP new_card = intrusive(new Card(*game));
|
||||
// set field values
|
||||
SCRIPT_PARAM(ScriptValueP, input);
|
||||
ScriptValueP it = input->makeIterator(input);
|
||||
ScriptValueP key;
|
||||
while (ScriptValueP v = it->next(&key)) {
|
||||
assert(key);
|
||||
String name = key->toString();
|
||||
// find value to update
|
||||
IndexMap<FieldP,ValueP>::const_iterator value_it = new_card->data.find(name);
|
||||
if (value_it == new_card->data.end()) {
|
||||
throw ScriptError(format_string(_("Card doesn't have a field named '%s'"),name));
|
||||
}
|
||||
Value* value = value_it->get();
|
||||
// set the value
|
||||
if (TextValue* tvalue = dynamic_cast<TextValue*>(value)) {
|
||||
tvalue->value = v->toString();
|
||||
} else if (ChoiceValue* cvalue = dynamic_cast<ChoiceValue*>(value)) {
|
||||
cvalue->value = v->toString();
|
||||
} else if (PackageChoiceValue* pvalue = dynamic_cast<PackageChoiceValue*>(value)) {
|
||||
pvalue->package_name = v->toString();
|
||||
} else if (ColorValue* cvalue = dynamic_cast<ColorValue*>(value)) {
|
||||
cvalue->value = (AColor)*v;
|
||||
} else {
|
||||
throw ScriptError(format_string(_("Can not set value '%s', it is not of the right type"),name));
|
||||
}
|
||||
}
|
||||
SCRIPT_RETURN(new_card);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Init
|
||||
|
||||
void init_script_construction_functions(Context& ctx) {
|
||||
ctx.setVariable(_("new card"), script_new_card);
|
||||
ctx.setVariable(_("new card"), script_new_card);
|
||||
}
|
||||
|
||||
+311
-311
@@ -32,219 +32,219 @@ DECLARE_TYPEOF_COLLECTION(ChoiceField::ChoiceP);
|
||||
//
|
||||
|
||||
SCRIPT_FUNCTION_WITH_DEP(combined_editor) {
|
||||
// read 'field#' arguments
|
||||
vector<TextValue*> values;
|
||||
for (int i = 0 ; ; ++i) {
|
||||
String name = _("field"); if (i > 0) name = name << i;
|
||||
SCRIPT_OPTIONAL_PARAM_N(ValueP, name, value) {
|
||||
TextValue* text_value = dynamic_cast<TextValue*>(value.get());
|
||||
if (!text_value) throw ScriptError(_("Argument '")+name+_("' should be a text field"));
|
||||
values.push_back(text_value);
|
||||
} else if (i > 0) break;
|
||||
}
|
||||
if (values.empty()) {
|
||||
throw ScriptError(_("No fields specified for combined_editor"));
|
||||
}
|
||||
// read 'separator#' arguments
|
||||
vector<String> separators;
|
||||
for (int i = 0 ; ; ++i) {
|
||||
String name = _("separator"); if (i > 0) name = name << i;
|
||||
SCRIPT_OPTIONAL_PARAM_N(String, name, separator) {
|
||||
separators.push_back(separator);
|
||||
} else if (i > 0) break;
|
||||
}
|
||||
if (separators.size() < values.size() - 1) {
|
||||
throw ScriptError(String::Format(_("Not enough separators for combine_editor, expected %d"), values.size()-1));
|
||||
}
|
||||
// the value
|
||||
SCRIPT_PARAM_C(String, value);
|
||||
// remove suffix/prefix
|
||||
SCRIPT_OPTIONAL_PARAM_(String, prefix);
|
||||
SCRIPT_OPTIONAL_PARAM_(String, suffix);
|
||||
if (is_substr(value,0,_("<prefix"))) {
|
||||
value = value.substr(min(value.size(), match_close_tag_end(value, 0)));
|
||||
}
|
||||
size_t pos = value.rfind(_("<suffix"));
|
||||
if (pos != String::npos && match_close_tag_end(value,pos) >= value.size()) {
|
||||
value = value.substr(0, pos);
|
||||
}
|
||||
// split the value
|
||||
vector<pair<String,bool> > value_parts; // (value part, is empty)
|
||||
pos = value.find(_("<sep"));
|
||||
while (pos != String::npos) {
|
||||
String part = value.substr(0, pos);
|
||||
value_parts.push_back(make_pair(part, false));
|
||||
value = value.substr(min(match_close_tag_end(value,pos), value.size()));
|
||||
pos = value.find(_("<sep"));
|
||||
}
|
||||
value_parts.push_back(make_pair(value, false));
|
||||
value_parts.resize(values.size()); // TODO: what if there are more value_parts than values?
|
||||
// update the values if our input value is newer?
|
||||
Age new_value_update = last_update_age();
|
||||
FOR_EACH_2(v, values, nv, value_parts) {
|
||||
//if (v->value() != nv.first && v->last_update < new_value_update) {
|
||||
if (v->last_update < new_value_update) {
|
||||
bool changed = v->value() != nv.first;
|
||||
v->value.assign(nv.first);
|
||||
changed |= v->update(ctx);
|
||||
v->last_update = new_value_update;
|
||||
if (changed) { // notify of change
|
||||
SCRIPT_OPTIONAL_PARAM_(CardP, card);
|
||||
SCRIPT_PARAM(Set*, set);
|
||||
ScriptValueEvent change(card.get(), v);
|
||||
set->actions.tellListeners(change, false);
|
||||
}
|
||||
}
|
||||
nv.first = v->value();
|
||||
nv.second = index_to_untagged(nv.first, nv.first.size()) == 0;
|
||||
}
|
||||
// options
|
||||
SCRIPT_PARAM_DEFAULT_N(bool, _("hide when empty"), hide_when_empty, false);
|
||||
SCRIPT_PARAM_DEFAULT_N(bool, _("soft before empty"), soft_before_empty, false);
|
||||
// recombine the parts
|
||||
String new_value = value_parts.front().first;
|
||||
bool new_value_empty = value_parts.front().second;
|
||||
size_t size_before_last = 0;
|
||||
for (size_t i = 1 ; i < value_parts.size() ; ++i) {
|
||||
size_before_last = new_value.size();
|
||||
if (value_parts[i].second && new_value_empty && hide_when_empty) {
|
||||
// no separator
|
||||
} else if (value_parts[i].second && soft_before_empty) {
|
||||
// soft separator
|
||||
new_value += _("<sep-soft>") + separators[i - 1] + _("</sep-soft>");
|
||||
new_value_empty = false;
|
||||
} else {
|
||||
// normal separator
|
||||
new_value += _("<sep>") + separators[i - 1] + _("</sep>");
|
||||
new_value_empty = false;
|
||||
}
|
||||
new_value += value_parts[i].first;
|
||||
}
|
||||
if (!new_value_empty || !hide_when_empty) {
|
||||
if (!suffix.empty()) {
|
||||
if (is_substr(new_value, size_before_last, _("<sep-soft>")) && value_parts.size() >= 2) {
|
||||
// If the value ends in a soft separator, we have this situation:
|
||||
// [blah]<sep-soft>ABC</sep-soft><suffix>XYZ</suffix>
|
||||
// This renderes as:
|
||||
// [blah] XYZ
|
||||
// Which looks bad, so instead change the text to
|
||||
// [blah]<sep>XYZ<soft>ABC</soft></sep>
|
||||
// Which might be slightly incorrect, but soft text doesn't matter anyway.
|
||||
size_t after = min(new_value.size(), match_close_tag_end(new_value, size_before_last));
|
||||
new_value = new_value.substr(0, size_before_last)
|
||||
+ _("<sep>")
|
||||
+ suffix
|
||||
+ _("<soft>")
|
||||
+ separators[value_parts.size() - 2]
|
||||
+ _("</soft></sep>")
|
||||
+ new_value.substr(after);
|
||||
} else {
|
||||
new_value += _("<suffix>") + suffix + _("</suffix>");
|
||||
}
|
||||
}
|
||||
if (!prefix.empty()) {
|
||||
new_value = _("<prefix>") + prefix + _("</prefix>") + new_value;
|
||||
}
|
||||
}
|
||||
SCRIPT_RETURN(new_value);
|
||||
// read 'field#' arguments
|
||||
vector<TextValue*> values;
|
||||
for (int i = 0 ; ; ++i) {
|
||||
String name = _("field"); if (i > 0) name = name << i;
|
||||
SCRIPT_OPTIONAL_PARAM_N(ValueP, name, value) {
|
||||
TextValue* text_value = dynamic_cast<TextValue*>(value.get());
|
||||
if (!text_value) throw ScriptError(_("Argument '")+name+_("' should be a text field"));
|
||||
values.push_back(text_value);
|
||||
} else if (i > 0) break;
|
||||
}
|
||||
if (values.empty()) {
|
||||
throw ScriptError(_("No fields specified for combined_editor"));
|
||||
}
|
||||
// read 'separator#' arguments
|
||||
vector<String> separators;
|
||||
for (int i = 0 ; ; ++i) {
|
||||
String name = _("separator"); if (i > 0) name = name << i;
|
||||
SCRIPT_OPTIONAL_PARAM_N(String, name, separator) {
|
||||
separators.push_back(separator);
|
||||
} else if (i > 0) break;
|
||||
}
|
||||
if (separators.size() < values.size() - 1) {
|
||||
throw ScriptError(String::Format(_("Not enough separators for combine_editor, expected %d"), values.size()-1));
|
||||
}
|
||||
// the value
|
||||
SCRIPT_PARAM_C(String, value);
|
||||
// remove suffix/prefix
|
||||
SCRIPT_OPTIONAL_PARAM_(String, prefix);
|
||||
SCRIPT_OPTIONAL_PARAM_(String, suffix);
|
||||
if (is_substr(value,0,_("<prefix"))) {
|
||||
value = value.substr(min(value.size(), match_close_tag_end(value, 0)));
|
||||
}
|
||||
size_t pos = value.rfind(_("<suffix"));
|
||||
if (pos != String::npos && match_close_tag_end(value,pos) >= value.size()) {
|
||||
value = value.substr(0, pos);
|
||||
}
|
||||
// split the value
|
||||
vector<pair<String,bool> > value_parts; // (value part, is empty)
|
||||
pos = value.find(_("<sep"));
|
||||
while (pos != String::npos) {
|
||||
String part = value.substr(0, pos);
|
||||
value_parts.push_back(make_pair(part, false));
|
||||
value = value.substr(min(match_close_tag_end(value,pos), value.size()));
|
||||
pos = value.find(_("<sep"));
|
||||
}
|
||||
value_parts.push_back(make_pair(value, false));
|
||||
value_parts.resize(values.size()); // TODO: what if there are more value_parts than values?
|
||||
// update the values if our input value is newer?
|
||||
Age new_value_update = last_update_age();
|
||||
FOR_EACH_2(v, values, nv, value_parts) {
|
||||
//if (v->value() != nv.first && v->last_update < new_value_update) {
|
||||
if (v->last_update < new_value_update) {
|
||||
bool changed = v->value() != nv.first;
|
||||
v->value.assign(nv.first);
|
||||
changed |= v->update(ctx);
|
||||
v->last_update = new_value_update;
|
||||
if (changed) { // notify of change
|
||||
SCRIPT_OPTIONAL_PARAM_(CardP, card);
|
||||
SCRIPT_PARAM(Set*, set);
|
||||
ScriptValueEvent change(card.get(), v);
|
||||
set->actions.tellListeners(change, false);
|
||||
}
|
||||
}
|
||||
nv.first = v->value();
|
||||
nv.second = index_to_untagged(nv.first, nv.first.size()) == 0;
|
||||
}
|
||||
// options
|
||||
SCRIPT_PARAM_DEFAULT_N(bool, _("hide when empty"), hide_when_empty, false);
|
||||
SCRIPT_PARAM_DEFAULT_N(bool, _("soft before empty"), soft_before_empty, false);
|
||||
// recombine the parts
|
||||
String new_value = value_parts.front().first;
|
||||
bool new_value_empty = value_parts.front().second;
|
||||
size_t size_before_last = 0;
|
||||
for (size_t i = 1 ; i < value_parts.size() ; ++i) {
|
||||
size_before_last = new_value.size();
|
||||
if (value_parts[i].second && new_value_empty && hide_when_empty) {
|
||||
// no separator
|
||||
} else if (value_parts[i].second && soft_before_empty) {
|
||||
// soft separator
|
||||
new_value += _("<sep-soft>") + separators[i - 1] + _("</sep-soft>");
|
||||
new_value_empty = false;
|
||||
} else {
|
||||
// normal separator
|
||||
new_value += _("<sep>") + separators[i - 1] + _("</sep>");
|
||||
new_value_empty = false;
|
||||
}
|
||||
new_value += value_parts[i].first;
|
||||
}
|
||||
if (!new_value_empty || !hide_when_empty) {
|
||||
if (!suffix.empty()) {
|
||||
if (is_substr(new_value, size_before_last, _("<sep-soft>")) && value_parts.size() >= 2) {
|
||||
// If the value ends in a soft separator, we have this situation:
|
||||
// [blah]<sep-soft>ABC</sep-soft><suffix>XYZ</suffix>
|
||||
// This renderes as:
|
||||
// [blah] XYZ
|
||||
// Which looks bad, so instead change the text to
|
||||
// [blah]<sep>XYZ<soft>ABC</soft></sep>
|
||||
// Which might be slightly incorrect, but soft text doesn't matter anyway.
|
||||
size_t after = min(new_value.size(), match_close_tag_end(new_value, size_before_last));
|
||||
new_value = new_value.substr(0, size_before_last)
|
||||
+ _("<sep>")
|
||||
+ suffix
|
||||
+ _("<soft>")
|
||||
+ separators[value_parts.size() - 2]
|
||||
+ _("</soft></sep>")
|
||||
+ new_value.substr(after);
|
||||
} else {
|
||||
new_value += _("<suffix>") + suffix + _("</suffix>");
|
||||
}
|
||||
}
|
||||
if (!prefix.empty()) {
|
||||
new_value = _("<prefix>") + prefix + _("</prefix>") + new_value;
|
||||
}
|
||||
}
|
||||
SCRIPT_RETURN(new_value);
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION_DEPENDENCIES(combined_editor) {
|
||||
// read 'field#' arguments
|
||||
vector<FieldP> fields;
|
||||
for (int i = 0 ; ; ++i) {
|
||||
String name = _("field"); if (i > 0) name = name << i;
|
||||
SCRIPT_OPTIONAL_PARAM_N(ValueP, name, value) {
|
||||
fields.push_back(value->fieldP);
|
||||
} else if (i > 0) break;
|
||||
}
|
||||
// Find the target field
|
||||
SCRIPT_PARAM_C(Set*, set);
|
||||
GameP game = set->game;
|
||||
FieldP target_field;
|
||||
if (dep.type == DEP_CARD_FIELD) target_field = game->card_fields[dep.index];
|
||||
else if (dep.type == DEP_SET_FIELD) target_field = game->set_fields[dep.index];
|
||||
else if (dep.type == DEP_EXTRA_CARD_FIELD) {
|
||||
SCRIPT_PARAM_C(StyleSheetP, stylesheet);
|
||||
target_field = stylesheet->extra_card_fields[dep.index];
|
||||
}
|
||||
else throw InternalError(_("Finding dependencies of combined error for non card/set field"));
|
||||
// Add dependencies, from target_field on field#
|
||||
// For card fields
|
||||
size_t j = 0;
|
||||
FOR_EACH(f, game->card_fields) {
|
||||
Dependency dep(DEP_CARD_COPY_DEP, j++);
|
||||
FOR_EACH(fn, fields) {
|
||||
if (f == fn) {
|
||||
target_field->dependent_scripts.add(dep);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// For set fields
|
||||
j = 0;
|
||||
FOR_EACH(f, game->set_fields) {
|
||||
Dependency dep(DEP_SET_COPY_DEP, j++);
|
||||
FOR_EACH(fn, fields) {
|
||||
if (f == fn) {
|
||||
target_field->dependent_scripts.add(dep);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return dependency_dummy;
|
||||
// read 'field#' arguments
|
||||
vector<FieldP> fields;
|
||||
for (int i = 0 ; ; ++i) {
|
||||
String name = _("field"); if (i > 0) name = name << i;
|
||||
SCRIPT_OPTIONAL_PARAM_N(ValueP, name, value) {
|
||||
fields.push_back(value->fieldP);
|
||||
} else if (i > 0) break;
|
||||
}
|
||||
// Find the target field
|
||||
SCRIPT_PARAM_C(Set*, set);
|
||||
GameP game = set->game;
|
||||
FieldP target_field;
|
||||
if (dep.type == DEP_CARD_FIELD) target_field = game->card_fields[dep.index];
|
||||
else if (dep.type == DEP_SET_FIELD) target_field = game->set_fields[dep.index];
|
||||
else if (dep.type == DEP_EXTRA_CARD_FIELD) {
|
||||
SCRIPT_PARAM_C(StyleSheetP, stylesheet);
|
||||
target_field = stylesheet->extra_card_fields[dep.index];
|
||||
}
|
||||
else throw InternalError(_("Finding dependencies of combined error for non card/set field"));
|
||||
// Add dependencies, from target_field on field#
|
||||
// For card fields
|
||||
size_t j = 0;
|
||||
FOR_EACH(f, game->card_fields) {
|
||||
Dependency dep(DEP_CARD_COPY_DEP, j++);
|
||||
FOR_EACH(fn, fields) {
|
||||
if (f == fn) {
|
||||
target_field->dependent_scripts.add(dep);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// For set fields
|
||||
j = 0;
|
||||
FOR_EACH(f, game->set_fields) {
|
||||
Dependency dep(DEP_SET_COPY_DEP, j++);
|
||||
FOR_EACH(fn, fields) {
|
||||
if (f == fn) {
|
||||
target_field->dependent_scripts.add(dep);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return dependency_dummy;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Choice values
|
||||
|
||||
// convert a full choice name into the name of the top level group it is in
|
||||
SCRIPT_FUNCTION(primary_choice) {
|
||||
SCRIPT_PARAM_C(ValueP,input);
|
||||
ChoiceValueP value = dynamic_pointer_cast<ChoiceValue>(input);
|
||||
if (!value) {
|
||||
throw ScriptError(_("Argument to 'primary_choice' should be a choice value"));
|
||||
}
|
||||
// determine choice
|
||||
int id = value->field().choices->choiceId(value->value);
|
||||
// find the last group that still contains id
|
||||
const vector<ChoiceField::ChoiceP>& choices = value->field().choices->choices;
|
||||
FOR_EACH_CONST_REVERSE(c, choices) {
|
||||
if (id >= c->first_id) {
|
||||
SCRIPT_RETURN(c->name);
|
||||
}
|
||||
}
|
||||
SCRIPT_RETURN(_(""));
|
||||
SCRIPT_PARAM_C(ValueP,input);
|
||||
ChoiceValueP value = dynamic_pointer_cast<ChoiceValue>(input);
|
||||
if (!value) {
|
||||
throw ScriptError(_("Argument to 'primary_choice' should be a choice value"));
|
||||
}
|
||||
// determine choice
|
||||
int id = value->field().choices->choiceId(value->value);
|
||||
// find the last group that still contains id
|
||||
const vector<ChoiceField::ChoiceP>& choices = value->field().choices->choices;
|
||||
FOR_EACH_CONST_REVERSE(c, choices) {
|
||||
if (id >= c->first_id) {
|
||||
SCRIPT_RETURN(c->name);
|
||||
}
|
||||
}
|
||||
SCRIPT_RETURN(_(""));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Multiple choice values
|
||||
|
||||
/// Iterate over a comma separated list
|
||||
bool next_choice(size_t& start, size_t& end, const String& input) {
|
||||
if (start >= input.size()) return false;
|
||||
// ingore whitespace
|
||||
while (start < input.size() && input.GetChar(start) == _(' ')) ++start;
|
||||
// find end
|
||||
end = input.find_first_of(_(','), start);
|
||||
if (end == String::npos) end = input.size();
|
||||
return true;
|
||||
if (start >= input.size()) return false;
|
||||
// ingore whitespace
|
||||
while (start < input.size() && input.GetChar(start) == _(' ')) ++start;
|
||||
// find end
|
||||
end = input.find_first_of(_(','), start);
|
||||
if (end == String::npos) end = input.size();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Is the given choice active?
|
||||
bool chosen(const String& choice, const String& input) {
|
||||
for (size_t start = 0, end = 0 ; next_choice(start,end,input) ; start = end+1 ) {
|
||||
// does this choice match the one asked about?
|
||||
if (end - start == choice.size() && is_substr(input, start, choice)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
for (size_t start = 0, end = 0 ; next_choice(start,end,input) ; start = end+1 ) {
|
||||
// does this choice match the one asked about?
|
||||
if (end - start == choice.size() && is_substr(input, start, choice)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// is the given choice active?
|
||||
SCRIPT_FUNCTION(chosen) {
|
||||
SCRIPT_PARAM_C(String,choice);
|
||||
SCRIPT_PARAM_C(String,input);
|
||||
SCRIPT_RETURN(chosen(choice, input));
|
||||
SCRIPT_PARAM_C(String,choice);
|
||||
SCRIPT_PARAM_C(String,input);
|
||||
SCRIPT_RETURN(chosen(choice, input));
|
||||
}
|
||||
|
||||
/// Filter the choices
|
||||
@@ -252,154 +252,154 @@ SCRIPT_FUNCTION(chosen) {
|
||||
* and at least min. Use prefered as choice to add/keep in case of conflicts.
|
||||
*/
|
||||
String filter_choices(const String& input, const vector<String>& choices, int min, int max, String prefered) {
|
||||
if (choices.empty()) return input; // do nothing, shouldn't happen, but better make sure
|
||||
String ret;
|
||||
int count = 0;
|
||||
vector<bool> seen(choices.size()); // which choices have we seen in input?
|
||||
// walk over the input
|
||||
for (size_t start = 0, end = 0 ; next_choice(start,end,input) ; start = end +1) {
|
||||
// is this choice in choices
|
||||
bool in_choices = false;
|
||||
for (size_t i = 0 ; i < choices.size() ; ++i) {
|
||||
if (!seen[i] && is_substr(input, start, choices[i])) {
|
||||
seen[i] = true; ++count;
|
||||
in_choices = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// is this choice unaffected?
|
||||
if (!in_choices) {
|
||||
if (!ret.empty()) ret += _(", ");
|
||||
ret += input.substr(start, end - start);
|
||||
}
|
||||
}
|
||||
// keep more choices
|
||||
if (count < min) {
|
||||
// add prefered choice
|
||||
for (size_t i = 0 ; i < choices.size() ; ++i) {
|
||||
if (choices[i] == prefered) {
|
||||
if (!seen[i]) {
|
||||
seen[i] = true; ++count;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// add more choices
|
||||
for (size_t i = 0 ; i < choices.size() ; ++i) {
|
||||
if (count >= min) break;
|
||||
if (!seen[i]) {
|
||||
seen[i] = true; ++count;
|
||||
}
|
||||
}
|
||||
}
|
||||
// keep less choices
|
||||
if (count > max) {
|
||||
for (size_t i = choices.size() - 1 ; i >= 0 ; --i) {
|
||||
if (count <= max) break;
|
||||
if (seen[i]) {
|
||||
if (max > 0 && choices[i] == prefered) continue; // we would rather not remove prefered choice
|
||||
seen[i] = false; --count;
|
||||
}
|
||||
}
|
||||
}
|
||||
// add the 'seen' choices to ret
|
||||
for (size_t i = 0 ; i < choices.size() ; ++i) {
|
||||
if (seen[i]) {
|
||||
if (!ret.empty()) ret += _(", ");
|
||||
ret += choices[i];
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
if (choices.empty()) return input; // do nothing, shouldn't happen, but better make sure
|
||||
String ret;
|
||||
int count = 0;
|
||||
vector<bool> seen(choices.size()); // which choices have we seen in input?
|
||||
// walk over the input
|
||||
for (size_t start = 0, end = 0 ; next_choice(start,end,input) ; start = end +1) {
|
||||
// is this choice in choices
|
||||
bool in_choices = false;
|
||||
for (size_t i = 0 ; i < choices.size() ; ++i) {
|
||||
if (!seen[i] && is_substr(input, start, choices[i])) {
|
||||
seen[i] = true; ++count;
|
||||
in_choices = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// is this choice unaffected?
|
||||
if (!in_choices) {
|
||||
if (!ret.empty()) ret += _(", ");
|
||||
ret += input.substr(start, end - start);
|
||||
}
|
||||
}
|
||||
// keep more choices
|
||||
if (count < min) {
|
||||
// add prefered choice
|
||||
for (size_t i = 0 ; i < choices.size() ; ++i) {
|
||||
if (choices[i] == prefered) {
|
||||
if (!seen[i]) {
|
||||
seen[i] = true; ++count;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// add more choices
|
||||
for (size_t i = 0 ; i < choices.size() ; ++i) {
|
||||
if (count >= min) break;
|
||||
if (!seen[i]) {
|
||||
seen[i] = true; ++count;
|
||||
}
|
||||
}
|
||||
}
|
||||
// keep less choices
|
||||
if (count > max) {
|
||||
for (size_t i = choices.size() - 1 ; i >= 0 ; --i) {
|
||||
if (count <= max) break;
|
||||
if (seen[i]) {
|
||||
if (max > 0 && choices[i] == prefered) continue; // we would rather not remove prefered choice
|
||||
seen[i] = false; --count;
|
||||
}
|
||||
}
|
||||
}
|
||||
// add the 'seen' choices to ret
|
||||
for (size_t i = 0 ; i < choices.size() ; ++i) {
|
||||
if (seen[i]) {
|
||||
if (!ret.empty()) ret += _(", ");
|
||||
ret += choices[i];
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// read 'choice#' arguments
|
||||
void read_choices_param(Context& ctx, vector<String>& choices_out) {
|
||||
SCRIPT_OPTIONAL_PARAM_C(String,choices) {
|
||||
for (size_t start = 0, end = 0 ; next_choice(start,end,choices) ; start = end + 1) {
|
||||
choices_out.push_back(choices.substr(start,end-start));
|
||||
}
|
||||
} else {
|
||||
// old style: separate arguments
|
||||
SCRIPT_OPTIONAL_PARAM_C(String,choice) {
|
||||
choices_out.push_back(choice);
|
||||
} else {
|
||||
for (int i = 1 ; ; ++i) {
|
||||
String name = _("choice");
|
||||
SCRIPT_OPTIONAL_PARAM_N(String, name << i, choice) {
|
||||
choices_out.push_back(choice);
|
||||
} else break;
|
||||
}
|
||||
}
|
||||
}
|
||||
SCRIPT_OPTIONAL_PARAM_C(String,choices) {
|
||||
for (size_t start = 0, end = 0 ; next_choice(start,end,choices) ; start = end + 1) {
|
||||
choices_out.push_back(choices.substr(start,end-start));
|
||||
}
|
||||
} else {
|
||||
// old style: separate arguments
|
||||
SCRIPT_OPTIONAL_PARAM_C(String,choice) {
|
||||
choices_out.push_back(choice);
|
||||
} else {
|
||||
for (int i = 1 ; ; ++i) {
|
||||
String name = _("choice");
|
||||
SCRIPT_OPTIONAL_PARAM_N(String, name << i, choice) {
|
||||
choices_out.push_back(choice);
|
||||
} else break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add the given choice if it is not already active
|
||||
SCRIPT_FUNCTION(require_choice) {
|
||||
SCRIPT_PARAM_C(String,input);
|
||||
SCRIPT_OPTIONAL_PARAM_N_(String,_("last change"),last_change);
|
||||
vector<String> choices;
|
||||
read_choices_param(ctx, choices);
|
||||
SCRIPT_RETURN(filter_choices(input, choices, 1, (int)choices.size(), last_change));
|
||||
SCRIPT_PARAM_C(String,input);
|
||||
SCRIPT_OPTIONAL_PARAM_N_(String,_("last change"),last_change);
|
||||
vector<String> choices;
|
||||
read_choices_param(ctx, choices);
|
||||
SCRIPT_RETURN(filter_choices(input, choices, 1, (int)choices.size(), last_change));
|
||||
}
|
||||
|
||||
// make sure at most one of the choices is active
|
||||
SCRIPT_FUNCTION(exclusive_choice) {
|
||||
SCRIPT_PARAM_C(String,input);
|
||||
SCRIPT_OPTIONAL_PARAM_N_(String,_("last change"),last_change);
|
||||
vector<String> choices;
|
||||
read_choices_param(ctx, choices);
|
||||
SCRIPT_RETURN(filter_choices(input, choices, 0, 1, last_change));
|
||||
SCRIPT_PARAM_C(String,input);
|
||||
SCRIPT_OPTIONAL_PARAM_N_(String,_("last change"),last_change);
|
||||
vector<String> choices;
|
||||
read_choices_param(ctx, choices);
|
||||
SCRIPT_RETURN(filter_choices(input, choices, 0, 1, last_change));
|
||||
}
|
||||
|
||||
// make sure exactly one of the choices is active
|
||||
SCRIPT_FUNCTION(require_exclusive_choice) {
|
||||
SCRIPT_PARAM_C(String,input);
|
||||
SCRIPT_OPTIONAL_PARAM_N_(String,_("last change"),last_change);
|
||||
vector<String> choices;
|
||||
read_choices_param(ctx, choices);
|
||||
SCRIPT_RETURN(filter_choices(input, choices, 1, 1, last_change));
|
||||
SCRIPT_PARAM_C(String,input);
|
||||
SCRIPT_OPTIONAL_PARAM_N_(String,_("last change"),last_change);
|
||||
vector<String> choices;
|
||||
read_choices_param(ctx, choices);
|
||||
SCRIPT_RETURN(filter_choices(input, choices, 1, 1, last_change));
|
||||
}
|
||||
|
||||
// make sure none of the choices are active
|
||||
SCRIPT_FUNCTION(remove_choice) {
|
||||
SCRIPT_PARAM_C(String,input);
|
||||
vector<String> choices;
|
||||
read_choices_param(ctx, choices);
|
||||
SCRIPT_RETURN(filter_choices(input, choices, 0, 0, _("")));
|
||||
SCRIPT_PARAM_C(String,input);
|
||||
vector<String> choices;
|
||||
read_choices_param(ctx, choices);
|
||||
SCRIPT_RETURN(filter_choices(input, choices, 0, 0, _("")));
|
||||
}
|
||||
|
||||
// count how many choices are active
|
||||
SCRIPT_FUNCTION(count_chosen) {
|
||||
SCRIPT_PARAM_C(String,input);
|
||||
SCRIPT_OPTIONAL_PARAM_C(String,choices) {
|
||||
// only count specific choices
|
||||
int count = 0;
|
||||
for (size_t start = 0, end = 0 ; next_choice(start,end,choices) ; start = end + 1) {
|
||||
if (chosen(choices.substr(start,end-start),input)) ++count;
|
||||
}
|
||||
SCRIPT_RETURN(count);
|
||||
} else {
|
||||
// count all choices => count comma's + 1
|
||||
if (input.empty()) {
|
||||
SCRIPT_RETURN(0);
|
||||
} else {
|
||||
int count = 1;
|
||||
FOR_EACH(c, input) if (c == _(',')) ++count;
|
||||
SCRIPT_RETURN(count);
|
||||
}
|
||||
}
|
||||
SCRIPT_PARAM_C(String,input);
|
||||
SCRIPT_OPTIONAL_PARAM_C(String,choices) {
|
||||
// only count specific choices
|
||||
int count = 0;
|
||||
for (size_t start = 0, end = 0 ; next_choice(start,end,choices) ; start = end + 1) {
|
||||
if (chosen(choices.substr(start,end-start),input)) ++count;
|
||||
}
|
||||
SCRIPT_RETURN(count);
|
||||
} else {
|
||||
// count all choices => count comma's + 1
|
||||
if (input.empty()) {
|
||||
SCRIPT_RETURN(0);
|
||||
} else {
|
||||
int count = 1;
|
||||
FOR_EACH(c, input) if (c == _(',')) ++count;
|
||||
SCRIPT_RETURN(count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Init
|
||||
|
||||
void init_script_editor_functions(Context& ctx) {
|
||||
ctx.setVariable(_("forward editor"), script_combined_editor); // compatability
|
||||
ctx.setVariable(_("combined editor"), script_combined_editor);
|
||||
ctx.setVariable(_("primary choice"), script_primary_choice);
|
||||
ctx.setVariable(_("chosen"), script_chosen);
|
||||
ctx.setVariable(_("count chosen"), script_count_chosen);
|
||||
ctx.setVariable(_("require choice"), script_require_choice);
|
||||
ctx.setVariable(_("exclusive choice"), script_exclusive_choice);
|
||||
ctx.setVariable(_("require exclusive choice"), script_require_exclusive_choice);
|
||||
ctx.setVariable(_("remove choice"), script_remove_choice);
|
||||
ctx.setVariable(_("forward editor"), script_combined_editor); // compatability
|
||||
ctx.setVariable(_("combined editor"), script_combined_editor);
|
||||
ctx.setVariable(_("primary choice"), script_primary_choice);
|
||||
ctx.setVariable(_("chosen"), script_chosen);
|
||||
ctx.setVariable(_("count chosen"), script_count_chosen);
|
||||
ctx.setVariable(_("require choice"), script_require_choice);
|
||||
ctx.setVariable(_("exclusive choice"), script_exclusive_choice);
|
||||
ctx.setVariable(_("require exclusive choice"), script_require_exclusive_choice);
|
||||
ctx.setVariable(_("remove choice"), script_remove_choice);
|
||||
}
|
||||
|
||||
+251
-251
@@ -15,208 +15,208 @@
|
||||
// ----------------------------------------------------------------------------- : Util
|
||||
|
||||
bool is_vowel(Char c) {
|
||||
return c == _('a') || c == _('e') || c == _('i') || c == _('o') || c == _('u')
|
||||
|| c == _('A') || c == _('E') || c == _('I') || c == _('O') || c == _('U');
|
||||
return c == _('a') || c == _('e') || c == _('i') || c == _('o') || c == _('u')
|
||||
|| c == _('A') || c == _('E') || c == _('I') || c == _('O') || c == _('U');
|
||||
}
|
||||
inline bool is_constant(Char c) {
|
||||
return !is_vowel(c);
|
||||
return !is_vowel(c);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Numbers
|
||||
|
||||
/// Write a number using words, for example 23 -> "twenty-three"
|
||||
String english_number(int i) {
|
||||
switch (i) {
|
||||
case 0: return _("zero");
|
||||
case 1: return _("one");
|
||||
case 2: return _("two");
|
||||
case 3: return _("three");
|
||||
case 4: return _("four");
|
||||
case 5: return _("five");
|
||||
case 6: return _("six");
|
||||
case 7: return _("seven");
|
||||
case 8: return _("eight");
|
||||
case 9: return _("nine");
|
||||
case 10: return _("ten");
|
||||
case 11: return _("eleven");
|
||||
case 12: return _("twelve");
|
||||
case 13: return _("thirteen");
|
||||
case 15: return _("fifteen");
|
||||
case 18: return _("eighteen");
|
||||
case 20: return _("twenty");
|
||||
case 30: return _("thirty");
|
||||
case 40: return _("forty");
|
||||
case 50: return _("fifty");
|
||||
case 80: return _("eighty");
|
||||
default: {
|
||||
if (i < 0 || i >= 100) {
|
||||
// number too large, keep as digits
|
||||
return (String() << i);
|
||||
} else if (i < 20) {
|
||||
return english_number(i%10) + _("teen");
|
||||
} else if (i % 10 == 0) {
|
||||
return english_number(i/10) + _("ty");
|
||||
} else {
|
||||
// <a>ty-<b>
|
||||
return english_number(i/10*10) + _("-") + english_number(i%10);
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (i) {
|
||||
case 0: return _("zero");
|
||||
case 1: return _("one");
|
||||
case 2: return _("two");
|
||||
case 3: return _("three");
|
||||
case 4: return _("four");
|
||||
case 5: return _("five");
|
||||
case 6: return _("six");
|
||||
case 7: return _("seven");
|
||||
case 8: return _("eight");
|
||||
case 9: return _("nine");
|
||||
case 10: return _("ten");
|
||||
case 11: return _("eleven");
|
||||
case 12: return _("twelve");
|
||||
case 13: return _("thirteen");
|
||||
case 15: return _("fifteen");
|
||||
case 18: return _("eighteen");
|
||||
case 20: return _("twenty");
|
||||
case 30: return _("thirty");
|
||||
case 40: return _("forty");
|
||||
case 50: return _("fifty");
|
||||
case 80: return _("eighty");
|
||||
default: {
|
||||
if (i < 0 || i >= 100) {
|
||||
// number too large, keep as digits
|
||||
return (String() << i);
|
||||
} else if (i < 20) {
|
||||
return english_number(i%10) + _("teen");
|
||||
} else if (i % 10 == 0) {
|
||||
return english_number(i/10) + _("ty");
|
||||
} else {
|
||||
// <a>ty-<b>
|
||||
return english_number(i/10*10) + _("-") + english_number(i%10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Write an ordinal number using words, for example 23 -> "twenty-third"
|
||||
String english_ordinal(int i) {
|
||||
switch (i) {
|
||||
case 1: return _("first");
|
||||
case 2: return _("second");
|
||||
case 3: return _("third");
|
||||
case 5: return _("fifth");
|
||||
case 8: return _("eighth");
|
||||
case 9: return _("ninth");
|
||||
case 11: return _("eleventh");
|
||||
case 12: return _("twelfth");
|
||||
default: {
|
||||
if (i <= 0 || i >= 100) {
|
||||
// number too large, keep as digits
|
||||
return String::Format(_("%dth"), i);
|
||||
} else if (i < 20) {
|
||||
return english_number(i) + _("th");
|
||||
} else if (i % 10 == 0) {
|
||||
String num = english_number(i);
|
||||
return num.substr(0,num.size()-1) + _("ieth"); // twentieth
|
||||
} else {
|
||||
// <a>ty-<b>th
|
||||
return english_number(i/10*10) + _("-") + english_ordinal(i%10);
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (i) {
|
||||
case 1: return _("first");
|
||||
case 2: return _("second");
|
||||
case 3: return _("third");
|
||||
case 5: return _("fifth");
|
||||
case 8: return _("eighth");
|
||||
case 9: return _("ninth");
|
||||
case 11: return _("eleventh");
|
||||
case 12: return _("twelfth");
|
||||
default: {
|
||||
if (i <= 0 || i >= 100) {
|
||||
// number too large, keep as digits
|
||||
return String::Format(_("%dth"), i);
|
||||
} else if (i < 20) {
|
||||
return english_number(i) + _("th");
|
||||
} else if (i % 10 == 0) {
|
||||
String num = english_number(i);
|
||||
return num.substr(0,num.size()-1) + _("ieth"); // twentieth
|
||||
} else {
|
||||
// <a>ty-<b>th
|
||||
return english_number(i/10*10) + _("-") + english_ordinal(i%10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Write a number using words, use "a" for 1
|
||||
String english_number_a(int i) {
|
||||
if (i == 1) return _("a");
|
||||
else return english_number(i);
|
||||
if (i == 1) return _("a");
|
||||
else return english_number(i);
|
||||
}
|
||||
/// Write a number using words, use "" for 1
|
||||
String english_number_multiple(int i) {
|
||||
if (i == 1) return _("");
|
||||
else return english_number(i);
|
||||
if (i == 1) return _("");
|
||||
else return english_number(i);
|
||||
}
|
||||
|
||||
|
||||
// script_english_number_*
|
||||
String do_english_num(String input, String(*fun)(int)) {
|
||||
if (is_substr(input, 0, _("<param-"))) {
|
||||
// a keyword parameter, of the form "<param->123</param->"
|
||||
size_t start = skip_tag(input, 0);
|
||||
if (start != String::npos) {
|
||||
size_t end = input.find_first_of(_('<'), start);
|
||||
if (end != String::npos) {
|
||||
String is = input.substr(start, end - start);
|
||||
long i = 0;
|
||||
if (is.ToLong(&i)) {
|
||||
if (i == 1) {
|
||||
return _("<hint-1>") + substr_replace(input, start, end, fun(i));
|
||||
} else {
|
||||
return _("<hint-2>") + substr_replace(input, start, end, fun(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return _("<hint-2>") + input;
|
||||
} else {
|
||||
long i = 0;
|
||||
if (input.ToLong(&i)) {
|
||||
return fun(i);
|
||||
}
|
||||
return input;
|
||||
}
|
||||
if (is_substr(input, 0, _("<param-"))) {
|
||||
// a keyword parameter, of the form "<param->123</param->"
|
||||
size_t start = skip_tag(input, 0);
|
||||
if (start != String::npos) {
|
||||
size_t end = input.find_first_of(_('<'), start);
|
||||
if (end != String::npos) {
|
||||
String is = input.substr(start, end - start);
|
||||
long i = 0;
|
||||
if (is.ToLong(&i)) {
|
||||
if (i == 1) {
|
||||
return _("<hint-1>") + substr_replace(input, start, end, fun(i));
|
||||
} else {
|
||||
return _("<hint-2>") + substr_replace(input, start, end, fun(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return _("<hint-2>") + input;
|
||||
} else {
|
||||
long i = 0;
|
||||
if (input.ToLong(&i)) {
|
||||
return fun(i);
|
||||
}
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(english_number) {
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
SCRIPT_RETURN(do_english_num(input, english_number));
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
SCRIPT_RETURN(do_english_num(input, english_number));
|
||||
}
|
||||
SCRIPT_FUNCTION(english_number_a) {
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
SCRIPT_RETURN(do_english_num(input, english_number_a));
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
SCRIPT_RETURN(do_english_num(input, english_number_a));
|
||||
}
|
||||
SCRIPT_FUNCTION(english_number_multiple) {
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
SCRIPT_RETURN(do_english_num(input, english_number_multiple));
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
SCRIPT_RETURN(do_english_num(input, english_number_multiple));
|
||||
}
|
||||
SCRIPT_FUNCTION(english_number_ordinal) {
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
SCRIPT_RETURN(do_english_num(input, english_ordinal));
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
SCRIPT_RETURN(do_english_num(input, english_ordinal));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Singular/plural
|
||||
|
||||
String english_singular(const String& str) {
|
||||
if (str.size() > 3 && is_substr(str, str.size()-3, _("ies"))) {
|
||||
return str.substr(0, str.size() - 3) + _("y");
|
||||
} else if (str.size() > 3 && is_substr(str, str.size()-3, _("oes"))) {
|
||||
return str.substr(0, str.size() - 2);
|
||||
} else if (str.size() > 4 && is_substr(str, str.size()-4, _("ches"))) {
|
||||
return str.substr(0, str.size() - 2);
|
||||
} else if (str.size() > 4 && is_substr(str, str.size()-4, _("shes"))) {
|
||||
return str.substr(0, str.size() - 2);
|
||||
} else if (str.size() > 4 && is_substr(str, str.size()-4, _("sses"))) {
|
||||
return str.substr(0, str.size() - 2);
|
||||
} else if (str.size() > 5 && is_substr(str, str.size()-3, _("ves")) && (is_substr(str, str.size()-5, _("el")) || is_substr(str, str.size()-5, _("ar")) )) {
|
||||
return str.substr(0, str.size() - 3) + _("f");
|
||||
} else if (str.size() > 1 && str.GetChar(str.size() - 1) == _('s')) {
|
||||
return str.substr(0, str.size() - 1);
|
||||
} else if (str.size() >= 3 && is_substr(str, str.size()-3, _("men"))) {
|
||||
return str.substr(0, str.size() - 2) + _("an");
|
||||
} else {
|
||||
return str;
|
||||
}
|
||||
if (str.size() > 3 && is_substr(str, str.size()-3, _("ies"))) {
|
||||
return str.substr(0, str.size() - 3) + _("y");
|
||||
} else if (str.size() > 3 && is_substr(str, str.size()-3, _("oes"))) {
|
||||
return str.substr(0, str.size() - 2);
|
||||
} else if (str.size() > 4 && is_substr(str, str.size()-4, _("ches"))) {
|
||||
return str.substr(0, str.size() - 2);
|
||||
} else if (str.size() > 4 && is_substr(str, str.size()-4, _("shes"))) {
|
||||
return str.substr(0, str.size() - 2);
|
||||
} else if (str.size() > 4 && is_substr(str, str.size()-4, _("sses"))) {
|
||||
return str.substr(0, str.size() - 2);
|
||||
} else if (str.size() > 5 && is_substr(str, str.size()-3, _("ves")) && (is_substr(str, str.size()-5, _("el")) || is_substr(str, str.size()-5, _("ar")) )) {
|
||||
return str.substr(0, str.size() - 3) + _("f");
|
||||
} else if (str.size() > 1 && str.GetChar(str.size() - 1) == _('s')) {
|
||||
return str.substr(0, str.size() - 1);
|
||||
} else if (str.size() >= 3 && is_substr(str, str.size()-3, _("men"))) {
|
||||
return str.substr(0, str.size() - 2) + _("an");
|
||||
} else {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
String english_plural(const String& str) {
|
||||
if (str.size() > 2) {
|
||||
Char a = str.GetChar(str.size() - 2);
|
||||
Char b = str.GetChar(str.size() - 1);
|
||||
if (b == _('y') && is_constant(a)) {
|
||||
return str.substr(0, str.size() - 1) + _("ies");
|
||||
} else if (b == _('o') && is_constant(a)) {
|
||||
return str + _("es");
|
||||
} else if ((a == _('s') || a == _('c')) && b == _('h')) {
|
||||
return str + _("es");
|
||||
} else if (b == _('s')) {
|
||||
return str + _("es");
|
||||
} else {
|
||||
return str + _("s");
|
||||
}
|
||||
}
|
||||
return str + _("s");
|
||||
if (str.size() > 2) {
|
||||
Char a = str.GetChar(str.size() - 2);
|
||||
Char b = str.GetChar(str.size() - 1);
|
||||
if (b == _('y') && is_constant(a)) {
|
||||
return str.substr(0, str.size() - 1) + _("ies");
|
||||
} else if (b == _('o') && is_constant(a)) {
|
||||
return str + _("es");
|
||||
} else if ((a == _('s') || a == _('c')) && b == _('h')) {
|
||||
return str + _("es");
|
||||
} else if (b == _('s')) {
|
||||
return str + _("es");
|
||||
} else {
|
||||
return str + _("s");
|
||||
}
|
||||
}
|
||||
return str + _("s");
|
||||
}
|
||||
|
||||
// script_english_singular/plural/singplur
|
||||
String do_english(String input, String(*fun)(const String&)) {
|
||||
if (is_substr(input, 0, _("<param-"))) {
|
||||
// a keyword parameter, of the form "<param->123</param->"
|
||||
size_t start = skip_tag(input, 0);
|
||||
if (start != String::npos) {
|
||||
size_t end = input.find_first_of(_('<'), start);
|
||||
if (end != String::npos) {
|
||||
String is = input.substr(start, end - start);
|
||||
return substr_replace(input, start, end, fun(is));
|
||||
}
|
||||
}
|
||||
return input; // failed
|
||||
} else {
|
||||
return fun(input);
|
||||
}
|
||||
if (is_substr(input, 0, _("<param-"))) {
|
||||
// a keyword parameter, of the form "<param->123</param->"
|
||||
size_t start = skip_tag(input, 0);
|
||||
if (start != String::npos) {
|
||||
size_t end = input.find_first_of(_('<'), start);
|
||||
if (end != String::npos) {
|
||||
String is = input.substr(start, end - start);
|
||||
return substr_replace(input, start, end, fun(is));
|
||||
}
|
||||
}
|
||||
return input; // failed
|
||||
} else {
|
||||
return fun(input);
|
||||
}
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(english_singular) {
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
SCRIPT_RETURN(do_english(input, english_singular));
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
SCRIPT_RETURN(do_english(input, english_singular));
|
||||
}
|
||||
SCRIPT_FUNCTION(english_plural) {
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
SCRIPT_RETURN(do_english(input, english_plural));
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
SCRIPT_RETURN(do_english(input, english_plural));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Hints
|
||||
@@ -235,110 +235,110 @@ SCRIPT_FUNCTION(english_plural) {
|
||||
* Note: there is no close tags for hints
|
||||
*/
|
||||
String process_english_hints(const String& str) {
|
||||
String ret; ret.reserve(str.size());
|
||||
// have we seen a <hint-1/2>?
|
||||
// 1 for singular, 2 for plural
|
||||
int singplur = 0;
|
||||
for (size_t i = 0 ; i < str.size() ; ) {
|
||||
Char c = str.GetChar(i);
|
||||
if (is_substr(str, i, _("<hint-"))) {
|
||||
Char h = str.GetChar(i + 6); // hint code
|
||||
if (h == _('1')) {
|
||||
singplur = 1;
|
||||
} else if (h == _('2')) {
|
||||
singplur = 2;
|
||||
}
|
||||
i = skip_tag(str, i);
|
||||
} else if (is_substr(str, i, _("<param-"))) {
|
||||
size_t after = skip_tag(str, i);
|
||||
if (after != String::npos) {
|
||||
Char c = str.GetChar(after);
|
||||
if (singplur == 1 && is_substr(str, after, _("a</param-"))) {
|
||||
// a -> an, where the a originates from english_number_a(1)
|
||||
size_t after_end = skip_tag(str,after+1);
|
||||
if (after_end == String::npos) {
|
||||
throw Error(_("Incomplete </param> tag"));
|
||||
}
|
||||
if (after_end != String::npos && after_end + 1 < str.size()
|
||||
&& isSpace(str.GetChar(after_end)) && is_vowel(str.GetChar(after_end+1))) {
|
||||
ret.append(str,i,after-i);
|
||||
ret += _("an");
|
||||
i = after + 1;
|
||||
continue;
|
||||
}
|
||||
} else if (is_vowel(c) && ret.size() >= 2) {
|
||||
// a -> an?
|
||||
// is there "a" before this?
|
||||
String last = ret.substr(ret.size() - 2);
|
||||
if ( (ret.size() == 2 || !isAlpha(ret.GetChar(ret.size() - 3))) &&
|
||||
(last == _("a ") || last == _("A ")) ) {
|
||||
ret.insert(ret.size() - 1, _('n'));
|
||||
}
|
||||
} else if (is_substr(str, after, _("</param-")) && ret.size() >= 1 &&
|
||||
ret.GetChar(ret.size() - 1) == _(' ')) {
|
||||
// empty param, drop space before it
|
||||
ret.resize(ret.size() - 1);
|
||||
}
|
||||
}
|
||||
ret.append(str,i,min(after,str.size())-i);
|
||||
i = after;
|
||||
} else if (is_substr(str, i, _("<singular>"))) {
|
||||
// singular -> keep, plural -> drop
|
||||
size_t start = skip_tag(str, i);
|
||||
size_t end = match_close_tag(str, start);
|
||||
if (singplur == 1 && end != String::npos) {
|
||||
ret += str.substr(start, end - start);
|
||||
}
|
||||
singplur = 0;
|
||||
i = skip_tag(str, end);
|
||||
} else if (is_substr(str, i, _("<plural>"))) {
|
||||
// singular -> drop, plural -> keep
|
||||
size_t start = skip_tag(str, i);
|
||||
size_t end = match_close_tag(str, start);
|
||||
if (singplur == 2 && end != String::npos) {
|
||||
ret += str.substr(start, end - start);
|
||||
}
|
||||
singplur = 0;
|
||||
i = skip_tag(str, end);
|
||||
} else if (c == _('(') && singplur) {
|
||||
// singular -> drop (...), plural -> keep it
|
||||
size_t end = str.find_first_of(_(')'), i);
|
||||
if (end != String::npos) {
|
||||
if (singplur == 2) {
|
||||
ret += str.substr(i + 1, end - i - 1);
|
||||
}
|
||||
i = end + 1;
|
||||
} else { // handle like normal
|
||||
ret += c;
|
||||
++i;
|
||||
}
|
||||
singplur = 0;
|
||||
} else if (c == _('<')) {
|
||||
size_t after = skip_tag(str, i);
|
||||
ret.append(str,i,min(after,str.size())-i);
|
||||
i = after;
|
||||
} else {
|
||||
ret += c;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
String ret; ret.reserve(str.size());
|
||||
// have we seen a <hint-1/2>?
|
||||
// 1 for singular, 2 for plural
|
||||
int singplur = 0;
|
||||
for (size_t i = 0 ; i < str.size() ; ) {
|
||||
Char c = str.GetChar(i);
|
||||
if (is_substr(str, i, _("<hint-"))) {
|
||||
Char h = str.GetChar(i + 6); // hint code
|
||||
if (h == _('1')) {
|
||||
singplur = 1;
|
||||
} else if (h == _('2')) {
|
||||
singplur = 2;
|
||||
}
|
||||
i = skip_tag(str, i);
|
||||
} else if (is_substr(str, i, _("<param-"))) {
|
||||
size_t after = skip_tag(str, i);
|
||||
if (after != String::npos) {
|
||||
Char c = str.GetChar(after);
|
||||
if (singplur == 1 && is_substr(str, after, _("a</param-"))) {
|
||||
// a -> an, where the a originates from english_number_a(1)
|
||||
size_t after_end = skip_tag(str,after+1);
|
||||
if (after_end == String::npos) {
|
||||
throw Error(_("Incomplete </param> tag"));
|
||||
}
|
||||
if (after_end != String::npos && after_end + 1 < str.size()
|
||||
&& isSpace(str.GetChar(after_end)) && is_vowel(str.GetChar(after_end+1))) {
|
||||
ret.append(str,i,after-i);
|
||||
ret += _("an");
|
||||
i = after + 1;
|
||||
continue;
|
||||
}
|
||||
} else if (is_vowel(c) && ret.size() >= 2) {
|
||||
// a -> an?
|
||||
// is there "a" before this?
|
||||
String last = ret.substr(ret.size() - 2);
|
||||
if ( (ret.size() == 2 || !isAlpha(ret.GetChar(ret.size() - 3))) &&
|
||||
(last == _("a ") || last == _("A ")) ) {
|
||||
ret.insert(ret.size() - 1, _('n'));
|
||||
}
|
||||
} else if (is_substr(str, after, _("</param-")) && ret.size() >= 1 &&
|
||||
ret.GetChar(ret.size() - 1) == _(' ')) {
|
||||
// empty param, drop space before it
|
||||
ret.resize(ret.size() - 1);
|
||||
}
|
||||
}
|
||||
ret.append(str,i,min(after,str.size())-i);
|
||||
i = after;
|
||||
} else if (is_substr(str, i, _("<singular>"))) {
|
||||
// singular -> keep, plural -> drop
|
||||
size_t start = skip_tag(str, i);
|
||||
size_t end = match_close_tag(str, start);
|
||||
if (singplur == 1 && end != String::npos) {
|
||||
ret += str.substr(start, end - start);
|
||||
}
|
||||
singplur = 0;
|
||||
i = skip_tag(str, end);
|
||||
} else if (is_substr(str, i, _("<plural>"))) {
|
||||
// singular -> drop, plural -> keep
|
||||
size_t start = skip_tag(str, i);
|
||||
size_t end = match_close_tag(str, start);
|
||||
if (singplur == 2 && end != String::npos) {
|
||||
ret += str.substr(start, end - start);
|
||||
}
|
||||
singplur = 0;
|
||||
i = skip_tag(str, end);
|
||||
} else if (c == _('(') && singplur) {
|
||||
// singular -> drop (...), plural -> keep it
|
||||
size_t end = str.find_first_of(_(')'), i);
|
||||
if (end != String::npos) {
|
||||
if (singplur == 2) {
|
||||
ret += str.substr(i + 1, end - i - 1);
|
||||
}
|
||||
i = end + 1;
|
||||
} else { // handle like normal
|
||||
ret += c;
|
||||
++i;
|
||||
}
|
||||
singplur = 0;
|
||||
} else if (c == _('<')) {
|
||||
size_t after = skip_tag(str, i);
|
||||
ret.append(str,i,min(after,str.size())-i);
|
||||
i = after;
|
||||
} else {
|
||||
ret += c;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(process_english_hints) {
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
assert_tagged(input);
|
||||
SCRIPT_RETURN(process_english_hints(input));
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
assert_tagged(input);
|
||||
SCRIPT_RETURN(process_english_hints(input));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Init
|
||||
|
||||
void init_script_english_functions(Context& ctx) {
|
||||
ctx.setVariable(_("english number"), script_english_number);
|
||||
ctx.setVariable(_("english number a"), script_english_number_a);
|
||||
ctx.setVariable(_("english number multiple"), script_english_number_multiple);
|
||||
ctx.setVariable(_("english number ordinal"), script_english_number_ordinal);
|
||||
ctx.setVariable(_("english singular"), script_english_singular);
|
||||
ctx.setVariable(_("english plural"), script_english_plural);
|
||||
ctx.setVariable(_("process english hints"), script_process_english_hints);
|
||||
ctx.setVariable(_("english number"), script_english_number);
|
||||
ctx.setVariable(_("english number a"), script_english_number_a);
|
||||
ctx.setVariable(_("english number multiple"), script_english_number_multiple);
|
||||
ctx.setVariable(_("english number ordinal"), script_english_number_ordinal);
|
||||
ctx.setVariable(_("english singular"), script_english_singular);
|
||||
ctx.setVariable(_("english plural"), script_english_plural);
|
||||
ctx.setVariable(_("process english hints"), script_process_english_hints);
|
||||
}
|
||||
|
||||
+349
-349
@@ -27,65 +27,65 @@ DECLARE_TYPEOF_COLLECTION(SymbolFont::DrawableSymbol);
|
||||
|
||||
// Make sure we can export files to a data directory
|
||||
void guard_export_info(const String& fun, bool need_template = false) {
|
||||
if (!export_info() && (!need_template || export_info()->export_template)) {
|
||||
throw ScriptError(_("Can only use ") + fun + _(" from export templates"));
|
||||
} else if (export_info()->directory_relative.empty()) {
|
||||
throw ScriptError(_("Can only use ") + fun + _(" when 'create directory' is set to true"));
|
||||
}
|
||||
if (!export_info() && (!need_template || export_info()->export_template)) {
|
||||
throw ScriptError(_("Can only use ") + fun + _(" from export templates"));
|
||||
} else if (export_info()->directory_relative.empty()) {
|
||||
throw ScriptError(_("Can only use ") + fun + _(" when 'create directory' is set to true"));
|
||||
}
|
||||
}
|
||||
|
||||
/// Find an absolute filename for a relative filename from an export template,
|
||||
/// Returns the absolute filename, and may modify the relative name.
|
||||
String get_export_full_path(String& rel_name) {
|
||||
ExportInfo& ei = *export_info();
|
||||
// the absolute path
|
||||
wxFileName fn(rel_name);
|
||||
fn.Normalize(wxPATH_NORM_ALL, ei.directory_absolute);
|
||||
if (!ei.allow_writes_outside) {
|
||||
// check if path is okay
|
||||
wxFileName fn2(_("x"));
|
||||
fn2.SetPath(ei.directory_absolute);
|
||||
fn2.Normalize(wxPATH_NORM_ALL, ei.directory_absolute);
|
||||
String p1 = fn.GetFullPath();
|
||||
String p2 = fn2.GetFullPath();
|
||||
p2.resize(p2.size() - 1); // drop the x
|
||||
if (p2.empty() || p1.size() < p2.size() || p1.substr(0,p2.size()-1) != p2.substr(0,p2.size()-1)) {
|
||||
throw ScriptError(_("Not a relative filename: ") + rel_name);
|
||||
}
|
||||
}
|
||||
rel_name = fn.GetFullName();
|
||||
return fn.GetFullPath();
|
||||
ExportInfo& ei = *export_info();
|
||||
// the absolute path
|
||||
wxFileName fn(rel_name);
|
||||
fn.Normalize(wxPATH_NORM_ALL, ei.directory_absolute);
|
||||
if (!ei.allow_writes_outside) {
|
||||
// check if path is okay
|
||||
wxFileName fn2(_("x"));
|
||||
fn2.SetPath(ei.directory_absolute);
|
||||
fn2.Normalize(wxPATH_NORM_ALL, ei.directory_absolute);
|
||||
String p1 = fn.GetFullPath();
|
||||
String p2 = fn2.GetFullPath();
|
||||
p2.resize(p2.size() - 1); // drop the x
|
||||
if (p2.empty() || p1.size() < p2.size() || p1.substr(0,p2.size()-1) != p2.substr(0,p2.size()-1)) {
|
||||
throw ScriptError(_("Not a relative filename: ") + rel_name);
|
||||
}
|
||||
}
|
||||
rel_name = fn.GetFullName();
|
||||
return fn.GetFullPath();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : HTML
|
||||
|
||||
// An HTML tag
|
||||
struct Tag {
|
||||
Tag(const Char* open_tag, const Char* close_tag)
|
||||
: open_tag(open_tag), close_tag(close_tag), opened(0)
|
||||
{}
|
||||
const Char* open_tag; ///< The tags to insert in HTML "<tag>"
|
||||
const Char* close_tag; ///< The tags to insert in HTML "</tag>"
|
||||
int opened; ///< How often is the tag opened in the input?
|
||||
/// Write an open or close tag to a string if needed
|
||||
void write(String& ret, bool close) {
|
||||
if (close) {
|
||||
if (--opened == 0) {
|
||||
ret += close_tag;
|
||||
}
|
||||
} else {
|
||||
if (++opened == 1) {
|
||||
ret += open_tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
Tag(const Char* open_tag, const Char* close_tag)
|
||||
: open_tag(open_tag), close_tag(close_tag), opened(0)
|
||||
{}
|
||||
const Char* open_tag; ///< The tags to insert in HTML "<tag>"
|
||||
const Char* close_tag; ///< The tags to insert in HTML "</tag>"
|
||||
int opened; ///< How often is the tag opened in the input?
|
||||
/// Write an open or close tag to a string if needed
|
||||
void write(String& ret, bool close) {
|
||||
if (close) {
|
||||
if (--opened == 0) {
|
||||
ret += close_tag;
|
||||
}
|
||||
} else {
|
||||
if (++opened == 1) {
|
||||
ret += open_tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// A tag, or a close tag
|
||||
struct NegTag {
|
||||
Tag* tag;
|
||||
bool neg; // a close tag instead of an open tag
|
||||
NegTag(Tag* tag, bool neg) : tag(tag), neg(neg) {}
|
||||
Tag* tag;
|
||||
bool neg; // a close tag instead of an open tag
|
||||
NegTag(Tag* tag, bool neg) : tag(tag), neg(neg) {}
|
||||
};
|
||||
|
||||
DECLARE_TYPEOF_COLLECTION(NegTag);
|
||||
@@ -93,371 +93,371 @@ DECLARE_TYPEOF_COLLECTION(NegTag);
|
||||
/// A stack of opened HTML tags
|
||||
class TagStack {
|
||||
public:
|
||||
void open(String& ret, Tag& tag) {
|
||||
add(ret, NegTag(&tag, false));
|
||||
}
|
||||
void close(String& ret, Tag& tag) {
|
||||
add(ret, NegTag(&tag, true));
|
||||
}
|
||||
// Close all tags, should be called at end of input
|
||||
void close_all(String& ret) {
|
||||
// cancel out tags with pending tags
|
||||
write_pending_tags(ret);
|
||||
// close all open tags
|
||||
while (!tags.empty()) {
|
||||
tags.back()->write(ret, true);
|
||||
tags.pop_back();
|
||||
}
|
||||
}
|
||||
// Write all pending tags, should be called before non-tag output
|
||||
void write_pending_tags(String& ret) {
|
||||
FOR_EACH(t, pending_tags) {
|
||||
t.tag->write(ret, t.neg);
|
||||
if (!t.neg) tags.push_back(t.tag);
|
||||
}
|
||||
pending_tags.clear();
|
||||
}
|
||||
|
||||
void open(String& ret, Tag& tag) {
|
||||
add(ret, NegTag(&tag, false));
|
||||
}
|
||||
void close(String& ret, Tag& tag) {
|
||||
add(ret, NegTag(&tag, true));
|
||||
}
|
||||
// Close all tags, should be called at end of input
|
||||
void close_all(String& ret) {
|
||||
// cancel out tags with pending tags
|
||||
write_pending_tags(ret);
|
||||
// close all open tags
|
||||
while (!tags.empty()) {
|
||||
tags.back()->write(ret, true);
|
||||
tags.pop_back();
|
||||
}
|
||||
}
|
||||
// Write all pending tags, should be called before non-tag output
|
||||
void write_pending_tags(String& ret) {
|
||||
FOR_EACH(t, pending_tags) {
|
||||
t.tag->write(ret, t.neg);
|
||||
if (!t.neg) tags.push_back(t.tag);
|
||||
}
|
||||
pending_tags.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
vector<Tag*> tags; ///< Tags opened in the html output
|
||||
vector<NegTag> pending_tags; ///< Tags opened in the tagged string, but not (yet) in the output
|
||||
|
||||
void add(String& ret, const NegTag& tag) {
|
||||
// Cancel out with pending tag?
|
||||
for (int i = (int)pending_tags.size() - 1 ; i >= 0 ; --i) {
|
||||
if (pending_tags[i].tag == tag.tag) {
|
||||
if (pending_tags[i].neg != tag.neg) {
|
||||
pending_tags.erase(pending_tags.begin() + i);
|
||||
return;
|
||||
} else {
|
||||
break; // look no further
|
||||
}
|
||||
}
|
||||
}
|
||||
// Cancel out with existing tag?
|
||||
if (tag.neg) {
|
||||
for (int i = (int)tags.size() - 1 ; i >= 0 ; --i) {
|
||||
if (tags[i] == tag.tag) {
|
||||
// cancel out with existing tag i, e.g. <b>:
|
||||
// situation was <a><b><c>text
|
||||
// situation will become <a><b><c>text</c></b><c>
|
||||
vector<NegTag> reopen;
|
||||
for (int j = (int)tags.size() - 1 ; j > i ; --j) {
|
||||
pending_tags.push_back(NegTag(tags[j], true)); // close tag, top down
|
||||
tags.pop_back();
|
||||
}
|
||||
pending_tags.push_back(tag); // now close tag i
|
||||
for (int j = i + 1 ; j < (int)tags.size() ; ++j) {
|
||||
pending_tags.push_back(NegTag(tags[j], false)); // reopen later, bottom up
|
||||
tags.pop_back();
|
||||
}
|
||||
tags.resize(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Just insert normally
|
||||
pending_tags.push_back(tag);
|
||||
}
|
||||
vector<Tag*> tags; ///< Tags opened in the html output
|
||||
vector<NegTag> pending_tags; ///< Tags opened in the tagged string, but not (yet) in the output
|
||||
|
||||
void add(String& ret, const NegTag& tag) {
|
||||
// Cancel out with pending tag?
|
||||
for (int i = (int)pending_tags.size() - 1 ; i >= 0 ; --i) {
|
||||
if (pending_tags[i].tag == tag.tag) {
|
||||
if (pending_tags[i].neg != tag.neg) {
|
||||
pending_tags.erase(pending_tags.begin() + i);
|
||||
return;
|
||||
} else {
|
||||
break; // look no further
|
||||
}
|
||||
}
|
||||
}
|
||||
// Cancel out with existing tag?
|
||||
if (tag.neg) {
|
||||
for (int i = (int)tags.size() - 1 ; i >= 0 ; --i) {
|
||||
if (tags[i] == tag.tag) {
|
||||
// cancel out with existing tag i, e.g. <b>:
|
||||
// situation was <a><b><c>text
|
||||
// situation will become <a><b><c>text</c></b><c>
|
||||
vector<NegTag> reopen;
|
||||
for (int j = (int)tags.size() - 1 ; j > i ; --j) {
|
||||
pending_tags.push_back(NegTag(tags[j], true)); // close tag, top down
|
||||
tags.pop_back();
|
||||
}
|
||||
pending_tags.push_back(tag); // now close tag i
|
||||
for (int j = i + 1 ; j < (int)tags.size() ; ++j) {
|
||||
pending_tags.push_back(NegTag(tags[j], false)); // reopen later, bottom up
|
||||
tags.pop_back();
|
||||
}
|
||||
tags.resize(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Just insert normally
|
||||
pending_tags.push_back(tag);
|
||||
}
|
||||
};
|
||||
|
||||
// html-escape a string
|
||||
String html_escape(const String& str) {
|
||||
String ret;
|
||||
FOR_EACH_CONST(c, str) {
|
||||
if (c == _('\1') || c == _('<')) { // escape <
|
||||
ret += _("<");
|
||||
} else if (c == _('>')) { // escape >
|
||||
ret += _(">");
|
||||
} else if (c == _('&')) { // escape &
|
||||
ret += _("&");
|
||||
} else if (c == _('\'')) { // escape '
|
||||
ret += _("'");
|
||||
} else if (c == _('\"')) { // escape "
|
||||
ret += _(""");
|
||||
} else if (c >= 0x80) { // escape non ascii
|
||||
ret += String(_("&#")) << (int)c << _(';');
|
||||
} else {
|
||||
ret += c;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
String ret;
|
||||
FOR_EACH_CONST(c, str) {
|
||||
if (c == _('\1') || c == _('<')) { // escape <
|
||||
ret += _("<");
|
||||
} else if (c == _('>')) { // escape >
|
||||
ret += _(">");
|
||||
} else if (c == _('&')) { // escape &
|
||||
ret += _("&");
|
||||
} else if (c == _('\'')) { // escape '
|
||||
ret += _("'");
|
||||
} else if (c == _('\"')) { // escape "
|
||||
ret += _(""");
|
||||
} else if (c >= 0x80) { // escape non ascii
|
||||
ret += String(_("&#")) << (int)c << _(';');
|
||||
} else {
|
||||
ret += c;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// write symbols to html
|
||||
String symbols_to_html(const String& str, SymbolFont& symbol_font, double size) {
|
||||
guard_export_info(_("symbols_to_html"));
|
||||
ExportInfo& ei = *export_info();
|
||||
vector<SymbolFont::DrawableSymbol> symbols;
|
||||
symbol_font.split(str, symbols);
|
||||
String html;
|
||||
FOR_EACH(sym, symbols) {
|
||||
String filename = symbol_font.name() + _("-") + clean_filename(sym.text) + _(".png");
|
||||
map<String,wxSize>::iterator it = ei.exported_images.find(filename);
|
||||
if (it == ei.exported_images.end()) {
|
||||
// save symbol image
|
||||
Image img = symbol_font.getImage(size, sym);
|
||||
wxFileName fn;
|
||||
fn.SetPath(ei.directory_absolute);
|
||||
fn.SetFullName(filename);
|
||||
img.SaveFile(fn.GetFullPath());
|
||||
it = ei.exported_images.insert(make_pair(filename, wxSize(img.GetWidth(), img.GetHeight()))).first;
|
||||
}
|
||||
html += _("<img src='") + filename + _("' alt='") + html_escape(sym.text)
|
||||
+ _("' width='") + (String() << it->second.x)
|
||||
+ _("' height='") + (String() << it->second.y) + _("'>");
|
||||
}
|
||||
return html;
|
||||
guard_export_info(_("symbols_to_html"));
|
||||
ExportInfo& ei = *export_info();
|
||||
vector<SymbolFont::DrawableSymbol> symbols;
|
||||
symbol_font.split(str, symbols);
|
||||
String html;
|
||||
FOR_EACH(sym, symbols) {
|
||||
String filename = symbol_font.name() + _("-") + clean_filename(sym.text) + _(".png");
|
||||
map<String,wxSize>::iterator it = ei.exported_images.find(filename);
|
||||
if (it == ei.exported_images.end()) {
|
||||
// save symbol image
|
||||
Image img = symbol_font.getImage(size, sym);
|
||||
wxFileName fn;
|
||||
fn.SetPath(ei.directory_absolute);
|
||||
fn.SetFullName(filename);
|
||||
img.SaveFile(fn.GetFullPath());
|
||||
it = ei.exported_images.insert(make_pair(filename, wxSize(img.GetWidth(), img.GetHeight()))).first;
|
||||
}
|
||||
html += _("<img src='") + filename + _("' alt='") + html_escape(sym.text)
|
||||
+ _("' width='") + (String() << it->second.x)
|
||||
+ _("' height='") + (String() << it->second.y) + _("'>");
|
||||
}
|
||||
return html;
|
||||
}
|
||||
|
||||
String to_html(const String& str_in, const SymbolFontP& symbol_font, double symbol_size) {
|
||||
String str = remove_tag_contents(str_in,_("<sep-soft"));
|
||||
String ret;
|
||||
Tag bold (_("<b>"), _("</b>")),
|
||||
String str = remove_tag_contents(str_in,_("<sep-soft"));
|
||||
String ret;
|
||||
Tag bold (_("<b>"), _("</b>")),
|
||||
italic(_("<i>"), _("</i>")),
|
||||
symbol(_("<span class=\"symbol\">"), _("</span>"));
|
||||
TagStack tags;
|
||||
String symbols;
|
||||
for (size_t i = 0 ; i < str.size() ; ) {
|
||||
Char c = str.GetChar(i);
|
||||
if (c == _('<')) {
|
||||
++i;
|
||||
if (is_substr(str, i, _("b"))) {
|
||||
tags.open (ret, bold);
|
||||
} else if (is_substr(str, i, _("/b"))) {
|
||||
tags.close(ret, bold);
|
||||
} else if (is_substr(str, i, _("i"))) {
|
||||
tags.open (ret, italic);
|
||||
} else if (is_substr(str, i, _("/i"))) {
|
||||
tags.close(ret, italic);
|
||||
} else if (is_substr(str, i, _("sym"))) {
|
||||
tags.open (ret, symbol);
|
||||
} else if (is_substr(str, i, _("/sym"))) {
|
||||
if (!symbols.empty()) {
|
||||
// write symbols in a special way
|
||||
tags.write_pending_tags(ret);
|
||||
ret += symbols_to_html(symbols, *symbol_font, symbol_size);
|
||||
symbols.clear();
|
||||
}
|
||||
tags.close(ret, symbol);
|
||||
}
|
||||
i = skip_tag(str, i-1);
|
||||
} else {
|
||||
// normal character
|
||||
tags.write_pending_tags(ret);
|
||||
++i;
|
||||
if (symbol.opened > 0 && symbol_font) {
|
||||
symbols += c; // write as symbols instead
|
||||
} else {
|
||||
c = untag_char(c);
|
||||
if (c == _('<')) { // escape <
|
||||
ret += _("<");
|
||||
} else if (c == _('&')) { // escape &
|
||||
ret += _("&");
|
||||
} else if (c >= 0x80) { // escape non ascii
|
||||
ret += String(_("&#")) << (int)c << _(';');
|
||||
} else if (c == _('\n')) {
|
||||
ret += _("<br>\n");
|
||||
} else {
|
||||
ret += c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// end of input
|
||||
if (!symbols.empty()) {
|
||||
tags.write_pending_tags(ret);
|
||||
ret += symbols_to_html(symbols, *symbol_font, symbol_size);
|
||||
symbols.clear();
|
||||
}
|
||||
tags.close_all(ret);
|
||||
return ret;
|
||||
TagStack tags;
|
||||
String symbols;
|
||||
for (size_t i = 0 ; i < str.size() ; ) {
|
||||
Char c = str.GetChar(i);
|
||||
if (c == _('<')) {
|
||||
++i;
|
||||
if (is_substr(str, i, _("b"))) {
|
||||
tags.open (ret, bold);
|
||||
} else if (is_substr(str, i, _("/b"))) {
|
||||
tags.close(ret, bold);
|
||||
} else if (is_substr(str, i, _("i"))) {
|
||||
tags.open (ret, italic);
|
||||
} else if (is_substr(str, i, _("/i"))) {
|
||||
tags.close(ret, italic);
|
||||
} else if (is_substr(str, i, _("sym"))) {
|
||||
tags.open (ret, symbol);
|
||||
} else if (is_substr(str, i, _("/sym"))) {
|
||||
if (!symbols.empty()) {
|
||||
// write symbols in a special way
|
||||
tags.write_pending_tags(ret);
|
||||
ret += symbols_to_html(symbols, *symbol_font, symbol_size);
|
||||
symbols.clear();
|
||||
}
|
||||
tags.close(ret, symbol);
|
||||
}
|
||||
i = skip_tag(str, i-1);
|
||||
} else {
|
||||
// normal character
|
||||
tags.write_pending_tags(ret);
|
||||
++i;
|
||||
if (symbol.opened > 0 && symbol_font) {
|
||||
symbols += c; // write as symbols instead
|
||||
} else {
|
||||
c = untag_char(c);
|
||||
if (c == _('<')) { // escape <
|
||||
ret += _("<");
|
||||
} else if (c == _('&')) { // escape &
|
||||
ret += _("&");
|
||||
} else if (c >= 0x80) { // escape non ascii
|
||||
ret += String(_("&#")) << (int)c << _(';');
|
||||
} else if (c == _('\n')) {
|
||||
ret += _("<br>\n");
|
||||
} else {
|
||||
ret += c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// end of input
|
||||
if (!symbols.empty()) {
|
||||
tags.write_pending_tags(ret);
|
||||
ret += symbols_to_html(symbols, *symbol_font, symbol_size);
|
||||
symbols.clear();
|
||||
}
|
||||
tags.close_all(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// convert a tagged string to html
|
||||
SCRIPT_FUNCTION(to_html) {
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
// symbol font?
|
||||
SymbolFontP symbol_font;
|
||||
SCRIPT_OPTIONAL_PARAM_N(String, _("symbol font"), font_name) {
|
||||
symbol_font = SymbolFont::byName(font_name);
|
||||
symbol_font->update(ctx);
|
||||
}
|
||||
SCRIPT_OPTIONAL_PARAM_N_(double, _("symbol font size"), symbol_font_size);
|
||||
if (symbol_font_size <= 0) symbol_font_size = 12; // a default
|
||||
SCRIPT_RETURN(to_html(input, symbol_font, symbol_font_size));
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
// symbol font?
|
||||
SymbolFontP symbol_font;
|
||||
SCRIPT_OPTIONAL_PARAM_N(String, _("symbol font"), font_name) {
|
||||
symbol_font = SymbolFont::byName(font_name);
|
||||
symbol_font->update(ctx);
|
||||
}
|
||||
SCRIPT_OPTIONAL_PARAM_N_(double, _("symbol font size"), symbol_font_size);
|
||||
if (symbol_font_size <= 0) symbol_font_size = 12; // a default
|
||||
SCRIPT_RETURN(to_html(input, symbol_font, symbol_font_size));
|
||||
}
|
||||
|
||||
// convert a symbol string to html
|
||||
SCRIPT_FUNCTION(symbols_to_html) {
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
SCRIPT_PARAM_N(String, _("symbol font"), font_name);
|
||||
SCRIPT_OPTIONAL_PARAM_N_(double, _("symbol font size"), symbol_font_size);
|
||||
SymbolFontP symbol_font = SymbolFont::byName(font_name);
|
||||
symbol_font->update(ctx);
|
||||
if (symbol_font_size <= 0) symbol_font_size = 12; // a default
|
||||
SCRIPT_RETURN(symbols_to_html(input, *symbol_font, symbol_font_size));
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
SCRIPT_PARAM_N(String, _("symbol font"), font_name);
|
||||
SCRIPT_OPTIONAL_PARAM_N_(double, _("symbol font size"), symbol_font_size);
|
||||
SymbolFontP symbol_font = SymbolFont::byName(font_name);
|
||||
symbol_font->update(ctx);
|
||||
if (symbol_font_size <= 0) symbol_font_size = 12; // a default
|
||||
SCRIPT_RETURN(symbols_to_html(input, *symbol_font, symbol_font_size));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : BB Code
|
||||
|
||||
String to_bbcode(const String& str_in) {
|
||||
String str = remove_tag_contents(str_in,_("<sep-soft"));
|
||||
String ret;
|
||||
Tag bold (_("[b]"), _("[/b]")),
|
||||
String str = remove_tag_contents(str_in,_("<sep-soft"));
|
||||
String ret;
|
||||
Tag bold (_("[b]"), _("[/b]")),
|
||||
italic(_("[i]"), _("[/i]"));
|
||||
TagStack tags;
|
||||
String symbols;
|
||||
for (size_t i = 0 ; i < str.size() ; ) {
|
||||
Char c = str.GetChar(i);
|
||||
if (c == _('<')) {
|
||||
++i;
|
||||
if (is_substr(str, i, _("b"))) {
|
||||
tags.open (ret, bold);
|
||||
} else if (is_substr(str, i, _("/b"))) {
|
||||
tags.close(ret, bold);
|
||||
} else if (is_substr(str, i, _("i"))) {
|
||||
tags.open (ret, italic);
|
||||
} else if (is_substr(str, i, _("/i"))) {
|
||||
tags.close(ret, italic);
|
||||
} /*else if (is_substr(str, i, _("sym"))) {
|
||||
tags.open (ret, symbol);
|
||||
} else if (is_substr(str, i, _("/sym"))) {
|
||||
if (!symbols.empty()) {
|
||||
// write symbols in a special way
|
||||
tags.write_pending_tags(ret);
|
||||
ret += symbols_to_html(symbols, symbol_font);
|
||||
symbols.clear();
|
||||
}
|
||||
tags.close(ret, symbol);
|
||||
}*/
|
||||
i = skip_tag(str, i-1);
|
||||
} else {
|
||||
// normal character
|
||||
tags.write_pending_tags(ret);
|
||||
++i;
|
||||
// if (symbol.opened > 0 && symbol_font) {
|
||||
// symbols += c; // write as symbols instead
|
||||
// } else {
|
||||
ret += untag_char(c);
|
||||
// }
|
||||
}
|
||||
}
|
||||
// end of input
|
||||
/* if (!symbols.empty()) {
|
||||
tags.write_pending_tags(ret);
|
||||
ret += symbols_to_html(symbols, symbol_font);
|
||||
symbols.clear();
|
||||
}*/
|
||||
tags.close_all(ret);
|
||||
return ret;
|
||||
TagStack tags;
|
||||
String symbols;
|
||||
for (size_t i = 0 ; i < str.size() ; ) {
|
||||
Char c = str.GetChar(i);
|
||||
if (c == _('<')) {
|
||||
++i;
|
||||
if (is_substr(str, i, _("b"))) {
|
||||
tags.open (ret, bold);
|
||||
} else if (is_substr(str, i, _("/b"))) {
|
||||
tags.close(ret, bold);
|
||||
} else if (is_substr(str, i, _("i"))) {
|
||||
tags.open (ret, italic);
|
||||
} else if (is_substr(str, i, _("/i"))) {
|
||||
tags.close(ret, italic);
|
||||
} /*else if (is_substr(str, i, _("sym"))) {
|
||||
tags.open (ret, symbol);
|
||||
} else if (is_substr(str, i, _("/sym"))) {
|
||||
if (!symbols.empty()) {
|
||||
// write symbols in a special way
|
||||
tags.write_pending_tags(ret);
|
||||
ret += symbols_to_html(symbols, symbol_font);
|
||||
symbols.clear();
|
||||
}
|
||||
tags.close(ret, symbol);
|
||||
}*/
|
||||
i = skip_tag(str, i-1);
|
||||
} else {
|
||||
// normal character
|
||||
tags.write_pending_tags(ret);
|
||||
++i;
|
||||
// if (symbol.opened > 0 && symbol_font) {
|
||||
// symbols += c; // write as symbols instead
|
||||
// } else {
|
||||
ret += untag_char(c);
|
||||
// }
|
||||
}
|
||||
}
|
||||
// end of input
|
||||
/* if (!symbols.empty()) {
|
||||
tags.write_pending_tags(ret);
|
||||
ret += symbols_to_html(symbols, symbol_font);
|
||||
symbols.clear();
|
||||
}*/
|
||||
tags.close_all(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// convert a tagged string to BBCode
|
||||
SCRIPT_FUNCTION(to_bbcode) {
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
throw "TODO";
|
||||
// SCRIPT_RETURN(to_bbcode(input, symbol_font));
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
throw "TODO";
|
||||
// SCRIPT_RETURN(to_bbcode(input, symbol_font));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Text
|
||||
|
||||
// convert a tagged string to plain text
|
||||
SCRIPT_FUNCTION(to_text) {
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
SCRIPT_RETURN(untag_hide_sep(input));
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
SCRIPT_RETURN(untag_hide_sep(input));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Files
|
||||
|
||||
// copy from source package -> destination directory, return new filename (relative)
|
||||
SCRIPT_FUNCTION(copy_file) {
|
||||
guard_export_info(_("copy_file"));
|
||||
SCRIPT_PARAM_C(String, input); // file to copy
|
||||
// output path
|
||||
String out_name = input;
|
||||
String out_path = get_export_full_path(out_name);
|
||||
// copy
|
||||
ExportInfo& ei = *export_info();
|
||||
InputStreamP in = ei.export_template->openIn(input);
|
||||
wxFileOutputStream out(out_path);
|
||||
if (!out.Ok()) throw Error(_("Unable to open file '") + out_path + _("' for output"));
|
||||
out.Write(*in);
|
||||
SCRIPT_RETURN(out_name);
|
||||
guard_export_info(_("copy_file"));
|
||||
SCRIPT_PARAM_C(String, input); // file to copy
|
||||
// output path
|
||||
String out_name = input;
|
||||
String out_path = get_export_full_path(out_name);
|
||||
// copy
|
||||
ExportInfo& ei = *export_info();
|
||||
InputStreamP in = ei.export_template->openIn(input);
|
||||
wxFileOutputStream out(out_path);
|
||||
if (!out.Ok()) throw Error(_("Unable to open file '") + out_path + _("' for output"));
|
||||
out.Write(*in);
|
||||
SCRIPT_RETURN(out_name);
|
||||
}
|
||||
|
||||
// write a file to the destination directory
|
||||
SCRIPT_FUNCTION(write_text_file) {
|
||||
guard_export_info(_("write_text_file"));
|
||||
SCRIPT_PARAM_C(String, input); // text to write
|
||||
SCRIPT_PARAM(String, file); // file to write to
|
||||
// output path
|
||||
String out_path = get_export_full_path(file);
|
||||
// write
|
||||
wxFileOutputStream out(out_path);
|
||||
if (!out.Ok()) throw Error(_("Unable to open file '") + out_path + _("' for output"));
|
||||
wxTextOutputStream tout(out);
|
||||
tout.WriteString(BYTE_ORDER_MARK);
|
||||
tout.WriteString(input);
|
||||
SCRIPT_RETURN(file);
|
||||
guard_export_info(_("write_text_file"));
|
||||
SCRIPT_PARAM_C(String, input); // text to write
|
||||
SCRIPT_PARAM(String, file); // file to write to
|
||||
// output path
|
||||
String out_path = get_export_full_path(file);
|
||||
// write
|
||||
wxFileOutputStream out(out_path);
|
||||
if (!out.Ok()) throw Error(_("Unable to open file '") + out_path + _("' for output"));
|
||||
wxTextOutputStream tout(out);
|
||||
tout.WriteString(BYTE_ORDER_MARK);
|
||||
tout.WriteString(input);
|
||||
SCRIPT_RETURN(file);
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(write_image_file) {
|
||||
guard_export_info(_("write_image_file"));
|
||||
// output path
|
||||
SCRIPT_PARAM(String, file); // file to write to
|
||||
String out_path = get_export_full_path(file);
|
||||
// duplicates?
|
||||
ExportInfo& ei = *export_info();
|
||||
if (ei.exported_images.find(file) != ei.exported_images.end()) {
|
||||
SCRIPT_RETURN(file); // already written an image with this name
|
||||
}
|
||||
// get image
|
||||
SCRIPT_PARAM_C(ScriptValueP, input);
|
||||
SCRIPT_OPTIONAL_PARAM_(int, width);
|
||||
SCRIPT_OPTIONAL_PARAM_(int, height);
|
||||
ScriptObject<CardP>* card = dynamic_cast<ScriptObject<CardP>*>(input.get()); // is it a card?
|
||||
Image image;
|
||||
GeneratedImage::Options options(width, height, ei.export_template.get(), ei.set.get());
|
||||
if (card) {
|
||||
image = conform_image(export_bitmap(ei.set, card->getValue()).ConvertToImage(), options);
|
||||
} else {
|
||||
image = image_from_script(input)->generateConform(options);
|
||||
}
|
||||
if (!image.Ok()) throw Error(_("Unable to generate image for file ") + file);
|
||||
// write
|
||||
image.SaveFile(out_path);
|
||||
ei.exported_images.insert(make_pair(file, wxSize(image.GetWidth(), image.GetHeight())));
|
||||
SCRIPT_RETURN(file);
|
||||
guard_export_info(_("write_image_file"));
|
||||
// output path
|
||||
SCRIPT_PARAM(String, file); // file to write to
|
||||
String out_path = get_export_full_path(file);
|
||||
// duplicates?
|
||||
ExportInfo& ei = *export_info();
|
||||
if (ei.exported_images.find(file) != ei.exported_images.end()) {
|
||||
SCRIPT_RETURN(file); // already written an image with this name
|
||||
}
|
||||
// get image
|
||||
SCRIPT_PARAM_C(ScriptValueP, input);
|
||||
SCRIPT_OPTIONAL_PARAM_(int, width);
|
||||
SCRIPT_OPTIONAL_PARAM_(int, height);
|
||||
ScriptObject<CardP>* card = dynamic_cast<ScriptObject<CardP>*>(input.get()); // is it a card?
|
||||
Image image;
|
||||
GeneratedImage::Options options(width, height, ei.export_template.get(), ei.set.get());
|
||||
if (card) {
|
||||
image = conform_image(export_bitmap(ei.set, card->getValue()).ConvertToImage(), options);
|
||||
} else {
|
||||
image = image_from_script(input)->generateConform(options);
|
||||
}
|
||||
if (!image.Ok()) throw Error(_("Unable to generate image for file ") + file);
|
||||
// write
|
||||
image.SaveFile(out_path);
|
||||
ei.exported_images.insert(make_pair(file, wxSize(image.GetWidth(), image.GetHeight())));
|
||||
SCRIPT_RETURN(file);
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(write_set_file) {
|
||||
guard_export_info(_("write_set_file"));
|
||||
// output path
|
||||
SCRIPT_PARAM(String, file); // file to write to
|
||||
String out_path = get_export_full_path(file);
|
||||
// export
|
||||
SCRIPT_PARAM_C(Set*, set);
|
||||
set->saveCopy(out_path); // TODO: use export_set instead?
|
||||
SCRIPT_RETURN(file);
|
||||
|
||||
guard_export_info(_("write_set_file"));
|
||||
// output path
|
||||
SCRIPT_PARAM(String, file); // file to write to
|
||||
String out_path = get_export_full_path(file);
|
||||
// export
|
||||
SCRIPT_PARAM_C(Set*, set);
|
||||
set->saveCopy(out_path); // TODO: use export_set instead?
|
||||
SCRIPT_RETURN(file);
|
||||
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(sanitize) {
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
//TODO
|
||||
SCRIPT_RETURN(input);
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
//TODO
|
||||
SCRIPT_RETURN(input);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Init
|
||||
|
||||
void init_script_export_functions(Context& ctx) {
|
||||
ctx.setVariable(_("to html"), script_to_html);
|
||||
ctx.setVariable(_("symbols to html"), script_symbols_to_html);
|
||||
ctx.setVariable(_("to text"), script_to_text);
|
||||
ctx.setVariable(_("copy file"), script_copy_file);
|
||||
ctx.setVariable(_("write text file"), script_write_text_file);
|
||||
ctx.setVariable(_("write image file"), script_write_image_file);
|
||||
ctx.setVariable(_("write set file"), script_write_set_file);
|
||||
ctx.setVariable(_("sanitize"), script_sanitize);
|
||||
ctx.setVariable(_("to html"), script_to_html);
|
||||
ctx.setVariable(_("symbols to html"), script_symbols_to_html);
|
||||
ctx.setVariable(_("to text"), script_to_text);
|
||||
ctx.setVariable(_("copy file"), script_copy_file);
|
||||
ctx.setVariable(_("write text file"), script_write_text_file);
|
||||
ctx.setVariable(_("write image file"), script_write_image_file);
|
||||
ctx.setVariable(_("write set file"), script_write_set_file);
|
||||
ctx.setVariable(_("sanitize"), script_sanitize);
|
||||
}
|
||||
|
||||
@@ -31,14 +31,14 @@ void init_script_construction_functions(Context& ctx);
|
||||
|
||||
/// Initialize all built in functions for a context
|
||||
inline void init_script_functions(Context& ctx) {
|
||||
init_script_basic_functions(ctx);
|
||||
init_script_regex_functions(ctx);
|
||||
init_script_image_functions(ctx);
|
||||
init_script_editor_functions(ctx);
|
||||
init_script_export_functions(ctx);
|
||||
init_script_english_functions(ctx);
|
||||
init_script_spelling_functions(ctx);
|
||||
init_script_construction_functions(ctx);
|
||||
init_script_basic_functions(ctx);
|
||||
init_script_regex_functions(ctx);
|
||||
init_script_image_functions(ctx);
|
||||
init_script_editor_functions(ctx);
|
||||
init_script_export_functions(ctx);
|
||||
init_script_english_functions(ctx);
|
||||
init_script_spelling_functions(ctx);
|
||||
init_script_construction_functions(ctx);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
|
||||
+147
-147
@@ -26,212 +26,212 @@ void parse_enum(const String&, ImageCombine& out);
|
||||
// ----------------------------------------------------------------------------- : Utility
|
||||
|
||||
template <> inline GeneratedImageP from_script<GeneratedImageP>(const ScriptValueP& value) {
|
||||
return image_from_script(value);
|
||||
return image_from_script(value);
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(to_image) {
|
||||
SCRIPT_PARAM_C(GeneratedImageP, input);
|
||||
return input;
|
||||
SCRIPT_PARAM_C(GeneratedImageP, input);
|
||||
return input;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Image functions
|
||||
|
||||
SCRIPT_FUNCTION(linear_blend) {
|
||||
SCRIPT_PARAM(GeneratedImageP, image1);
|
||||
SCRIPT_PARAM(GeneratedImageP, image2);
|
||||
SCRIPT_PARAM(double, x1); SCRIPT_PARAM(double, y1);
|
||||
SCRIPT_PARAM(double, x2); SCRIPT_PARAM(double, y2);
|
||||
return intrusive(new LinearBlendImage(image1, image2, x1,y1, x2,y2));
|
||||
SCRIPT_PARAM(GeneratedImageP, image1);
|
||||
SCRIPT_PARAM(GeneratedImageP, image2);
|
||||
SCRIPT_PARAM(double, x1); SCRIPT_PARAM(double, y1);
|
||||
SCRIPT_PARAM(double, x2); SCRIPT_PARAM(double, y2);
|
||||
return intrusive(new LinearBlendImage(image1, image2, x1,y1, x2,y2));
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(masked_blend) {
|
||||
SCRIPT_PARAM(GeneratedImageP, light);
|
||||
SCRIPT_PARAM(GeneratedImageP, dark);
|
||||
SCRIPT_PARAM(GeneratedImageP, mask);
|
||||
return intrusive(new MaskedBlendImage(light, dark, mask));
|
||||
SCRIPT_PARAM(GeneratedImageP, light);
|
||||
SCRIPT_PARAM(GeneratedImageP, dark);
|
||||
SCRIPT_PARAM(GeneratedImageP, mask);
|
||||
return intrusive(new MaskedBlendImage(light, dark, mask));
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(combine_blend) {
|
||||
SCRIPT_PARAM(String, combine);
|
||||
SCRIPT_PARAM(GeneratedImageP, image1);
|
||||
SCRIPT_PARAM(GeneratedImageP, image2);
|
||||
ImageCombine image_combine;
|
||||
parse_enum(combine, image_combine);
|
||||
return intrusive(new CombineBlendImage(image1, image2, image_combine));
|
||||
SCRIPT_PARAM(String, combine);
|
||||
SCRIPT_PARAM(GeneratedImageP, image1);
|
||||
SCRIPT_PARAM(GeneratedImageP, image2);
|
||||
ImageCombine image_combine;
|
||||
parse_enum(combine, image_combine);
|
||||
return intrusive(new CombineBlendImage(image1, image2, image_combine));
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(set_mask) {
|
||||
SCRIPT_PARAM(GeneratedImageP, image);
|
||||
SCRIPT_PARAM(GeneratedImageP, mask);
|
||||
return intrusive(new SetMaskImage(image, mask));
|
||||
SCRIPT_PARAM(GeneratedImageP, image);
|
||||
SCRIPT_PARAM(GeneratedImageP, mask);
|
||||
return intrusive(new SetMaskImage(image, mask));
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(set_alpha) {
|
||||
SCRIPT_PARAM_C(GeneratedImageP, input);
|
||||
SCRIPT_PARAM(double, alpha);
|
||||
return intrusive(new SetAlphaImage(input, alpha));
|
||||
SCRIPT_PARAM_C(GeneratedImageP, input);
|
||||
SCRIPT_PARAM(double, alpha);
|
||||
return intrusive(new SetAlphaImage(input, alpha));
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(set_combine) {
|
||||
SCRIPT_PARAM(String, combine);
|
||||
SCRIPT_PARAM_C(GeneratedImageP, input);
|
||||
ImageCombine image_combine;
|
||||
parse_enum(combine, image_combine);
|
||||
return intrusive(new SetCombineImage(input, image_combine));
|
||||
SCRIPT_PARAM(String, combine);
|
||||
SCRIPT_PARAM_C(GeneratedImageP, input);
|
||||
ImageCombine image_combine;
|
||||
parse_enum(combine, image_combine);
|
||||
return intrusive(new SetCombineImage(input, image_combine));
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(saturate) {
|
||||
SCRIPT_PARAM_C(GeneratedImageP, input);
|
||||
SCRIPT_PARAM(double, amount);
|
||||
return intrusive(new SaturateImage(input, amount));
|
||||
SCRIPT_PARAM_C(GeneratedImageP, input);
|
||||
SCRIPT_PARAM(double, amount);
|
||||
return intrusive(new SaturateImage(input, amount));
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(invert_image) {
|
||||
SCRIPT_PARAM_C(GeneratedImageP, input);
|
||||
return intrusive(new InvertImage(input));
|
||||
SCRIPT_PARAM_C(GeneratedImageP, input);
|
||||
return intrusive(new InvertImage(input));
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(recolor_image) {
|
||||
SCRIPT_PARAM_C(GeneratedImageP, input);
|
||||
SCRIPT_OPTIONAL_PARAM(Color, red) {
|
||||
SCRIPT_PARAM(Color, green);
|
||||
SCRIPT_PARAM(Color, blue);
|
||||
SCRIPT_PARAM_DEFAULT(Color, white, *wxWHITE);
|
||||
return intrusive(new RecolorImage2(input,red,green,blue,white));
|
||||
} else {
|
||||
SCRIPT_PARAM(Color, color);
|
||||
return intrusive(new RecolorImage(input,color));
|
||||
}
|
||||
SCRIPT_PARAM_C(GeneratedImageP, input);
|
||||
SCRIPT_OPTIONAL_PARAM(Color, red) {
|
||||
SCRIPT_PARAM(Color, green);
|
||||
SCRIPT_PARAM(Color, blue);
|
||||
SCRIPT_PARAM_DEFAULT(Color, white, *wxWHITE);
|
||||
return intrusive(new RecolorImage2(input,red,green,blue,white));
|
||||
} else {
|
||||
SCRIPT_PARAM(Color, color);
|
||||
return intrusive(new RecolorImage(input,color));
|
||||
}
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(enlarge) {
|
||||
SCRIPT_PARAM_C(GeneratedImageP, input);
|
||||
SCRIPT_PARAM_N(double, _("border size"), border_size);
|
||||
return intrusive(new EnlargeImage(input, border_size));
|
||||
SCRIPT_PARAM_C(GeneratedImageP, input);
|
||||
SCRIPT_PARAM_N(double, _("border size"), border_size);
|
||||
return intrusive(new EnlargeImage(input, border_size));
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(crop) {
|
||||
SCRIPT_PARAM_C(GeneratedImageP, input);
|
||||
SCRIPT_PARAM_N(int, _("width"), width);
|
||||
SCRIPT_PARAM_N(int, _("height"), height);
|
||||
SCRIPT_PARAM_N(double, _("offset x"), offset_x);
|
||||
SCRIPT_PARAM_N(double, _("offset y"), offset_y);
|
||||
return intrusive(new CropImage(input, width, height, offset_x, offset_y));
|
||||
SCRIPT_PARAM_C(GeneratedImageP, input);
|
||||
SCRIPT_PARAM_N(int, _("width"), width);
|
||||
SCRIPT_PARAM_N(int, _("height"), height);
|
||||
SCRIPT_PARAM_N(double, _("offset x"), offset_x);
|
||||
SCRIPT_PARAM_N(double, _("offset y"), offset_y);
|
||||
return intrusive(new CropImage(input, width, height, offset_x, offset_y));
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(flip_horizontal) {
|
||||
SCRIPT_PARAM_C(GeneratedImageP, input);
|
||||
return intrusive(new FlipImageHorizontal(input));
|
||||
SCRIPT_PARAM_C(GeneratedImageP, input);
|
||||
return intrusive(new FlipImageHorizontal(input));
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(flip_vertical) {
|
||||
SCRIPT_PARAM_C(GeneratedImageP, input);
|
||||
return intrusive(new FlipImageVertical(input));
|
||||
SCRIPT_PARAM_C(GeneratedImageP, input);
|
||||
return intrusive(new FlipImageVertical(input));
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(rotate) {
|
||||
SCRIPT_PARAM_C(GeneratedImageP, input);
|
||||
SCRIPT_PARAM_N(Degrees, _("angle"), angle);
|
||||
return intrusive(new RotateImage(input,deg_to_rad(angle)));
|
||||
SCRIPT_PARAM_C(GeneratedImageP, input);
|
||||
SCRIPT_PARAM_N(Degrees, _("angle"), angle);
|
||||
return intrusive(new RotateImage(input,deg_to_rad(angle)));
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(drop_shadow) {
|
||||
SCRIPT_PARAM_C(GeneratedImageP, input);
|
||||
SCRIPT_OPTIONAL_PARAM_N_(double, _("offset x"), offset_x);
|
||||
SCRIPT_OPTIONAL_PARAM_N_(double, _("offset y"), offset_y);
|
||||
SCRIPT_OPTIONAL_PARAM_N_(double, _("alpha"), alpha);
|
||||
SCRIPT_OPTIONAL_PARAM_N_(double, _("blur radius"), blur_radius);
|
||||
SCRIPT_OPTIONAL_PARAM_N_(Color, _("color"), color);
|
||||
return intrusive(new DropShadowImage(input, offset_x, offset_y, alpha, blur_radius, color));
|
||||
SCRIPT_PARAM_C(GeneratedImageP, input);
|
||||
SCRIPT_OPTIONAL_PARAM_N_(double, _("offset x"), offset_x);
|
||||
SCRIPT_OPTIONAL_PARAM_N_(double, _("offset y"), offset_y);
|
||||
SCRIPT_OPTIONAL_PARAM_N_(double, _("alpha"), alpha);
|
||||
SCRIPT_OPTIONAL_PARAM_N_(double, _("blur radius"), blur_radius);
|
||||
SCRIPT_OPTIONAL_PARAM_N_(Color, _("color"), color);
|
||||
return intrusive(new DropShadowImage(input, offset_x, offset_y, alpha, blur_radius, color));
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(symbol_variation) {
|
||||
// find symbol
|
||||
SCRIPT_PARAM(ScriptValueP, symbol); // TODO: change to input?
|
||||
ScriptObject<ValueP>* valueO = dynamic_cast<ScriptObject<ValueP>*>(symbol.get());
|
||||
SymbolValue* value = valueO ? dynamic_cast<SymbolValue*>(valueO->getValue().get()) : nullptr;
|
||||
String filename;
|
||||
if (value) {
|
||||
filename = value->filename;
|
||||
} else if (valueO) {
|
||||
throw ScriptErrorConversion(valueO->typeName(), _TYPE_("symbol" ));
|
||||
} else {
|
||||
filename = from_script<String>(symbol);
|
||||
}
|
||||
// known variation?
|
||||
SCRIPT_OPTIONAL_PARAM_(String, variation)
|
||||
if (value && variation_) {
|
||||
// find style
|
||||
SCRIPT_PARAM(Set*, set);
|
||||
SCRIPT_OPTIONAL_PARAM_(CardP, card);
|
||||
SymbolStyleP style = dynamic_pointer_cast<SymbolStyle>(set->stylesheetForP(card)->styleFor(value->fieldP));
|
||||
if (!style) throw InternalError(_("Symbol value has a style of the wrong type"));
|
||||
// find variation
|
||||
FOR_EACH(v, style->variations) {
|
||||
if (v->name == variation) {
|
||||
// found it
|
||||
return intrusive(new SymbolToImage(value, filename, value->last_update, v));
|
||||
}
|
||||
}
|
||||
throw ScriptError(_("Variation of symbol not found ('") + variation + _("')"));
|
||||
} else {
|
||||
// custom variation
|
||||
SCRIPT_PARAM_N(double, _("border radius"), border_radius);
|
||||
SCRIPT_OPTIONAL_PARAM_N_(String, _("fill type"), fill_type);
|
||||
SymbolVariationP var(new SymbolVariation);
|
||||
var->border_radius = border_radius;
|
||||
if (fill_type == _("solid") || fill_type.empty()) {
|
||||
SCRIPT_PARAM_N(Color, _("fill color"), fill_color);
|
||||
SCRIPT_PARAM_N(Color, _("border color"), border_color);
|
||||
var->filter = intrusive(new SolidFillSymbolFilter(fill_color, border_color));
|
||||
} else if (fill_type == _("linear gradient")) {
|
||||
SCRIPT_PARAM_N(Color, _("fill color 1"), fill_color_1);
|
||||
SCRIPT_PARAM_N(Color, _("border color 1"), border_color_1);
|
||||
SCRIPT_PARAM_N(Color, _("fill color 2"), fill_color_2);
|
||||
SCRIPT_PARAM_N(Color, _("border color 2"), border_color_2);
|
||||
SCRIPT_PARAM_N(double, _("center x"), center_x);
|
||||
SCRIPT_PARAM_N(double, _("center y"), center_y);
|
||||
SCRIPT_PARAM_N(double, _("end x"), end_x);
|
||||
SCRIPT_PARAM_N(double, _("end y"), end_y);
|
||||
var->filter = intrusive(new LinearGradientSymbolFilter(fill_color_1, border_color_1, fill_color_2, border_color_2
|
||||
,center_x, center_y, end_x, end_y));
|
||||
} else if (fill_type == _("radial gradient")) {
|
||||
SCRIPT_PARAM_N(Color, _("fill color 1"), fill_color_1);
|
||||
SCRIPT_PARAM_N(Color, _("border color 1"), border_color_1);
|
||||
SCRIPT_PARAM_N(Color, _("fill color 2"), fill_color_2);
|
||||
SCRIPT_PARAM_N(Color, _("border color 2"), border_color_2);
|
||||
var->filter = intrusive(new RadialGradientSymbolFilter(fill_color_1, border_color_1, fill_color_2, border_color_2));
|
||||
} else {
|
||||
throw ScriptError(_("Unknown fill type for symbol_variation: ") + fill_type);
|
||||
}
|
||||
return intrusive(new SymbolToImage(value, filename, value ? value->last_update : Age(0), var));
|
||||
}
|
||||
// find symbol
|
||||
SCRIPT_PARAM(ScriptValueP, symbol); // TODO: change to input?
|
||||
ScriptObject<ValueP>* valueO = dynamic_cast<ScriptObject<ValueP>*>(symbol.get());
|
||||
SymbolValue* value = valueO ? dynamic_cast<SymbolValue*>(valueO->getValue().get()) : nullptr;
|
||||
String filename;
|
||||
if (value) {
|
||||
filename = value->filename;
|
||||
} else if (valueO) {
|
||||
throw ScriptErrorConversion(valueO->typeName(), _TYPE_("symbol" ));
|
||||
} else {
|
||||
filename = from_script<String>(symbol);
|
||||
}
|
||||
// known variation?
|
||||
SCRIPT_OPTIONAL_PARAM_(String, variation)
|
||||
if (value && variation_) {
|
||||
// find style
|
||||
SCRIPT_PARAM(Set*, set);
|
||||
SCRIPT_OPTIONAL_PARAM_(CardP, card);
|
||||
SymbolStyleP style = dynamic_pointer_cast<SymbolStyle>(set->stylesheetForP(card)->styleFor(value->fieldP));
|
||||
if (!style) throw InternalError(_("Symbol value has a style of the wrong type"));
|
||||
// find variation
|
||||
FOR_EACH(v, style->variations) {
|
||||
if (v->name == variation) {
|
||||
// found it
|
||||
return intrusive(new SymbolToImage(value, filename, value->last_update, v));
|
||||
}
|
||||
}
|
||||
throw ScriptError(_("Variation of symbol not found ('") + variation + _("')"));
|
||||
} else {
|
||||
// custom variation
|
||||
SCRIPT_PARAM_N(double, _("border radius"), border_radius);
|
||||
SCRIPT_OPTIONAL_PARAM_N_(String, _("fill type"), fill_type);
|
||||
SymbolVariationP var(new SymbolVariation);
|
||||
var->border_radius = border_radius;
|
||||
if (fill_type == _("solid") || fill_type.empty()) {
|
||||
SCRIPT_PARAM_N(Color, _("fill color"), fill_color);
|
||||
SCRIPT_PARAM_N(Color, _("border color"), border_color);
|
||||
var->filter = intrusive(new SolidFillSymbolFilter(fill_color, border_color));
|
||||
} else if (fill_type == _("linear gradient")) {
|
||||
SCRIPT_PARAM_N(Color, _("fill color 1"), fill_color_1);
|
||||
SCRIPT_PARAM_N(Color, _("border color 1"), border_color_1);
|
||||
SCRIPT_PARAM_N(Color, _("fill color 2"), fill_color_2);
|
||||
SCRIPT_PARAM_N(Color, _("border color 2"), border_color_2);
|
||||
SCRIPT_PARAM_N(double, _("center x"), center_x);
|
||||
SCRIPT_PARAM_N(double, _("center y"), center_y);
|
||||
SCRIPT_PARAM_N(double, _("end x"), end_x);
|
||||
SCRIPT_PARAM_N(double, _("end y"), end_y);
|
||||
var->filter = intrusive(new LinearGradientSymbolFilter(fill_color_1, border_color_1, fill_color_2, border_color_2
|
||||
,center_x, center_y, end_x, end_y));
|
||||
} else if (fill_type == _("radial gradient")) {
|
||||
SCRIPT_PARAM_N(Color, _("fill color 1"), fill_color_1);
|
||||
SCRIPT_PARAM_N(Color, _("border color 1"), border_color_1);
|
||||
SCRIPT_PARAM_N(Color, _("fill color 2"), fill_color_2);
|
||||
SCRIPT_PARAM_N(Color, _("border color 2"), border_color_2);
|
||||
var->filter = intrusive(new RadialGradientSymbolFilter(fill_color_1, border_color_1, fill_color_2, border_color_2));
|
||||
} else {
|
||||
throw ScriptError(_("Unknown fill type for symbol_variation: ") + fill_type);
|
||||
}
|
||||
return intrusive(new SymbolToImage(value, filename, value ? value->last_update : Age(0), var));
|
||||
}
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(built_in_image) {
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
return intrusive(new BuiltInImage(input));
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
return intrusive(new BuiltInImage(input));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Init
|
||||
|
||||
void init_script_image_functions(Context& ctx) {
|
||||
ctx.setVariable(_("to image"), script_to_image);
|
||||
ctx.setVariable(_("linear blend"), script_linear_blend);
|
||||
ctx.setVariable(_("masked blend"), script_masked_blend);
|
||||
ctx.setVariable(_("combine blend"), script_combine_blend);
|
||||
ctx.setVariable(_("set mask"), script_set_mask);
|
||||
ctx.setVariable(_("set alpha"), script_set_alpha);
|
||||
ctx.setVariable(_("set combine"), script_set_combine);
|
||||
ctx.setVariable(_("saturate"), script_saturate);
|
||||
ctx.setVariable(_("invert image"), script_invert_image);
|
||||
ctx.setVariable(_("recolor image"), script_recolor_image);
|
||||
ctx.setVariable(_("enlarge"), script_enlarge);
|
||||
ctx.setVariable(_("crop"), script_crop);
|
||||
ctx.setVariable(_("flip horizontal"), script_flip_horizontal);
|
||||
ctx.setVariable(_("flip vertical"), script_flip_vertical);
|
||||
ctx.setVariable(_("rotate"), script_rotate);
|
||||
ctx.setVariable(_("drop shadow"), script_drop_shadow);
|
||||
ctx.setVariable(_("symbol variation"), script_symbol_variation);
|
||||
ctx.setVariable(_("built in image"), script_built_in_image);
|
||||
ctx.setVariable(_("to image"), script_to_image);
|
||||
ctx.setVariable(_("linear blend"), script_linear_blend);
|
||||
ctx.setVariable(_("masked blend"), script_masked_blend);
|
||||
ctx.setVariable(_("combine blend"), script_combine_blend);
|
||||
ctx.setVariable(_("set mask"), script_set_mask);
|
||||
ctx.setVariable(_("set alpha"), script_set_alpha);
|
||||
ctx.setVariable(_("set combine"), script_set_combine);
|
||||
ctx.setVariable(_("saturate"), script_saturate);
|
||||
ctx.setVariable(_("invert image"), script_invert_image);
|
||||
ctx.setVariable(_("recolor image"), script_recolor_image);
|
||||
ctx.setVariable(_("enlarge"), script_enlarge);
|
||||
ctx.setVariable(_("crop"), script_crop);
|
||||
ctx.setVariable(_("flip horizontal"), script_flip_horizontal);
|
||||
ctx.setVariable(_("flip vertical"), script_flip_vertical);
|
||||
ctx.setVariable(_("rotate"), script_rotate);
|
||||
ctx.setVariable(_("drop shadow"), script_drop_shadow);
|
||||
ctx.setVariable(_("symbol variation"), script_symbol_variation);
|
||||
ctx.setVariable(_("built in image"), script_built_in_image);
|
||||
}
|
||||
|
||||
+185
-185
@@ -20,238 +20,238 @@ DECLARE_TYPEOF_COLLECTION(pair<Variable COMMA ScriptValueP>);
|
||||
/// A regular expression for use in a script
|
||||
class ScriptRegex : public ScriptValue, public Regex {
|
||||
public:
|
||||
virtual ScriptType type() const { return SCRIPT_REGEX; }
|
||||
virtual String typeName() const { return _("regex"); }
|
||||
|
||||
ScriptRegex(const String& code) {
|
||||
assign(code);
|
||||
}
|
||||
|
||||
/// Match only if in_context also matches
|
||||
bool matches(Results& results, const String& str, String::const_iterator begin, const ScriptRegexP& in_context) {
|
||||
if (!in_context) {
|
||||
return matches(results, begin, str.end());
|
||||
} else {
|
||||
while (matches(results, begin, str.end())) {
|
||||
Results::const_reference match = results[0];
|
||||
String context_str(str.begin(), match.first); // before
|
||||
context_str += _("<match>");
|
||||
context_str.append(match.second, str.end()); // after
|
||||
if (in_context->matches(context_str)) {
|
||||
return true; // the context matches, done
|
||||
}
|
||||
begin = match.second; // skip
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
using Regex::matches;
|
||||
virtual ScriptType type() const { return SCRIPT_REGEX; }
|
||||
virtual String typeName() const { return _("regex"); }
|
||||
|
||||
ScriptRegex(const String& code) {
|
||||
assign(code);
|
||||
}
|
||||
|
||||
/// Match only if in_context also matches
|
||||
bool matches(Results& results, const String& str, String::const_iterator begin, const ScriptRegexP& in_context) {
|
||||
if (!in_context) {
|
||||
return matches(results, begin, str.end());
|
||||
} else {
|
||||
while (matches(results, begin, str.end())) {
|
||||
Results::const_reference match = results[0];
|
||||
String context_str(str.begin(), match.first); // before
|
||||
context_str += _("<match>");
|
||||
context_str.append(match.second, str.end()); // after
|
||||
if (in_context->matches(context_str)) {
|
||||
return true; // the context matches, done
|
||||
}
|
||||
begin = match.second; // skip
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
using Regex::matches;
|
||||
};
|
||||
|
||||
ScriptRegexP regex_from_script(const ScriptValueP& value) {
|
||||
// is it a regex already?
|
||||
ScriptRegexP regex = dynamic_pointer_cast<ScriptRegex>(value);
|
||||
if (!regex) {
|
||||
// TODO: introduce some kind of caching?
|
||||
regex = intrusive(new ScriptRegex(*value));
|
||||
}
|
||||
return regex;
|
||||
// is it a regex already?
|
||||
ScriptRegexP regex = dynamic_pointer_cast<ScriptRegex>(value);
|
||||
if (!regex) {
|
||||
// TODO: introduce some kind of caching?
|
||||
regex = intrusive(new ScriptRegex(*value));
|
||||
}
|
||||
return regex;
|
||||
}
|
||||
|
||||
template <> inline ScriptRegexP from_script<ScriptRegexP>(const ScriptValueP& value) {
|
||||
return regex_from_script(value);
|
||||
return regex_from_script(value);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Rules : regex replace
|
||||
|
||||
struct RegexReplacer {
|
||||
ScriptRegexP match; ///< Regex to match
|
||||
ScriptRegexP context; ///< Match only in a given context, optional
|
||||
String replacement_string; ///< Replacement
|
||||
ScriptValueP replacement_function; ///< Replacement function instead of a simple string, optional
|
||||
bool recursive; ///< Recurse into the replacement
|
||||
|
||||
String apply(Context& ctx, const String& input, int level = 0) const {
|
||||
String ret;
|
||||
String::const_iterator start = input.begin();
|
||||
ScriptRegex::Results results;
|
||||
while (match->matches(results, input, start, context)) {
|
||||
// for each match ...
|
||||
ScriptRegex::Results::const_reference pos = results[0];
|
||||
ret.append(start, pos.first); // everything before the match position stays
|
||||
// determine replacement
|
||||
String inside;
|
||||
if (replacement_function) {
|
||||
// set match results in context
|
||||
for (UInt sub = 0 ; sub < results.size() ; ++sub) {
|
||||
String name = sub == 0 ? _("input") : String(_("_")) << sub;
|
||||
ctx.setVariable(name, to_script(results.str(sub)));
|
||||
}
|
||||
// call
|
||||
inside = replacement_function->eval(ctx)->toString();
|
||||
} else {
|
||||
inside = results.format(replacement_string);
|
||||
}
|
||||
// append replaced inside
|
||||
if (recursive && level < 20) {
|
||||
ret += apply(ctx, inside, level + 1);
|
||||
} else {
|
||||
ret += inside;
|
||||
}
|
||||
start = pos.second;
|
||||
}
|
||||
ret.append(start, input.end());
|
||||
return ret;
|
||||
}
|
||||
ScriptRegexP match; ///< Regex to match
|
||||
ScriptRegexP context; ///< Match only in a given context, optional
|
||||
String replacement_string; ///< Replacement
|
||||
ScriptValueP replacement_function; ///< Replacement function instead of a simple string, optional
|
||||
bool recursive; ///< Recurse into the replacement
|
||||
|
||||
String apply(Context& ctx, const String& input, int level = 0) const {
|
||||
String ret;
|
||||
String::const_iterator start = input.begin();
|
||||
ScriptRegex::Results results;
|
||||
while (match->matches(results, input, start, context)) {
|
||||
// for each match ...
|
||||
ScriptRegex::Results::const_reference pos = results[0];
|
||||
ret.append(start, pos.first); // everything before the match position stays
|
||||
// determine replacement
|
||||
String inside;
|
||||
if (replacement_function) {
|
||||
// set match results in context
|
||||
for (UInt sub = 0 ; sub < results.size() ; ++sub) {
|
||||
String name = sub == 0 ? _("input") : String(_("_")) << sub;
|
||||
ctx.setVariable(name, to_script(results.str(sub)));
|
||||
}
|
||||
// call
|
||||
inside = replacement_function->eval(ctx)->toString();
|
||||
} else {
|
||||
inside = results.format(replacement_string);
|
||||
}
|
||||
// append replaced inside
|
||||
if (recursive && level < 20) {
|
||||
ret += apply(ctx, inside, level + 1);
|
||||
} else {
|
||||
ret += inside;
|
||||
}
|
||||
start = pos.second;
|
||||
}
|
||||
ret.append(start, input.end());
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
SCRIPT_FUNCTION_WITH_SIMPLIFY(replace) {
|
||||
// construct replacer
|
||||
RegexReplacer replacer;
|
||||
replacer.match = from_script<ScriptRegexP>(ctx.getVariable(SCRIPT_VAR_match), SCRIPT_VAR_match);
|
||||
if (ctx.getVariableOpt(SCRIPT_VAR_in_context)) {
|
||||
replacer.context = from_script<ScriptRegexP>(ctx.getVariableOpt(SCRIPT_VAR_in_context), SCRIPT_VAR_in_context);
|
||||
}
|
||||
if (ctx.getVariableOpt(SCRIPT_VAR_recursive)) {
|
||||
replacer.recursive = from_script<bool>(ctx.getVariableOpt(SCRIPT_VAR_recursive), SCRIPT_VAR_recursive);
|
||||
} else {
|
||||
replacer.recursive = false;
|
||||
}
|
||||
replacer.replacement_function = ctx.getVariable(SCRIPT_VAR_replace);
|
||||
if (replacer.replacement_function->type() != SCRIPT_FUNCTION) {
|
||||
replacer.replacement_string = replacer.replacement_function->toString();
|
||||
replacer.replacement_function = ScriptValueP();
|
||||
}
|
||||
// run
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
if (replacer.context || replacer.replacement_function || replacer.recursive) {
|
||||
SCRIPT_RETURN(replacer.apply(ctx, input));
|
||||
} else {
|
||||
// simple replacing
|
||||
replacer.match->replace_all(&input, replacer.replacement_string);
|
||||
SCRIPT_RETURN(input);
|
||||
}
|
||||
// construct replacer
|
||||
RegexReplacer replacer;
|
||||
replacer.match = from_script<ScriptRegexP>(ctx.getVariable(SCRIPT_VAR_match), SCRIPT_VAR_match);
|
||||
if (ctx.getVariableOpt(SCRIPT_VAR_in_context)) {
|
||||
replacer.context = from_script<ScriptRegexP>(ctx.getVariableOpt(SCRIPT_VAR_in_context), SCRIPT_VAR_in_context);
|
||||
}
|
||||
if (ctx.getVariableOpt(SCRIPT_VAR_recursive)) {
|
||||
replacer.recursive = from_script<bool>(ctx.getVariableOpt(SCRIPT_VAR_recursive), SCRIPT_VAR_recursive);
|
||||
} else {
|
||||
replacer.recursive = false;
|
||||
}
|
||||
replacer.replacement_function = ctx.getVariable(SCRIPT_VAR_replace);
|
||||
if (replacer.replacement_function->type() != SCRIPT_FUNCTION) {
|
||||
replacer.replacement_string = replacer.replacement_function->toString();
|
||||
replacer.replacement_function = ScriptValueP();
|
||||
}
|
||||
// run
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
if (replacer.context || replacer.replacement_function || replacer.recursive) {
|
||||
SCRIPT_RETURN(replacer.apply(ctx, input));
|
||||
} else {
|
||||
// simple replacing
|
||||
replacer.match->replace_all(&input, replacer.replacement_string);
|
||||
SCRIPT_RETURN(input);
|
||||
}
|
||||
}
|
||||
SCRIPT_FUNCTION_SIMPLIFY_CLOSURE(replace) {
|
||||
FOR_EACH(b, closure.bindings) {
|
||||
if (b.first == SCRIPT_VAR_match || b.first == SCRIPT_VAR_in_context) {
|
||||
b.second = regex_from_script(b.second); // pre-compile
|
||||
}
|
||||
}
|
||||
return ScriptValueP();
|
||||
FOR_EACH(b, closure.bindings) {
|
||||
if (b.first == SCRIPT_VAR_match || b.first == SCRIPT_VAR_in_context) {
|
||||
b.second = regex_from_script(b.second); // pre-compile
|
||||
}
|
||||
}
|
||||
return ScriptValueP();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Rules : regex filter
|
||||
|
||||
SCRIPT_FUNCTION_WITH_SIMPLIFY(filter_text) {
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
SCRIPT_PARAM_C(ScriptRegexP, match);
|
||||
SCRIPT_OPTIONAL_PARAM_C_(ScriptRegexP, in_context);
|
||||
String ret;
|
||||
// find all matches
|
||||
String::const_iterator start = input.begin();
|
||||
ScriptRegex::Results results;
|
||||
while (match->matches(results, input, start, in_context)) {
|
||||
// match, append to result
|
||||
ScriptRegex::Results::const_reference pos = results[0];
|
||||
ret.append(pos.first, pos.second); // the match
|
||||
start = pos.second;
|
||||
}
|
||||
SCRIPT_RETURN(ret);
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
SCRIPT_PARAM_C(ScriptRegexP, match);
|
||||
SCRIPT_OPTIONAL_PARAM_C_(ScriptRegexP, in_context);
|
||||
String ret;
|
||||
// find all matches
|
||||
String::const_iterator start = input.begin();
|
||||
ScriptRegex::Results results;
|
||||
while (match->matches(results, input, start, in_context)) {
|
||||
// match, append to result
|
||||
ScriptRegex::Results::const_reference pos = results[0];
|
||||
ret.append(pos.first, pos.second); // the match
|
||||
start = pos.second;
|
||||
}
|
||||
SCRIPT_RETURN(ret);
|
||||
}
|
||||
SCRIPT_FUNCTION_SIMPLIFY_CLOSURE(filter_text) {
|
||||
FOR_EACH(b, closure.bindings) {
|
||||
if (b.first == SCRIPT_VAR_match || b.first == SCRIPT_VAR_in_context) {
|
||||
b.second = regex_from_script(b.second); // pre-compile
|
||||
}
|
||||
}
|
||||
return ScriptValueP();
|
||||
FOR_EACH(b, closure.bindings) {
|
||||
if (b.first == SCRIPT_VAR_match || b.first == SCRIPT_VAR_in_context) {
|
||||
b.second = regex_from_script(b.second); // pre-compile
|
||||
}
|
||||
}
|
||||
return ScriptValueP();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Rules : regex break
|
||||
|
||||
SCRIPT_FUNCTION_WITH_SIMPLIFY(break_text) {
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
SCRIPT_PARAM_C(ScriptRegexP, match);
|
||||
SCRIPT_OPTIONAL_PARAM_C_(ScriptRegexP, in_context);
|
||||
ScriptCustomCollectionP ret(new ScriptCustomCollection);
|
||||
// find all matches
|
||||
String::const_iterator start = input.begin();
|
||||
ScriptRegex::Results results;
|
||||
while (match->matches(results, input, start, in_context)) {
|
||||
// match, append to result
|
||||
ret->value.push_back(to_script(results.str()));
|
||||
start = results[0].second;
|
||||
}
|
||||
return ret;
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
SCRIPT_PARAM_C(ScriptRegexP, match);
|
||||
SCRIPT_OPTIONAL_PARAM_C_(ScriptRegexP, in_context);
|
||||
ScriptCustomCollectionP ret(new ScriptCustomCollection);
|
||||
// find all matches
|
||||
String::const_iterator start = input.begin();
|
||||
ScriptRegex::Results results;
|
||||
while (match->matches(results, input, start, in_context)) {
|
||||
// match, append to result
|
||||
ret->value.push_back(to_script(results.str()));
|
||||
start = results[0].second;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
SCRIPT_FUNCTION_SIMPLIFY_CLOSURE(break_text) {
|
||||
FOR_EACH(b, closure.bindings) {
|
||||
if (b.first == SCRIPT_VAR_match || b.first == SCRIPT_VAR_in_context) {
|
||||
b.second = regex_from_script(b.second); // pre-compile
|
||||
}
|
||||
}
|
||||
return ScriptValueP();
|
||||
FOR_EACH(b, closure.bindings) {
|
||||
if (b.first == SCRIPT_VAR_match || b.first == SCRIPT_VAR_in_context) {
|
||||
b.second = regex_from_script(b.second); // pre-compile
|
||||
}
|
||||
}
|
||||
return ScriptValueP();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Rules : regex split
|
||||
|
||||
SCRIPT_FUNCTION_WITH_SIMPLIFY(split_text) {
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
SCRIPT_PARAM_C(ScriptRegexP, match);
|
||||
SCRIPT_PARAM_DEFAULT_N(bool, _("include empty"), include_empty, true);
|
||||
ScriptCustomCollectionP ret(new ScriptCustomCollection);
|
||||
// find all matches
|
||||
String::const_iterator start = input.begin();
|
||||
ScriptRegex::Results results;
|
||||
while (match->matches(results, start, input.end())) {
|
||||
// match, append the part before it to the result
|
||||
ScriptRegex::Results::const_reference pos = results[0];
|
||||
if (include_empty || pos.first != start) {
|
||||
ret->value.push_back(to_script( String(start,pos.first) ));
|
||||
}
|
||||
start = pos.second;
|
||||
}
|
||||
if (include_empty || start != input.end()) {
|
||||
ret->value.push_back(to_script( String(start,input.end()) ));
|
||||
}
|
||||
return ret;
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
SCRIPT_PARAM_C(ScriptRegexP, match);
|
||||
SCRIPT_PARAM_DEFAULT_N(bool, _("include empty"), include_empty, true);
|
||||
ScriptCustomCollectionP ret(new ScriptCustomCollection);
|
||||
// find all matches
|
||||
String::const_iterator start = input.begin();
|
||||
ScriptRegex::Results results;
|
||||
while (match->matches(results, start, input.end())) {
|
||||
// match, append the part before it to the result
|
||||
ScriptRegex::Results::const_reference pos = results[0];
|
||||
if (include_empty || pos.first != start) {
|
||||
ret->value.push_back(to_script( String(start,pos.first) ));
|
||||
}
|
||||
start = pos.second;
|
||||
}
|
||||
if (include_empty || start != input.end()) {
|
||||
ret->value.push_back(to_script( String(start,input.end()) ));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
SCRIPT_FUNCTION_SIMPLIFY_CLOSURE(split_text) {
|
||||
FOR_EACH(b, closure.bindings) {
|
||||
if (b.first == SCRIPT_VAR_match) {
|
||||
b.second = regex_from_script(b.second); // pre-compile
|
||||
}
|
||||
}
|
||||
return ScriptValueP();
|
||||
FOR_EACH(b, closure.bindings) {
|
||||
if (b.first == SCRIPT_VAR_match) {
|
||||
b.second = regex_from_script(b.second); // pre-compile
|
||||
}
|
||||
}
|
||||
return ScriptValueP();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Rules : regex match
|
||||
|
||||
SCRIPT_FUNCTION_WITH_SIMPLIFY(match) {
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
SCRIPT_PARAM_C(ScriptRegexP, match);
|
||||
SCRIPT_RETURN(match->matches(input));
|
||||
SCRIPT_PARAM_C(String, input);
|
||||
SCRIPT_PARAM_C(ScriptRegexP, match);
|
||||
SCRIPT_RETURN(match->matches(input));
|
||||
}
|
||||
SCRIPT_FUNCTION_SIMPLIFY_CLOSURE(match) {
|
||||
FOR_EACH(b, closure.bindings) {
|
||||
if (b.first == SCRIPT_VAR_match) {
|
||||
b.second = regex_from_script(b.second); // pre-compile
|
||||
}
|
||||
}
|
||||
return ScriptValueP();
|
||||
FOR_EACH(b, closure.bindings) {
|
||||
if (b.first == SCRIPT_VAR_match) {
|
||||
b.second = regex_from_script(b.second); // pre-compile
|
||||
}
|
||||
}
|
||||
return ScriptValueP();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Init
|
||||
|
||||
void init_script_regex_functions(Context& ctx) {
|
||||
ctx.setVariable(_("replace"), script_replace);
|
||||
ctx.setVariable(_("filter text"), script_filter_text);
|
||||
ctx.setVariable(_("break text"), script_break_text);
|
||||
ctx.setVariable(_("split text"), script_split_text);
|
||||
ctx.setVariable(_("match"), script_match);
|
||||
ctx.setVariable(_("replace rule"), intrusive(new ScriptRule(script_replace)));
|
||||
ctx.setVariable(_("filter rule"), intrusive(new ScriptRule(script_filter_text)));
|
||||
ctx.setVariable(_("break rule"), intrusive(new ScriptRule(script_break_text)));
|
||||
ctx.setVariable(_("match rule"), intrusive(new ScriptRule(script_match)));
|
||||
ctx.setVariable(_("replace"), script_replace);
|
||||
ctx.setVariable(_("filter text"), script_filter_text);
|
||||
ctx.setVariable(_("break text"), script_break_text);
|
||||
ctx.setVariable(_("split text"), script_split_text);
|
||||
ctx.setVariable(_("match"), script_match);
|
||||
ctx.setVariable(_("replace rule"), intrusive(new ScriptRule(script_replace)));
|
||||
ctx.setVariable(_("filter rule"), intrusive(new ScriptRule(script_filter_text)));
|
||||
ctx.setVariable(_("break rule"), intrusive(new ScriptRule(script_break_text)));
|
||||
ctx.setVariable(_("match rule"), intrusive(new ScriptRule(script_match)));
|
||||
}
|
||||
|
||||
+144
-144
@@ -17,165 +17,165 @@
|
||||
// ----------------------------------------------------------------------------- : Functions
|
||||
|
||||
inline size_t spelled_correctly(const String& input, size_t start, size_t end, SpellChecker** checkers, const ScriptValueP& extra_test, Context& ctx) {
|
||||
// untag
|
||||
String word = untag(input.substr(start,end-start));
|
||||
if (word.empty()) return true;
|
||||
// symbol?
|
||||
if (is_in_tag(input,_("<sym"),start,end) ||
|
||||
is_in_tag(input,_("<nospellcheck"),start,end)) {
|
||||
// symbols are always spelled correctly
|
||||
// and <nospellcheck> tags should prevent spellcheck
|
||||
return true;
|
||||
}
|
||||
// run through spellchecker(s)
|
||||
for (size_t i = 0 ; checkers[i] ; ++i) {
|
||||
if (checkers[i]->spell(word)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// run through additional words regex
|
||||
if (extra_test) {
|
||||
// try on untagged
|
||||
ctx.setVariable(SCRIPT_VAR_input, to_script(word));
|
||||
if (*extra_test->eval(ctx)) {
|
||||
return true;
|
||||
}
|
||||
// try on tagged
|
||||
ctx.setVariable(SCRIPT_VAR_input, to_script(input.substr(start,end-start)));
|
||||
if (*extra_test->eval(ctx)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
// untag
|
||||
String word = untag(input.substr(start,end-start));
|
||||
if (word.empty()) return true;
|
||||
// symbol?
|
||||
if (is_in_tag(input,_("<sym"),start,end) ||
|
||||
is_in_tag(input,_("<nospellcheck"),start,end)) {
|
||||
// symbols are always spelled correctly
|
||||
// and <nospellcheck> tags should prevent spellcheck
|
||||
return true;
|
||||
}
|
||||
// run through spellchecker(s)
|
||||
for (size_t i = 0 ; checkers[i] ; ++i) {
|
||||
if (checkers[i]->spell(word)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// run through additional words regex
|
||||
if (extra_test) {
|
||||
// try on untagged
|
||||
ctx.setVariable(SCRIPT_VAR_input, to_script(word));
|
||||
if (*extra_test->eval(ctx)) {
|
||||
return true;
|
||||
}
|
||||
// try on tagged
|
||||
ctx.setVariable(SCRIPT_VAR_input, to_script(input.substr(start,end-start)));
|
||||
if (*extra_test->eval(ctx)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void check_word(const String& tag, const String& input, String& out, size_t start, size_t end, SpellChecker** checkers, const ScriptValueP& extra_test, Context& ctx) {
|
||||
if (start >= end) return;
|
||||
bool good = spelled_correctly(input, start, end, checkers, extra_test, ctx);
|
||||
if (!good) out += _("<") + tag;
|
||||
out.append(input, start, end-start);
|
||||
if (!good) out += _("</") + tag;
|
||||
if (start >= end) return;
|
||||
bool good = spelled_correctly(input, start, end, checkers, extra_test, ctx);
|
||||
if (!good) out += _("<") + tag;
|
||||
out.append(input, start, end-start);
|
||||
if (!good) out += _("</") + tag;
|
||||
}
|
||||
|
||||
void check_word(const String& tag, const String& input, String& out, Char sep, size_t prev, size_t start, size_t end, size_t after, SpellChecker** checkers, const ScriptValueP& extra_test, Context& ctx) {
|
||||
if (start == end) {
|
||||
// word consisting of whitespace/punctuation only
|
||||
if (untag(input.substr(prev,after-prev)).empty()) {
|
||||
if (isSpace(sep) && (after == input.size() || isSpace(input.GetChar(after)))) {
|
||||
// double space
|
||||
out += _("<error-spelling>");
|
||||
out.append(sep);
|
||||
out.append(input, prev, after-prev);
|
||||
out += _("</error-spelling>");
|
||||
} else {
|
||||
if (sep) out.append(sep);
|
||||
out.append(input, prev, after-prev);
|
||||
}
|
||||
} else {
|
||||
// stand alone punctuation
|
||||
if (sep) out.append(sep);
|
||||
out += _("<error-spelling>");
|
||||
out.append(input, prev, after-prev);
|
||||
out += _("</error-spelling>");
|
||||
}
|
||||
} else {
|
||||
// before the word
|
||||
if (sep) out.append(sep);
|
||||
out.append(input, prev, start-prev);
|
||||
// the word itself
|
||||
check_word(tag, input, out, start, end, checkers, extra_test, ctx);
|
||||
// after the word
|
||||
out.append(input, end, after-end);
|
||||
}
|
||||
if (start == end) {
|
||||
// word consisting of whitespace/punctuation only
|
||||
if (untag(input.substr(prev,after-prev)).empty()) {
|
||||
if (isSpace(sep) && (after == input.size() || isSpace(input.GetChar(after)))) {
|
||||
// double space
|
||||
out += _("<error-spelling>");
|
||||
out.append(sep);
|
||||
out.append(input, prev, after-prev);
|
||||
out += _("</error-spelling>");
|
||||
} else {
|
||||
if (sep) out.append(sep);
|
||||
out.append(input, prev, after-prev);
|
||||
}
|
||||
} else {
|
||||
// stand alone punctuation
|
||||
if (sep) out.append(sep);
|
||||
out += _("<error-spelling>");
|
||||
out.append(input, prev, after-prev);
|
||||
out += _("</error-spelling>");
|
||||
}
|
||||
} else {
|
||||
// before the word
|
||||
if (sep) out.append(sep);
|
||||
out.append(input, prev, start-prev);
|
||||
// the word itself
|
||||
check_word(tag, input, out, start, end, checkers, extra_test, ctx);
|
||||
// after the word
|
||||
out.append(input, end, after-end);
|
||||
}
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(check_spelling) {
|
||||
SCRIPT_PARAM_C(StyleSheetP,stylesheet);
|
||||
SCRIPT_PARAM_C(String,language);
|
||||
SCRIPT_PARAM_C(String,input);
|
||||
assert_tagged(input);
|
||||
if (!settings.stylesheetSettingsFor(*stylesheet).card_spellcheck_enabled)
|
||||
SCRIPT_RETURN(input);
|
||||
SCRIPT_OPTIONAL_PARAM_N_(String,_("extra dictionary"),extra_dictionary);
|
||||
SCRIPT_OPTIONAL_PARAM_N_(ScriptValueP,_("extra match"),extra_match);
|
||||
// remove old spelling error tags
|
||||
input = remove_tag(input, _("<error-spelling"));
|
||||
// no language -> spelling checking
|
||||
if (language.empty()) {
|
||||
SCRIPT_RETURN(input);
|
||||
}
|
||||
SpellChecker* checkers[3] = {nullptr};
|
||||
checkers[0] = &SpellChecker::get(language);
|
||||
if (!extra_dictionary.empty()) {
|
||||
checkers[1] = &SpellChecker::get(extra_dictionary,language);
|
||||
}
|
||||
// what will the missspelling tag be?
|
||||
String tag = _("error-spelling:");
|
||||
tag += language;
|
||||
if (!extra_dictionary.empty()) {
|
||||
tag += _(":") + extra_dictionary;
|
||||
}
|
||||
tag += _(">");
|
||||
// now walk over the words in the input, and mark misspellings
|
||||
String result;
|
||||
Char sep = 0;
|
||||
// indices are used as follows (at the time of check_word call):
|
||||
// input: "previous <tag>(<tag>word<tag>)<tag>next"
|
||||
// ^^ ^ ^ ^
|
||||
// || | | |
|
||||
// sep | | word_end pos
|
||||
// prev_end word_start
|
||||
//
|
||||
size_t prev_end = 0, word_start = 0, word_end = 0, pos = 0;
|
||||
while (pos < input.size()) {
|
||||
Char c = input.GetChar(pos);
|
||||
if (c == _('<')) {
|
||||
if (word_start == pos) {
|
||||
// prefer to place word start inside tags, i.e. as late as possible
|
||||
word_end = word_start = pos = skip_tag(input,pos);
|
||||
} else {
|
||||
pos = skip_tag(input,pos);
|
||||
}
|
||||
} else if (isSpace(c) || c == EM_DASH || c == EN_DASH) {
|
||||
// word boundary => check the word
|
||||
check_word(tag, input, result, sep, prev_end, word_start, word_end, pos, checkers, extra_match, ctx);
|
||||
// next
|
||||
sep = c;
|
||||
prev_end = word_start = word_end = pos = pos + 1;
|
||||
} else {
|
||||
pos++;
|
||||
if (word_start == pos-1 && is_word_start_punctuation(c)) {
|
||||
// skip punctuation at start of word
|
||||
word_end = word_start = pos;
|
||||
} else if (is_word_end_punctuation(c)) {
|
||||
// skip punctuation at end of word
|
||||
} else {
|
||||
word_end = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
// last word
|
||||
check_word(tag, input, result, sep, prev_end, word_start, word_end, pos, checkers, extra_match, ctx);
|
||||
// done
|
||||
assert_tagged(result);
|
||||
SCRIPT_RETURN(result);
|
||||
SCRIPT_PARAM_C(StyleSheetP,stylesheet);
|
||||
SCRIPT_PARAM_C(String,language);
|
||||
SCRIPT_PARAM_C(String,input);
|
||||
assert_tagged(input);
|
||||
if (!settings.stylesheetSettingsFor(*stylesheet).card_spellcheck_enabled)
|
||||
SCRIPT_RETURN(input);
|
||||
SCRIPT_OPTIONAL_PARAM_N_(String,_("extra dictionary"),extra_dictionary);
|
||||
SCRIPT_OPTIONAL_PARAM_N_(ScriptValueP,_("extra match"),extra_match);
|
||||
// remove old spelling error tags
|
||||
input = remove_tag(input, _("<error-spelling"));
|
||||
// no language -> spelling checking
|
||||
if (language.empty()) {
|
||||
SCRIPT_RETURN(input);
|
||||
}
|
||||
SpellChecker* checkers[3] = {nullptr};
|
||||
checkers[0] = &SpellChecker::get(language);
|
||||
if (!extra_dictionary.empty()) {
|
||||
checkers[1] = &SpellChecker::get(extra_dictionary,language);
|
||||
}
|
||||
// what will the missspelling tag be?
|
||||
String tag = _("error-spelling:");
|
||||
tag += language;
|
||||
if (!extra_dictionary.empty()) {
|
||||
tag += _(":") + extra_dictionary;
|
||||
}
|
||||
tag += _(">");
|
||||
// now walk over the words in the input, and mark misspellings
|
||||
String result;
|
||||
Char sep = 0;
|
||||
// indices are used as follows (at the time of check_word call):
|
||||
// input: "previous <tag>(<tag>word<tag>)<tag>next"
|
||||
// ^^ ^ ^ ^
|
||||
// || | | |
|
||||
// sep | | word_end pos
|
||||
// prev_end word_start
|
||||
//
|
||||
size_t prev_end = 0, word_start = 0, word_end = 0, pos = 0;
|
||||
while (pos < input.size()) {
|
||||
Char c = input.GetChar(pos);
|
||||
if (c == _('<')) {
|
||||
if (word_start == pos) {
|
||||
// prefer to place word start inside tags, i.e. as late as possible
|
||||
word_end = word_start = pos = skip_tag(input,pos);
|
||||
} else {
|
||||
pos = skip_tag(input,pos);
|
||||
}
|
||||
} else if (isSpace(c) || c == EM_DASH || c == EN_DASH) {
|
||||
// word boundary => check the word
|
||||
check_word(tag, input, result, sep, prev_end, word_start, word_end, pos, checkers, extra_match, ctx);
|
||||
// next
|
||||
sep = c;
|
||||
prev_end = word_start = word_end = pos = pos + 1;
|
||||
} else {
|
||||
pos++;
|
||||
if (word_start == pos-1 && is_word_start_punctuation(c)) {
|
||||
// skip punctuation at start of word
|
||||
word_end = word_start = pos;
|
||||
} else if (is_word_end_punctuation(c)) {
|
||||
// skip punctuation at end of word
|
||||
} else {
|
||||
word_end = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
// last word
|
||||
check_word(tag, input, result, sep, prev_end, word_start, word_end, pos, checkers, extra_match, ctx);
|
||||
// done
|
||||
assert_tagged(result);
|
||||
SCRIPT_RETURN(result);
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(check_spelling_word) {
|
||||
SCRIPT_PARAM_C(String,language);
|
||||
SCRIPT_PARAM_C(String,input);
|
||||
if (language.empty()) {
|
||||
// no language -> spelling checking
|
||||
SCRIPT_RETURN(true);
|
||||
} else {
|
||||
bool correct = SpellChecker::get(language).spell(input);
|
||||
SCRIPT_RETURN(correct);
|
||||
}
|
||||
SCRIPT_PARAM_C(String,language);
|
||||
SCRIPT_PARAM_C(String,input);
|
||||
if (language.empty()) {
|
||||
// no language -> spelling checking
|
||||
SCRIPT_RETURN(true);
|
||||
} else {
|
||||
bool correct = SpellChecker::get(language).spell(input);
|
||||
SCRIPT_RETURN(correct);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Init
|
||||
|
||||
void init_script_spelling_functions(Context& ctx) {
|
||||
ctx.setVariable(_("check spelling"), script_check_spelling);
|
||||
ctx.setVariable(_("check spelling word"), script_check_spelling_word);
|
||||
ctx.setVariable(_("check spelling"), script_check_spelling);
|
||||
ctx.setVariable(_("check spelling word"), script_check_spelling_word);
|
||||
}
|
||||
|
||||
+118
-118
@@ -38,31 +38,31 @@
|
||||
#define SCRIPT_FUNCTION(name) SCRIPT_FUNCTION_AUX(name,;)
|
||||
|
||||
/// Macro to declare a new script function with custom dependency handling
|
||||
#define SCRIPT_FUNCTION_WITH_DEP(name) \
|
||||
SCRIPT_FUNCTION_AUX(name, virtual ScriptValueP dependencies(Context&, const Dependency&) const;)
|
||||
#define SCRIPT_FUNCTION_WITH_DEP(name) \
|
||||
SCRIPT_FUNCTION_AUX(name, virtual ScriptValueP dependencies(Context&, const Dependency&) const;)
|
||||
|
||||
#define SCRIPT_FUNCTION_DEPENDENCIES(name) \
|
||||
ScriptValueP ScriptBuiltIn_##name::dependencies(Context& ctx, const Dependency& dep) const
|
||||
#define SCRIPT_FUNCTION_DEPENDENCIES(name) \
|
||||
ScriptValueP ScriptBuiltIn_##name::dependencies(Context& ctx, const Dependency& dep) const
|
||||
|
||||
/// Macro to declare a new script function with custom closure simplification
|
||||
#define SCRIPT_FUNCTION_WITH_SIMPLIFY(name) \
|
||||
SCRIPT_FUNCTION_AUX(name, virtual ScriptValueP simplifyClosure(ScriptClosure&) const;)
|
||||
#define SCRIPT_FUNCTION_WITH_SIMPLIFY(name) \
|
||||
SCRIPT_FUNCTION_AUX(name, virtual ScriptValueP simplifyClosure(ScriptClosure&) const;)
|
||||
|
||||
#define SCRIPT_FUNCTION_SIMPLIFY_CLOSURE(name) \
|
||||
ScriptValueP ScriptBuiltIn_##name::simplifyClosure(ScriptClosure& closure) const
|
||||
#define SCRIPT_FUNCTION_SIMPLIFY_CLOSURE(name) \
|
||||
ScriptValueP ScriptBuiltIn_##name::simplifyClosure(ScriptClosure& closure) const
|
||||
|
||||
// helper for SCRIPT_FUNCTION and SCRIPT_FUNCTION_DEP
|
||||
#define SCRIPT_FUNCTION_AUX(name,dep) \
|
||||
class ScriptBuiltIn_##name : public ScriptValue { \
|
||||
dep \
|
||||
virtual ScriptType type() const \
|
||||
{ return SCRIPT_FUNCTION; } \
|
||||
virtual String typeName() const \
|
||||
{ return _("built-in function '") _(#name) _("'"); } \
|
||||
virtual ScriptValueP do_eval(Context&, bool) const; \
|
||||
}; \
|
||||
ScriptValueP script_##name(new ScriptBuiltIn_##name); \
|
||||
ScriptValueP ScriptBuiltIn_##name::do_eval(Context& ctx, bool) const
|
||||
#define SCRIPT_FUNCTION_AUX(name,dep) \
|
||||
class ScriptBuiltIn_##name : public ScriptValue { \
|
||||
dep \
|
||||
virtual ScriptType type() const \
|
||||
{ return SCRIPT_FUNCTION; } \
|
||||
virtual String typeName() const \
|
||||
{ return _("built-in function '") _(#name) _("'"); } \
|
||||
virtual ScriptValueP do_eval(Context&, bool) const; \
|
||||
}; \
|
||||
ScriptValueP script_##name(new ScriptBuiltIn_##name); \
|
||||
ScriptValueP ScriptBuiltIn_##name::do_eval(Context& ctx, bool) const
|
||||
|
||||
/// Return a value from a SCRIPT_FUNCTION
|
||||
#define SCRIPT_RETURN(value) return to_script(value)
|
||||
@@ -71,19 +71,19 @@
|
||||
|
||||
template <typename Type>
|
||||
inline Type from_script(const ScriptValueP& v, const String& str) {
|
||||
try {
|
||||
return from_script<Type>(v);
|
||||
} catch (ScriptError& e) {
|
||||
throw ScriptError(_ERROR_2_("in parameter", str, e.what()));
|
||||
}
|
||||
try {
|
||||
return from_script<Type>(v);
|
||||
} catch (ScriptError& e) {
|
||||
throw ScriptError(_ERROR_2_("in parameter", str, e.what()));
|
||||
}
|
||||
}
|
||||
template <typename Type>
|
||||
inline Type from_script(const ScriptValueP& v, Variable var) {
|
||||
try {
|
||||
return from_script<Type>(v);
|
||||
} catch (ScriptError& e) {
|
||||
throw ScriptError(_ERROR_2_("in parameter", variable_to_string(var), e.what()));
|
||||
}
|
||||
try {
|
||||
return from_script<Type>(v);
|
||||
} catch (ScriptError& e) {
|
||||
throw ScriptError(_ERROR_2_("in parameter", variable_to_string(var), e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieve a parameter to a SCRIPT_FUNCTION with the given name and type
|
||||
@@ -96,14 +96,14 @@ inline Type from_script(const ScriptValueP& v, Variable var) {
|
||||
* @endcode
|
||||
* Throws an error if the parameter is not found.
|
||||
*/
|
||||
#define SCRIPT_PARAM(Type, name) \
|
||||
SCRIPT_PARAM_N(Type, _(#name), name)
|
||||
#define SCRIPT_PARAM_N(Type, str, name) \
|
||||
Type name = from_script<Type>(ctx.getVariable(str), str)
|
||||
#define SCRIPT_PARAM(Type, name) \
|
||||
SCRIPT_PARAM_N(Type, _(#name), name)
|
||||
#define SCRIPT_PARAM_N(Type, str, name) \
|
||||
Type name = from_script<Type>(ctx.getVariable(str), str)
|
||||
/// Faster variant of SCRIPT_PARAM when name is a CommonScriptVariable
|
||||
/** Doesn't require a runtime lookup of the name */
|
||||
#define SCRIPT_PARAM_C(Type, name) \
|
||||
SCRIPT_PARAM_N(Type, SCRIPT_VAR_ ## name, name)
|
||||
#define SCRIPT_PARAM_C(Type, name) \
|
||||
SCRIPT_PARAM_N(Type, SCRIPT_VAR_ ## name, name)
|
||||
|
||||
/// Retrieve an optional parameter
|
||||
/** Usage:
|
||||
@@ -116,112 +116,112 @@ inline Type from_script(const ScriptValueP& v, Variable var) {
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
#define SCRIPT_OPTIONAL_PARAM(Type, name) \
|
||||
SCRIPT_OPTIONAL_PARAM_N(Type, _(#name), name)
|
||||
#define SCRIPT_OPTIONAL_PARAM(Type, name) \
|
||||
SCRIPT_OPTIONAL_PARAM_N(Type, _(#name), name)
|
||||
/// Retrieve a named optional parameter
|
||||
#define SCRIPT_OPTIONAL_PARAM_N(Type, str, name) \
|
||||
SCRIPT_OPTIONAL_PARAM_N_(Type, str, name) \
|
||||
if (name##_)
|
||||
#define SCRIPT_OPTIONAL_PARAM_C(Type, name) \
|
||||
SCRIPT_OPTIONAL_PARAM_N(Type, SCRIPT_VAR_ ## name, name)
|
||||
#define SCRIPT_OPTIONAL_PARAM_N(Type, str, name) \
|
||||
SCRIPT_OPTIONAL_PARAM_N_(Type, str, name) \
|
||||
if (name##_)
|
||||
#define SCRIPT_OPTIONAL_PARAM_C(Type, name) \
|
||||
SCRIPT_OPTIONAL_PARAM_N(Type, SCRIPT_VAR_ ## name, name)
|
||||
|
||||
/// Retrieve an optional parameter, can't be used as an if statement
|
||||
#define SCRIPT_OPTIONAL_PARAM_(Type, name) \
|
||||
SCRIPT_OPTIONAL_PARAM_N_(Type, _(#name), name)
|
||||
#define SCRIPT_OPTIONAL_PARAM_(Type, name) \
|
||||
SCRIPT_OPTIONAL_PARAM_N_(Type, _(#name), name)
|
||||
/// Retrieve a named optional parameter, can't be used as an if statement
|
||||
#define SCRIPT_OPTIONAL_PARAM_N_(Type, str, name) \
|
||||
ScriptValueP name##_ = ctx.getVariableOpt(str); \
|
||||
Type name = name##_ && name##_ != script_nil \
|
||||
? from_script<Type>(name##_, str) : Type();
|
||||
#define SCRIPT_OPTIONAL_PARAM_C_(Type, name) \
|
||||
SCRIPT_OPTIONAL_PARAM_N_(Type, SCRIPT_VAR_ ## name, name)
|
||||
#define SCRIPT_OPTIONAL_PARAM_N_(Type, str, name) \
|
||||
ScriptValueP name##_ = ctx.getVariableOpt(str); \
|
||||
Type name = name##_ && name##_ != script_nil \
|
||||
? from_script<Type>(name##_, str) : Type();
|
||||
#define SCRIPT_OPTIONAL_PARAM_C_(Type, name) \
|
||||
SCRIPT_OPTIONAL_PARAM_N_(Type, SCRIPT_VAR_ ## name, name)
|
||||
|
||||
/// Retrieve an optional parameter with a default value
|
||||
#define SCRIPT_PARAM_DEFAULT(Type, name, def) \
|
||||
SCRIPT_PARAM_DEFAULT_N(Type, _(#name), name, def)
|
||||
#define SCRIPT_PARAM_DEFAULT(Type, name, def) \
|
||||
SCRIPT_PARAM_DEFAULT_N(Type, _(#name), name, def)
|
||||
/// Retrieve a named optional parameter with a default value
|
||||
#define SCRIPT_PARAM_DEFAULT_N(Type, str, name, def) \
|
||||
ScriptValueP name##_ = ctx.getVariableOpt(str); \
|
||||
Type name = name##_ ? from_script<Type>(name##_, str) : def
|
||||
#define SCRIPT_PARAM_DEFAULT_C(Type, name, def) \
|
||||
SCRIPT_PARAM_DEFAULT_N(Type, SCRIPT_VAR_ ## name, name, def)
|
||||
#define SCRIPT_PARAM_DEFAULT_N(Type, str, name, def) \
|
||||
ScriptValueP name##_ = ctx.getVariableOpt(str); \
|
||||
Type name = name##_ ? from_script<Type>(name##_, str) : def
|
||||
#define SCRIPT_PARAM_DEFAULT_C(Type, name, def) \
|
||||
SCRIPT_PARAM_DEFAULT_N(Type, SCRIPT_VAR_ ## name, name, def)
|
||||
|
||||
// ----------------------------------------------------------------------------- : Rules
|
||||
|
||||
/// Utility for defining a script rule with a single parameter
|
||||
#define SCRIPT_RULE_1(funname, type1, name1) \
|
||||
#define SCRIPT_RULE_1(funname, type1, name1) \
|
||||
SCRIPT_RULE_1_N(funname, type1, _(#name1), name1)
|
||||
#define SCRIPT_RULE_1_C(funname, type1, name1) \
|
||||
#define SCRIPT_RULE_1_C(funname, type1, name1) \
|
||||
SCRIPT_RULE_1_N(funname, type1, SCRIPT_VAR_ ## name1, name1)
|
||||
/// Utility for defining a script rule with a single named parameter
|
||||
#define SCRIPT_RULE_1_N(funname, type1, str1, name1) \
|
||||
class ScriptRule_##funname: public ScriptValue { \
|
||||
public: \
|
||||
inline ScriptRule_##funname(const type1& name1) : name1(name1) {} \
|
||||
virtual ScriptType type() const { return SCRIPT_FUNCTION; } \
|
||||
virtual String typeName() const { return _(#funname)_("_rule"); } \
|
||||
protected: \
|
||||
virtual ScriptValueP do_eval(Context& ctx, bool) const; \
|
||||
private: \
|
||||
type1 name1; \
|
||||
}; \
|
||||
SCRIPT_FUNCTION(funname##_rule) { \
|
||||
SCRIPT_PARAM_N(type1, str1, name1); \
|
||||
return intrusive(new ScriptRule_##funname(name1)); \
|
||||
} \
|
||||
SCRIPT_FUNCTION(funname) { \
|
||||
SCRIPT_PARAM_N(type1, str1, name1); \
|
||||
return ScriptRule_##funname(name1).eval(ctx); \
|
||||
} \
|
||||
ScriptValueP ScriptRule_##funname::do_eval(Context& ctx, bool) const
|
||||
#define SCRIPT_RULE_1_N(funname, type1, str1, name1) \
|
||||
class ScriptRule_##funname: public ScriptValue { \
|
||||
public: \
|
||||
inline ScriptRule_##funname(const type1& name1) : name1(name1) {} \
|
||||
virtual ScriptType type() const { return SCRIPT_FUNCTION; } \
|
||||
virtual String typeName() const { return _(#funname)_("_rule"); } \
|
||||
protected: \
|
||||
virtual ScriptValueP do_eval(Context& ctx, bool) const; \
|
||||
private: \
|
||||
type1 name1; \
|
||||
}; \
|
||||
SCRIPT_FUNCTION(funname##_rule) { \
|
||||
SCRIPT_PARAM_N(type1, str1, name1); \
|
||||
return intrusive(new ScriptRule_##funname(name1)); \
|
||||
} \
|
||||
SCRIPT_FUNCTION(funname) { \
|
||||
SCRIPT_PARAM_N(type1, str1, name1); \
|
||||
return ScriptRule_##funname(name1).eval(ctx); \
|
||||
} \
|
||||
ScriptValueP ScriptRule_##funname::do_eval(Context& ctx, bool) const
|
||||
|
||||
/// Utility for defining a script rule with two parameters
|
||||
#define SCRIPT_RULE_2(funname, type1, name1, type2, name2) \
|
||||
#define SCRIPT_RULE_2(funname, type1, name1, type2, name2) \
|
||||
SCRIPT_RULE_2_N(funname, type1, _(#name1), name1, type2, _(#name2), name2)
|
||||
#define SCRIPT_RULE_2_C(funname, type1, name1, type2, name2) \
|
||||
#define SCRIPT_RULE_2_C(funname, type1, name1, type2, name2) \
|
||||
SCRIPT_RULE_2_N(funname, type1, SCRIPT_VAR_ ## name1, name1, type2, SCRIPT_VAR_ ## name2, name2)
|
||||
/// Utility for defining a script rule with two named parameters
|
||||
#define SCRIPT_RULE_2_N(funname, type1, str1, name1, type2, str2, name2) \
|
||||
SCRIPT_RULE_2_N_AUX(funname, type1, str1, name1, type2, str2, name2, ;, ;)
|
||||
#define SCRIPT_RULE_2_N(funname, type1, str1, name1, type2, str2, name2) \
|
||||
SCRIPT_RULE_2_N_AUX(funname, type1, str1, name1, type2, str2, name2, ;, ;)
|
||||
/// Utility for defining a script rule with two named parameters, with dependencies
|
||||
#define SCRIPT_RULE_2_N_DEP(funname, type1, str1, name1, type2, str2, name2) \
|
||||
SCRIPT_RULE_2_N_AUX( funname, type1, str1, name1, type2, str2, name2, \
|
||||
virtual ScriptValueP dependencies(Context&, const Dependency&) const;, \
|
||||
SCRIPT_FUNCTION_DEPENDENCIES(funname) { \
|
||||
SCRIPT_PARAM_N(type1, str1, name1); \
|
||||
SCRIPT_PARAM_N(type2, str2, name2); \
|
||||
return ScriptRule_##funname(name1, name2).dependencies(ctx, dep); \
|
||||
})
|
||||
#define SCRIPT_RULE_2_N_DEP(funname, type1, str1, name1, type2, str2, name2) \
|
||||
SCRIPT_RULE_2_N_AUX( funname, type1, str1, name1, type2, str2, name2, \
|
||||
virtual ScriptValueP dependencies(Context&, const Dependency&) const;, \
|
||||
SCRIPT_FUNCTION_DEPENDENCIES(funname) { \
|
||||
SCRIPT_PARAM_N(type1, str1, name1); \
|
||||
SCRIPT_PARAM_N(type2, str2, name2); \
|
||||
return ScriptRule_##funname(name1, name2).dependencies(ctx, dep); \
|
||||
})
|
||||
|
||||
#define SCRIPT_RULE_2_N_AUX(funname, type1, str1, name1, type2, str2, name2, dep, more) \
|
||||
class ScriptRule_##funname: public ScriptValue { \
|
||||
public: \
|
||||
inline ScriptRule_##funname(const type1& name1, const type2& name2) \
|
||||
: name1(name1), name2(name2) {} \
|
||||
virtual ScriptType type() const { return SCRIPT_FUNCTION; } \
|
||||
virtual String typeName() const { return _(#funname)_("_rule"); } \
|
||||
dep \
|
||||
protected: \
|
||||
virtual ScriptValueP do_eval(Context& ctx, bool) const; \
|
||||
private: \
|
||||
type1 name1; \
|
||||
type2 name2; \
|
||||
}; \
|
||||
SCRIPT_FUNCTION(funname##_rule) { \
|
||||
SCRIPT_PARAM_N(type1, str1, name1); \
|
||||
SCRIPT_PARAM_N(type2, str2, name2); \
|
||||
return intrusive(new ScriptRule_##funname(name1, name2)); \
|
||||
} \
|
||||
SCRIPT_FUNCTION_AUX(funname, dep) { \
|
||||
SCRIPT_PARAM_N(type1, str1, name1); \
|
||||
SCRIPT_PARAM_N(type2, str2, name2); \
|
||||
return ScriptRule_##funname(name1, name2).eval(ctx); \
|
||||
} \
|
||||
more \
|
||||
ScriptValueP ScriptRule_##funname::do_eval(Context& ctx, bool) const
|
||||
class ScriptRule_##funname: public ScriptValue { \
|
||||
public: \
|
||||
inline ScriptRule_##funname(const type1& name1, const type2& name2) \
|
||||
: name1(name1), name2(name2) {} \
|
||||
virtual ScriptType type() const { return SCRIPT_FUNCTION; } \
|
||||
virtual String typeName() const { return _(#funname)_("_rule"); } \
|
||||
dep \
|
||||
protected: \
|
||||
virtual ScriptValueP do_eval(Context& ctx, bool) const; \
|
||||
private: \
|
||||
type1 name1; \
|
||||
type2 name2; \
|
||||
}; \
|
||||
SCRIPT_FUNCTION(funname##_rule) { \
|
||||
SCRIPT_PARAM_N(type1, str1, name1); \
|
||||
SCRIPT_PARAM_N(type2, str2, name2); \
|
||||
return intrusive(new ScriptRule_##funname(name1, name2)); \
|
||||
} \
|
||||
SCRIPT_FUNCTION_AUX(funname, dep) { \
|
||||
SCRIPT_PARAM_N(type1, str1, name1); \
|
||||
SCRIPT_PARAM_N(type2, str2, name2); \
|
||||
return ScriptRule_##funname(name1, name2).eval(ctx); \
|
||||
} \
|
||||
more \
|
||||
ScriptValueP ScriptRule_##funname::do_eval(Context& ctx, bool) const
|
||||
|
||||
#define SCRIPT_RULE_2_DEPENDENCIES(name) \
|
||||
ScriptValueP ScriptRule_##name::dependencies(Context& ctx, const Dependency& dep) const
|
||||
#define SCRIPT_RULE_2_DEPENDENCIES(name) \
|
||||
ScriptValueP ScriptRule_##name::dependencies(Context& ctx, const Dependency& dep) const
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
|
||||
Reference in New Issue
Block a user