Commit 6dfa6a4f authored by twanvl's avatar twanvl

The DECLARE_TYPEOF(()) calls don't work in MSVC, I changed it to use a COMMA macro instead of ,

If this doesn't work in GCC, the COMMA definition could be made only for MSVC, then GCC sees DECLARE_TYPEOF(map<int COMMA string>). GCC doesn't need DECLARE_TYPEOF anyway.

Keyword expansion now works, still todo:
 - marking parameters, e.g. "Cycling 2W" -> "Cycling <param-mana>2W</param-mana>"
 - user interface for toggling reminder text
 - user interface for keywords
parent d1e156eb
...@@ -260,8 +260,11 @@ error: ...@@ -260,8 +260,11 @@ error:
unable to store file: Error while saving, unable to store file unable to store file: Error while saving, unable to store file
# Script stuff # Script stuff
collection has no member: Collection has no member '%s' has no member: %s has no member '%s'
object has no member: Object has no member '%s' can't convert: Can't convert from %s to %s
has no member value: String "%s" has no member '%s'
can't convert value: Can't convert "%s" from %s to %s
unsupported format: Invalid string format: '%s'
# Image stuff # Image stuff
coordinates for blending overlap: Coordinates for blending overlap coordinates for blending overlap: Coordinates for blending overlap
...@@ -287,9 +290,15 @@ error: ...@@ -287,9 +290,15 @@ error:
############################################################## Types used in scripts ############################################################## Types used in scripts
type: type:
real: Real number function: function
integer: Integer number collection: collection
string: String object: object
real: real number
integer: integer number
string: string
boolean: boolean
color: color
nil: nothing
############################################################## Magic ############################################################## Magic
game: game:
......
...@@ -161,18 +161,22 @@ init script: ...@@ -161,18 +161,22 @@ init script:
# after: ")", # after: ")",
# fix_english: true # fix_english: true
# ) + # ) +
# step 3 : expand shortcut words ~ and CARDNAME expand_keywords_rule(
default_expand: { set.automatic_reminder_text == "yes" },
combine: { "{keyword}<atom-reminder><i> ({reminder})</i></atom-reminder>" }
) +
# step 3a : expand shortcut words ~ and CARDNAME
replace_rule( replace_rule(
match: "~|~THIS~|CARDNAME", match: "~|~THIS~|CARDNAME",
in_context: "(^|[[:space:]]|\\()<match>", # TODO: Allow any punctuation before in_context: "(^|[[:space:]]|\\()<match>", # TODO: Allow any punctuation before
replace: "<atom-cardname></atom-cardname>" replace: "<atom-cardname></atom-cardname>"
) + ) +
# step 4 : fill in atom fields # step 3b : fill in atom fields
tag_contents_rule( tag_contents_rule(
tag: "<atom-cardname>", tag: "<atom-cardname>",
contents: { if card_name=="" then "CARDNAME" else card_name } contents: { if card_name=="" then "CARDNAME" else card_name }
) + ) +
# step 4.5 : explict non mana symbols # step 4 : explict non mana symbols
replace_rule( replace_rule(
match: "\\][STXYZWUBRG0-9/|]+\\[", match: "\\][STXYZWUBRG0-9/|]+\\[",
replace: {"<nosym>" + mana_filter_t() + "</nosym>"} ) + replace: {"<nosym>" + mana_filter_t() + "</nosym>"} ) +
...@@ -802,7 +806,7 @@ keyword parameter type: ...@@ -802,7 +806,7 @@ keyword parameter type:
keyword parameter type: keyword parameter type:
name: cost name: cost
#insert as: word #insert as: word
match: ***:[XYZ0-9WUBRGS/]+|[^(.,\n]|([XYZ0-9WUBRGS/]+,)?[^(.,\n]* match: [XYZ0-9WUBRGS/]+|[^(.,\n]|([XYZ0-9WUBRGS/]+,)?[^(.,\n]*
keyword parameter type: keyword parameter type:
name: number name: number
match: [XYZ0-9]+ match: [XYZ0-9]+
...@@ -821,11 +825,11 @@ keyword parameter type: ...@@ -821,11 +825,11 @@ keyword parameter type:
keyword parameter type: keyword parameter type:
name: action name: action
#insert as: word #insert as: word
match: ***:[^(.,\n]+ match: [^(.,\n]+
keyword parameter type: keyword parameter type:
name: name name: name
#insert as: word #insert as: word
match: ***:[^(.,\n]+ match: [^(.,\n]+
############################# All Magic keywords ############################# All Magic keywords
# By JrEye and Neko_Asakami # By JrEye and Neko_Asakami
...@@ -851,7 +855,7 @@ keyword: ...@@ -851,7 +855,7 @@ keyword:
keyword: Cycling keyword: Cycling
separator: whitespace [ ] separator: whitespace [ ]
parameter: cost parameter: cost
reminder: <param>, Discard this card: Draw a card. reminder: {param1}, Discard this card: Draw a card.
keyword: keyword:
keyword: Trample keyword: Trample
reminder: If this creature would deal enough combat damage to its blockers to destroy them, you may have it deal the rest of its damage to defending player. reminder: If this creature would deal enough combat damage to its blockers to destroy them, you may have it deal the rest of its damage to defending player.
......
...@@ -9,8 +9,8 @@ ...@@ -9,8 +9,8 @@
#include <data/action/symbol.hpp> #include <data/action/symbol.hpp>
#include <data/action/symbol_part.hpp> #include <data/action/symbol_part.hpp>
DECLARE_TYPEOF_COLLECTION((pair<SymbolPartP,SymbolPartCombine>)); DECLARE_TYPEOF_COLLECTION(pair<SymbolPartP COMMA SymbolPartCombine>);
DECLARE_TYPEOF_COLLECTION((pair<SymbolPartP,size_t >)); DECLARE_TYPEOF_COLLECTION(pair<SymbolPartP COMMA size_t >);
DECLARE_TYPEOF_COLLECTION(SymbolPartP); DECLARE_TYPEOF_COLLECTION(SymbolPartP);
DECLARE_TYPEOF_COLLECTION(ControlPointP); DECLARE_TYPEOF_COLLECTION(ControlPointP);
...@@ -204,11 +204,11 @@ void SymbolPartScaleAction::update() { ...@@ -204,11 +204,11 @@ void SymbolPartScaleAction::update() {
// the size after the move // the size after the move
newMin = newRealMin; newSize = newRealSize; newMin = newRealMin; newSize = newRealSize;
if (constrain && scaleX != 0 && scaleY != 0) { if (constrain && scaleX != 0 && scaleY != 0) {
// TODO : snapping
Vector2D scale = newSize.div(tmpSize); Vector2D scale = newSize.div(tmpSize);
scale = constrain_vector(scale, true, true); scale = constrain_vector(scale, true, true);
newSize = tmpSize.mul(scale); newSize = tmpSize.mul(scale);
newMin += (newRealSize - newSize).mul(Vector2D(scaleX == -1 ? 1 : 0, scaleY == -1 ? 1 : 0)); newMin += (newRealSize - newSize).mul(Vector2D(scaleX == -1 ? 1 : 0, scaleY == -1 ? 1 : 0));
// TODO : snapping
} else if (snap >= 0) { } else if (snap >= 0) {
if (scaleX + scaleY < 0) { if (scaleX + scaleY < 0) {
newMin = snap_vector(newMin, snap); newMin = snap_vector(newMin, snap);
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#include <util/reflect.hpp> #include <util/reflect.hpp>
DECLARE_TYPEOF_COLLECTION(FieldP); DECLARE_TYPEOF_COLLECTION(FieldP);
DECLARE_TYPEOF_NO_REV((IndexMap<FieldP,ValueP>)); DECLARE_TYPEOF_NO_REV(IndexMap<FieldP COMMA ValueP>);
// ----------------------------------------------------------------------------- : Card // ----------------------------------------------------------------------------- : Card
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
#include <util/io/package.hpp> #include <util/io/package.hpp>
DECLARE_TYPEOF_COLLECTION(ChoiceField::ChoiceP); DECLARE_TYPEOF_COLLECTION(ChoiceField::ChoiceP);
DECLARE_TYPEOF((map<String,ScriptableImage>)); DECLARE_TYPEOF(map<String COMMA ScriptableImage>);
// ----------------------------------------------------------------------------- : ChoiceField // ----------------------------------------------------------------------------- : ChoiceField
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <data/format/image_to_symbol.hpp> #include <data/format/image_to_symbol.hpp>
#include <gfx/bezier.hpp> #include <gfx/bezier.hpp>
#include <util/error.hpp> #include <util/error.hpp>
#include <util/platform.hpp>
DECLARE_TYPEOF_COLLECTION(ControlPointP); DECLARE_TYPEOF_COLLECTION(ControlPointP);
DECLARE_TYPEOF_COLLECTION(SymbolPartP); DECLARE_TYPEOF_COLLECTION(SymbolPartP);
...@@ -99,7 +100,7 @@ bool is_mse1_symbol(const Image& img) { ...@@ -99,7 +100,7 @@ bool is_mse1_symbol(const Image& img) {
int r = *d++; int r = *d++;
int g = *d++; int g = *d++;
int b = *d++; int b = *d++;
delta += fabs(r - b) + fabs(r - g) + fabs(b - g); delta += abs(r - b) + abs(r - g) + abs(b - g);
} }
} }
if (delta > 5000) return false; // not black & white enough if (delta > 5000) return false; // not black & white enough
...@@ -357,7 +358,7 @@ void straighten(SymbolPart& part) { ...@@ -357,7 +358,7 @@ void straighten(SymbolPart& part) {
Vector2D bb = next.delta_before.normalized(); Vector2D bb = next.delta_before.normalized();
// if the area beneath the polygon formed by the handles is small // if the area beneath the polygon formed by the handles is small
// then it is a straight line // then it is a straight line
double cpDot = fabs(aa.cross(ab)) + fabs(bb.cross(ab)); double cpDot = abs(aa.cross(ab)) + abs(bb.cross(ab));
if (cpDot < treshold) { if (cpDot < treshold) {
cur.segment_after = next.segment_before = SEGMENT_LINE; cur.segment_after = next.segment_before = SEGMENT_LINE;
cur.delta_after = next.delta_before = Vector2D(); cur.delta_after = next.delta_before = Vector2D();
...@@ -374,7 +375,7 @@ void merge_lines(SymbolPart& part) { ...@@ -374,7 +375,7 @@ void merge_lines(SymbolPart& part) {
Vector2D a = part.getPoint(i-1)->pos, b = cur.pos, c = part.getPoint(i+1)->pos; Vector2D a = part.getPoint(i-1)->pos, b = cur.pos, c = part.getPoint(i+1)->pos;
Vector2D ab = (a-b).normalized(); Vector2D ab = (a-b).normalized();
Vector2D bc = (b-c).normalized(); Vector2D bc = (b-c).normalized();
double angle_len = fabs( atan2(ab.x,ab.y) - atan2(bc.x,bc.y)) * (a-c).lengthSqr(); double angle_len = abs( atan2(ab.x,ab.y) - atan2(bc.x,bc.y)) * (a-c).lengthSqr();
bool keep = angle_len >= .0001; bool keep = angle_len >= .0001;
if (!keep) { if (!keep) {
part.points.erase(part.points.begin() + i); part.points.erase(part.points.begin() + i);
......
This diff is collapsed.
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
DECLARE_POINTER_TYPE(KeywordParam); DECLARE_POINTER_TYPE(KeywordParam);
DECLARE_POINTER_TYPE(KeywordExpansion); DECLARE_POINTER_TYPE(KeywordExpansion);
DECLARE_POINTER_TYPE(KeywordMode); DECLARE_POINTER_TYPE(KeywordMode);
DECLARE_POINTER_TYPE(Keyword);
class KeywordTrie;
// ----------------------------------------------------------------------------- : Keyword components // ----------------------------------------------------------------------------- : Keyword components
...@@ -24,8 +26,7 @@ class KeywordParam { ...@@ -24,8 +26,7 @@ class KeywordParam {
public: public:
String name; ///< Name of the parameter type String name; ///< Name of the parameter type
String description; ///< Description of the type String description; ///< Description of the type
String match; ///< Uncompiled regex String match; ///< Regular expression to match
wxRegEx matchRe; ///< Regular expression to match
OptionalScript script; ///< Transformation of the value for showing in the reminder text OptionalScript script; ///< Transformation of the value for showing in the reminder text
String example; ///< Example for preview dialog String example; ///< Example for preview dialog
...@@ -49,9 +50,18 @@ class KeywordExpansion { ...@@ -49,9 +50,18 @@ class KeywordExpansion {
public: public:
String match; ///< String to match, <param> tags are used for parameters String match; ///< String to match, <param> tags are used for parameters
vector<KeywordParamP> parameters; ///< The types of parameters vector<KeywordParamP> parameters; ///< The types of parameters
// wxRegEx splitter; ///< Regular expression to split/match the components, automatically generated wxRegEx matchRe; ///< Regular expression to match and split parameters, automatically generated
StringScript reminder; ///< Reminder text of the keyword StringScript reminder; ///< Reminder text of the keyword
String mode; ///< Mode of use, can be used by scripts (only gives the name). Default is the mode of the Keyword. String mode; ///< Mode of use, can be used by scripts (only gives the name)
// . Default is the mode of the Keyword.
String regex;//TODO REMOVE
/// Prepare the expansion: (re)generate matchRe and the list of parameters.
/** Throws when there is an error in the input
* @param param_types A list of all parameter types.
* @param force Re-prepare even if the regex&parameters are okay
*/
void prepare(const vector<KeywordParamP>& param_types, bool force = false);
DECLARE_REFLECTION(); DECLARE_REFLECTION();
}; };
...@@ -64,7 +74,7 @@ class Keyword { ...@@ -64,7 +74,7 @@ class Keyword {
String keyword; ///< The keyword String keyword; ///< The keyword
vector<KeywordExpansionP> expansions; ///< Expansions, i.e. ways to use this keyword vector<KeywordExpansionP> expansions; ///< Expansions, i.e. ways to use this keyword
String rules; ///< Rules/explanation String rules; ///< Rules/explanation
String mode; ///< Mode of use, can be used by scripts (only gives the name) // String mode; ///< Mode of use, can be used by scripts (only gives the name)
DECLARE_REFLECTION(); DECLARE_REFLECTION();
}; };
...@@ -72,21 +82,41 @@ class Keyword { ...@@ -72,21 +82,41 @@ class Keyword {
// ----------------------------------------------------------------------------- : Using keywords // ----------------------------------------------------------------------------- : Using keywords
/// A class that allows for fast matching of keywords /// A database of keywords to allow for fast matching
class KeywordDatabase;
DECLARE_POINTER_TYPE(KeywordDatabase);
/// Create a new keyword database
KeywordDatabaseP new_keyword_database();
/// Add a keyword to a KeywordDatabase
/** NOTE: keywords may not be altered after they are added to the database, /** NOTE: keywords may not be altered after they are added to the database,
* The database should be rebuild. * The database should be rebuild.
*/ */
void add_keyword(KeywordDatabase& db, const Keyword& kw); class KeywordDatabase {
public:
/// Expand/update all keywords in the given string KeywordDatabase();
String expand_keywords(const KeywordDatabase& db, const String& text); ~KeywordDatabase();
/// Add a list of keywords to be matched
void add(const vector<KeywordP>&);
/// Add a keyword to be matched
void add(const Keyword&);
/// Add an expansion of a keyword to be matched
void add(const KeywordExpansion&);
/// Prepare the parameters and match regex for a list of keywords
static void prepare_parameters(const vector<KeywordParamP>&, const vector<KeywordP>&);
static void prepare_parameters(const vector<KeywordParamP>&, const Keyword&);
/// Clear the database
void clear();
/// Is the database empty?
inline bool empty() const { return !root; }
/// Expand/update all keywords in the given string.
/** @param expand_default script function indicating whether reminder text should be shown by default
* @param combine_script script function to combine keyword and reminder text in some way
* @param ctx context for evaluation of scripts
*/
String expand(const String& text, const ScriptValueP& expand_default, const ScriptValueP& combine_script, Context& ctx) const;
private:
KeywordTrie* root; ///< Data structure for finding keywords
};
// ----------------------------------------------------------------------------- : EOF // ----------------------------------------------------------------------------- : EOF
#endif #endif
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#include <wx/sstream.h> #include <wx/sstream.h>
DECLARE_TYPEOF_COLLECTION(CardP); DECLARE_TYPEOF_COLLECTION(CardP);
DECLARE_TYPEOF_NO_REV((IndexMap<FieldP,ValueP>)); DECLARE_TYPEOF_NO_REV(IndexMap<FieldP COMMA ValueP>);
// ----------------------------------------------------------------------------- : Set // ----------------------------------------------------------------------------- : Set
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <util/action_stack.hpp> #include <util/action_stack.hpp>
#include <util/io/package.hpp> #include <util/io/package.hpp>
#include <data/field.hpp> // for Set::value #include <data/field.hpp> // for Set::value
#include <data/keyword.hpp>
#include <boost/scoped_ptr.hpp> #include <boost/scoped_ptr.hpp>
DECLARE_POINTER_TYPE(Card); DECLARE_POINTER_TYPE(Card);
...@@ -57,6 +58,7 @@ class Set : public Packaged { ...@@ -57,6 +58,7 @@ class Set : public Packaged {
vector<KeywordP> keywords; ///< Additional keywords used in this set vector<KeywordP> keywords; ///< Additional keywords used in this set
String apprentice_code; ///< Code to use for apprentice (Magic only) String apprentice_code; ///< Code to use for apprentice (Magic only)
ActionStack actions; ///< Actions performed on this set and the cards in it ActionStack actions; ///< Actions performed on this set and the cards in it
KeywordDatabase keyword_db; ///< Database for matching keywords, must be cleared when keywords change
/// A context for performing scripts /// A context for performing scripts
/** Should only be used from the main thread! */ /** Should only be used from the main thread! */
......
...@@ -26,8 +26,8 @@ ...@@ -26,8 +26,8 @@
DECLARE_TYPEOF_COLLECTION(CardP); DECLARE_TYPEOF_COLLECTION(CardP);
DECLARE_TYPEOF_COLLECTION(FieldP); DECLARE_TYPEOF_COLLECTION(FieldP);
DECLARE_POINTER_TYPE(ChoiceValue); DECLARE_POINTER_TYPE(ChoiceValue);
DECLARE_TYPEOF((map<int,FieldP>)); DECLARE_TYPEOF(map<int COMMA FieldP>);
DECLARE_TYPEOF_NO_REV((IndexMap<FieldP,StyleP>)); DECLARE_TYPEOF_NO_REV(IndexMap<FieldP COMMA StyleP>);
// ----------------------------------------------------------------------------- : Events // ----------------------------------------------------------------------------- : Events
......
...@@ -15,7 +15,7 @@ DECLARE_TYPEOF_COLLECTION(GraphAxisP); ...@@ -15,7 +15,7 @@ DECLARE_TYPEOF_COLLECTION(GraphAxisP);
DECLARE_TYPEOF_COLLECTION(GraphElementP); DECLARE_TYPEOF_COLLECTION(GraphElementP);
DECLARE_TYPEOF_COLLECTION(GraphGroup); DECLARE_TYPEOF_COLLECTION(GraphGroup);
DECLARE_TYPEOF_COLLECTION(int); DECLARE_TYPEOF_COLLECTION(int);
DECLARE_TYPEOF((map<String,UInt>)); DECLARE_TYPEOF(map<String COMMA UInt>);
// ----------------------------------------------------------------------------- : Events // ----------------------------------------------------------------------------- : Events
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
#include <data/stylesheet.hpp> #include <data/stylesheet.hpp>
DECLARE_TYPEOF_COLLECTION(ValueViewerP); DECLARE_TYPEOF_COLLECTION(ValueViewerP);
DECLARE_TYPEOF_NO_REV((IndexMap<FieldP,StyleP>)); DECLARE_TYPEOF_NO_REV(IndexMap<FieldP COMMA StyleP>);
// ----------------------------------------------------------------------------- : NativeLookEditor // ----------------------------------------------------------------------------- : NativeLookEditor
......
...@@ -570,7 +570,7 @@ void TextValueEditor::fixSelection(IndexType t, Movement dir) { ...@@ -570,7 +570,7 @@ void TextValueEditor::fixSelection(IndexType t, Movement dir) {
// start and end must be on the same side of separators // start and end must be on the same side of separators
size_t seppos = val.find(_("<sep")); size_t seppos = val.find(_("<sep"));
while (seppos != String::npos) { while (seppos != String::npos) {
size_t sepend = skip_tag(val,match_close_tag(val, seppos)); size_t sepend = match_close_tag_end(val, seppos);
if (selection_start_i <= seppos && selection_end_i > seppos) { if (selection_start_i <= seppos && selection_end_i > seppos) {
// not on same side, move selection end before sep // not on same side, move selection end before sep
selection_end = index_to_cursor(val, seppos, dir); selection_end = index_to_cursor(val, seppos, dir);
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include <gui/util.hpp> // clearDC #include <gui/util.hpp> // clearDC
DECLARE_TYPEOF_COLLECTION(ValueViewerP); DECLARE_TYPEOF_COLLECTION(ValueViewerP);
DECLARE_TYPEOF_NO_REV((IndexMap<FieldP,StyleP>)); DECLARE_TYPEOF_NO_REV(IndexMap<FieldP COMMA StyleP>);
// ----------------------------------------------------------------------------- : DataViewer // ----------------------------------------------------------------------------- : DataViewer
......
...@@ -110,7 +110,7 @@ bool_no IMAGE "../common/bool_no.png" ...@@ -110,7 +110,7 @@ bool_no IMAGE "../common/bool_no.png"
//help_page BITMAP "help_page.png" //help_page BITMAP "help_page.png"
about IMAGE "../common/about.png" about IMAGE "../common/about.png"
two_beta IMAGE "../common/two_beta.png" two_beta IMAGE "../common/two_beta.png"
btn_normal IMAGE "../common/btn_normal.png" btn_normal IMAGE "../common/btn_normal.png"
btn_hover IMAGE "../common/btn_hover.png" btn_hover IMAGE "../common/btn_hover.png"
btn_focus IMAGE "../common/btn_focus.png" btn_focus IMAGE "../common/btn_focus.png"
...@@ -155,7 +155,7 @@ FILETYPE VFT_APP ...@@ -155,7 +155,7 @@ FILETYPE VFT_APP
VALUE "License", "GNU General Public License 2 or later; This is free software, and you are welcome to redistribute it under certain conditions; See the help file for details" VALUE "License", "GNU General Public License 2 or later; This is free software, and you are welcome to redistribute it under certain conditions; See the help file for details"
VALUE "FileDescription", "Magic Set Editor" VALUE "FileDescription", "Magic Set Editor"
VALUE "InternalName", "mse2/8" VALUE "InternalName", "mse2/8"
VALUE "LegalCopyright", " 2001-2006 Twan van Laarhoven" VALUE "LegalCopyright", " 2001-2006 Twan van Laarhoven"
VALUE "ProductName", "Magic Set Editor" VALUE "ProductName", "Magic Set Editor"
} }
} }
......
...@@ -215,7 +215,7 @@ void instrUnary (UnaryInstructionType i, ScriptValueP& a) { ...@@ -215,7 +215,7 @@ void instrUnary (UnaryInstructionType i, ScriptValueP& a) {
a = toScript(-(int)*a); a = toScript(-(int)*a);
break; break;
case I_NOT: case I_NOT:
a = toScript(!(int)*a); a = toScript(!(bool)*a);
break; break;
} }
} }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <util/tagged_string.hpp> #include <util/tagged_string.hpp>
#include <data/set.hpp> #include <data/set.hpp>
#include <data/game.hpp> #include <data/game.hpp>
#include <data/keyword.hpp>
#include <data/field/text.hpp> #include <data/field/text.hpp>
#include <wx/regex.h> #include <wx/regex.h>
...@@ -265,7 +266,7 @@ String spec_sort(const String& spec, const String& input) { ...@@ -265,7 +266,7 @@ String spec_sort(const String& spec, const String& input) {
ScriptValueP ScriptRule_##funname::eval(Context& ctx) const ScriptValueP ScriptRule_##funname::eval(Context& ctx) const
// Utility for defining a script rule with two parameters // Utility for defining a script rule with two parameters
#define SCRIPT_RULE_2(funname, type1, name1, type2, name2) \ #define SCRIPT_RULE_2_N(funname, type1, str1, name1, type2, str2, name2) \
class ScriptRule_##funname: public ScriptValue { \ class ScriptRule_##funname: public ScriptValue { \
public: \ public: \
inline ScriptRule_##funname(const type1& name1, const type2& name2) \ inline ScriptRule_##funname(const type1& name1, const type2& name2) \
...@@ -278,16 +279,18 @@ String spec_sort(const String& spec, const String& input) { ...@@ -278,16 +279,18 @@ String spec_sort(const String& spec, const String& input) {
type2 name2; \ type2 name2; \
}; \ }; \
SCRIPT_FUNCTION(funname##_rule) { \ SCRIPT_FUNCTION(funname##_rule) { \
SCRIPT_PARAM(type1, name1); \ SCRIPT_PARAM_N(type1, str1, name1); \
SCRIPT_PARAM(type2, name2); \ SCRIPT_PARAM_N(type2, str2, name2); \
return new_intrusive2<ScriptRule_##funname>(name1, name2); \ return new_intrusive2<ScriptRule_##funname>(name1, name2); \
} \ } \
SCRIPT_FUNCTION(funname) { \ SCRIPT_FUNCTION(funname) { \
SCRIPT_PARAM(type1, name1); \ SCRIPT_PARAM_N(type1, str1, name1); \
SCRIPT_PARAM(type2, name2); \ SCRIPT_PARAM_N(type2, str2, name2); \
return ScriptRule_##funname(name1, name2).eval(ctx); \ return ScriptRule_##funname(name1, name2).eval(ctx); \
} \ } \
ScriptValueP ScriptRule_##funname::eval(Context& ctx) const ScriptValueP ScriptRule_##funname::eval(Context& ctx) const
#define SCRIPT_RULE_2(funname, type1, name1, type2, name2) \
SCRIPT_RULE_2_N(funname, type1, _(#name1), name1, type2, _(#name2), name2)
// Create a rule for spec_sorting strings // Create a rule for spec_sorting strings
...@@ -339,10 +342,21 @@ SCRIPT_FUNCTION(contains) { ...@@ -339,10 +342,21 @@ SCRIPT_FUNCTION(contains) {
SCRIPT_RETURN(input.find(match) != String::npos); SCRIPT_RETURN(input.find(match) != String::npos);
} }
SCRIPT_FUNCTION(format) { SCRIPT_RULE_1(format, String, format) {
SCRIPT_PARAM(String, format); String fmt = _("%") + replace_all(format, _("%"), _(""));
SCRIPT_PARAM(String, input); // determine type expected by format string
SCRIPT_RETURN(format_string(_("%") + replace_all(format, _("%"), _("")), input)); if (format.find_first_of(_("DdIiOoXx")) != String.npos) {
SCRIPT_PARAM(int, input);
SCRIPT_RETURN(String::Format(fmt, input));
} else if (format.find_first_of(_("EeFfGg")) != String.npos) {
SCRIPT_PARAM(double, input);
SCRIPT_RETURN(String::Format(fmt, input));
} else if (format.find_first_of(_("Ss")) != String.npos) {
SCRIPT_PARAM(String, input);
SCRIPT_RETURN(format_string(fmt, input));
} else {
throw ScriptError(_ERROR_1_("unsupported format", format));
}
} }
// ----------------------------------------------------------------------------- : Tagged stuff // ----------------------------------------------------------------------------- : Tagged stuff
...@@ -381,7 +395,23 @@ SCRIPT_RULE_1(tag_remove, String, tag) { ...@@ -381,7 +395,23 @@ SCRIPT_RULE_1(tag_remove, String, tag) {
SCRIPT_RETURN(remove_tag(input, tag)); SCRIPT_RETURN(remove_tag(input, tag));
} }
// ----------------------------------------------------------------------------- : Vector stuff // ----------------------------------------------------------------------------- : Keywords
SCRIPT_RULE_2_N(expand_keywords, ScriptValueP, _("default expand"), default_expand,
ScriptValueP, _("combine"), combine) {
SCRIPT_PARAM(String, input);
SCRIPT_PARAM(Set*, set);
KeywordDatabase& db = set->keyword_db;
if (db.empty()) {
db.add(set->game->keywords);
db.add(set->keywords);
db.prepare_parameters(set->game->keyword_parameter_types, set->game->keywords);
db.prepare_parameters(set->game->keyword_parameter_types, set->keywords);
}
SCRIPT_RETURN(db.expand(input, default_expand, combine, ctx));
}
// ----------------------------------------------------------------------------- : Collection stuff
/// compare script values for equallity /// compare script values for equallity
bool equal(const ScriptValue& a, const ScriptValue& b) { bool equal(const ScriptValue& a, const ScriptValue& b) {
...@@ -497,7 +527,7 @@ SCRIPT_FUNCTION_DEP(combined_editor) { ...@@ -497,7 +527,7 @@ SCRIPT_FUNCTION_DEP(combined_editor) {
size_t pos = value.find(_("<sep")); size_t pos = value.find(_("<sep"));
while (pos != String::npos) { while (pos != String::npos) {
value_parts.push_back(value.substr(0, pos)); value_parts.push_back(value.substr(0, pos));
value = value.substr(min(skip_tag(value,match_close_tag(value,pos)), value.size())); value = value.substr(min(match_close_tag_end(value,pos), value.size()));
pos = value.find(_("<sep")); pos = value.find(_("<sep"));
} }
value_parts.push_back(value); value_parts.push_back(value);
...@@ -579,23 +609,25 @@ ScriptValueP ScriptBuildin_combined_editor::dependencies(Context& ctx, const Dep ...@@ -579,23 +609,25 @@ ScriptValueP ScriptBuildin_combined_editor::dependencies(Context& ctx, const Dep
// ----------------------------------------------------------------------------- : Initialize functions // ----------------------------------------------------------------------------- : Initialize functions
void init_script_functions(Context& ctx) { void init_script_functions(Context& ctx) {
ctx.setVariable(_("replace rule"), script_replace_rule); ctx.setVariable(_("replace rule"), script_replace_rule);
ctx.setVariable(_("filter rule"), script_filter_rule); ctx.setVariable(_("filter rule"), script_filter_rule);
ctx.setVariable(_("sort"), script_sort); ctx.setVariable(_("sort"), script_sort);
ctx.setVariable(_("sort rule"), script_sort_rule); ctx.setVariable(_("sort rule"), script_sort_rule);
ctx.setVariable(_("to upper"), script_to_upper); ctx.setVariable(_("to upper"), script_to_upper);
ctx.setVariable(_("to lower"), script_to_lower); ctx.setVariable(_("to lower"), script_to_lower);
ctx.setVariable(_("to title"), script_to_title); ctx.setVariable(_("to title"), script_to_title);
ctx.setVariable(_("substring"), script_substring); ctx.setVariable(_("substring"), script_substring);
ctx.setVariable(_("contains"), script_contains); ctx.setVariable(_("contains"), script_contains);
ctx.setVariable(_("format"), script_format); ctx.setVariable(_("format"), script_format);
ctx.setVariable(_("tag contents"), script_tag_contents); ctx.setVariable(_("tag contents"), script_tag_contents);
ctx.setVariable(_("remove tag"), script_tag_remove); ctx.setVariable(_("remove tag"), script_tag_remove);
ctx.setVariable(_("tag contents rule"), script_tag_contents_rule); ctx.setVariable(_("tag contents rule"), script_tag_contents_rule);
ctx.setVariable(_("tag remove rule"), script_tag_remove_rule); ctx.setVariable(_("tag remove rule"), script_tag_remove_rule);
ctx.setVariable(_("position"), script_position_of); ctx.setVariable(_("expand keywords rule"), script_expand_keywords_rule);
ctx.setVariable(_("number of items"), script_number_of_items); ctx.setVariable(_("expand keywords"), script_expand_keywords);
ctx.setVariable(_("forward editor"), script_combined_editor); ctx.setVariable(_("position"), script_position_of);
ctx.setVariable(_("combined editor"), script_combined_editor); ctx.setVariable(_("number of items"), script_number_of_items);
ctx.setVariable(_("forward editor"), script_combined_editor);
ctx.setVariable(_("combined editor"), script_combined_editor);
} }
...@@ -61,7 +61,7 @@ ScriptImageP to_script_image(const ScriptValueP& value) { ...@@ -61,7 +61,7 @@ ScriptImageP to_script_image(const ScriptValueP& value) {
/// Is the given image up to date? /// Is the given image up to date?
bool script_image_up_to_date(const ScriptValueP& value) { bool script_image_up_to_date(const ScriptValueP& value) {
if (value->type() == SCRIPT_INT) { if (value->type() == SCRIPT_INT) {
return (int)*value; // boolean up-to-dateness from parameter return (bool)*value; // boolean up-to-dateness from parameter
} else { } else {
return true; return true;
} }
......
...@@ -22,8 +22,8 @@ DECLARE_TYPEOF(Contexts); ...@@ -22,8 +22,8 @@ DECLARE_TYPEOF(Contexts);
DECLARE_TYPEOF_COLLECTION(CardP); DECLARE_TYPEOF_COLLECTION(CardP);
DECLARE_TYPEOF_COLLECTION(FieldP); DECLARE_TYPEOF_COLLECTION(FieldP);
DECLARE_TYPEOF_COLLECTION(Dependency); DECLARE_TYPEOF_COLLECTION(Dependency);
DECLARE_TYPEOF_NO_REV((IndexMap<FieldP,StyleP>)); DECLARE_TYPEOF_NO_REV(IndexMap<FieldP COMMA StyleP>);
DECLARE_TYPEOF_NO_REV((IndexMap<FieldP,ValueP>)); DECLARE_TYPEOF_NO_REV(IndexMap<FieldP COMMA ValueP>);
// initialize functions, from functions.cpp // initialize functions, from functions.cpp
void init_script_functions(Context& ctx); void init_script_functions(Context& ctx);
......
...@@ -53,13 +53,13 @@ class ScriptCollection : public ScriptValue { ...@@ -53,13 +53,13 @@ class ScriptCollection : public ScriptValue {
public: public:
inline ScriptCollection(const Collection* v) : value(v) {} inline ScriptCollection(const Collection* v) : value(v) {}
virtual ScriptType type() const { return SCRIPT_COLLECTION; } virtual ScriptType type() const { return SCRIPT_COLLECTION; }
virtual String typeName() const { return _("collection"); } virtual String typeName() const { return _TYPE_("collection"); }
virtual ScriptValueP getMember(const String& name) const { virtual ScriptValueP getMember(const String& name) const {
long index; long index;
if (name.ToLong(&index) && index >= 0 && (size_t)index < value->size()) { if (name.ToLong(&index) && index >= 0 && (size_t)index < value->size()) {
return toScript(value->at(index)); return toScript(value->at(index));
} else { } else {
throw ScriptError(_("Collection has no member ") + name); return ScriptValue::getMember(name);
} }
} }
virtual ScriptValueP makeIterator() const { virtual ScriptValueP makeIterator() const {
...@@ -79,7 +79,7 @@ ScriptValueP get_member(const map<String,V>& m, const String& name) { ...@@ -79,7 +79,7 @@ ScriptValueP get_member(const map<String,V>& m, const String& name) {
if (it != m.end()) { if (it != m.end()) {
return toScript(it->second); return toScript(it->second);
} else { } else {
throw ScriptError(_ERROR_1_("collection has no member", name)); throw ScriptError(_ERROR_2_("has no member", _TYPE_("collection"), name));
} }
} }
...@@ -89,7 +89,7 @@ ScriptValueP get_member(const IndexMap<K,V>& m, const String& name) { ...@@ -89,7 +89,7 @@ ScriptValueP get_member(const IndexMap<K,V>& m, const String& name) {
if (it != m.end()) { if (it != m.end()) {
return toScript(*it); return toScript(*it);
} else { } else {
throw ScriptError(_ERROR_1_("collection has no member", name)); throw ScriptError(_ERROR_2_("has no member", _TYPE_("collection"), name));
} }
} }
...@@ -99,7 +99,7 @@ class ScriptMap : public ScriptValue { ...@@ -99,7 +99,7 @@ class ScriptMap : public ScriptValue {
public: public:
inline ScriptMap(const Collection* v) : value(v) {} inline ScriptMap(const Collection* v) : value(v) {}
virtual ScriptType type() const { return SCRIPT_COLLECTION; } virtual ScriptType type() const { return SCRIPT_COLLECTION; }
virtual String typeName() const { return _("collection"); } virtual String typeName() const { return _TYPE_("collection"); }
virtual ScriptValueP getMember(const String& name) const { virtual ScriptValueP getMember(const String& name) const {
return get_member(*value, name); return get_member(*value, name);
} }
...@@ -132,7 +132,7 @@ class ScriptObject : public ScriptValue { ...@@ -132,7 +132,7 @@ class ScriptObject : public ScriptValue {
public: public:
inline ScriptObject(const T& v) : value(v) {} inline ScriptObject(const T& v) : value(v) {}
virtual ScriptType type() const { return SCRIPT_OBJECT; } virtual ScriptType type() const { return SCRIPT_OBJECT; }
virtual String typeName() const { return _("object"); } virtual String typeName() const { return _TYPE_("object"); }
virtual operator String() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator String(); } virtual operator String() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator String(); }
virtual operator double() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator double(); } virtual operator double() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator double(); }
virtual operator int() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator int(); } virtual operator int() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator int(); }
...@@ -147,7 +147,7 @@ class ScriptObject : public ScriptValue { ...@@ -147,7 +147,7 @@ class ScriptObject : public ScriptValue {
if (d) { if (d) {
return d->getMember(name); return d->getMember(name);
} else { } else {
throw ScriptError(_ERROR_1_("object has no member", name)); throw ScriptValue::getMember(name);
} }
} }
} }
...@@ -239,7 +239,9 @@ inline ScriptValueP toScript(const Defaultable<T>& v) { return toScript(v()); } ...@@ -239,7 +239,9 @@ inline ScriptValueP toScript(const Defaultable<T>& v) { return toScript(v()); }
* Throws an error if the parameter is not found. * Throws an error if the parameter is not found.
*/ */
#define SCRIPT_PARAM(Type, name) \ #define SCRIPT_PARAM(Type, name) \
Type name = getParam<Type>(ctx.getVariable(_(#name))) SCRIPT_PARAM_N(Type, _(#name), name)
#define SCRIPT_PARAM_N(Type, str, name) \
Type name = getParam<Type>(ctx.getVariable(str))
template <typename T> template <typename T>
inline T getParam (const ScriptValueP& value) { inline T getParam (const ScriptValueP& value) {
......
...@@ -15,14 +15,14 @@ ...@@ -15,14 +15,14 @@
// Base cases // Base cases
ScriptValue::operator String() const { return _("[[") + typeName() + _("]]"); } ScriptValue::operator String() const { return _("[[") + typeName() + _("]]"); }
ScriptValue::operator int() const { throw ScriptError( _("Can't convert from ")+typeName()+_(" to integer number")); } ScriptValue::operator int() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("integer" ))); }
ScriptValue::operator double() const { throw ScriptError( _("Can't convert from ")+typeName()+_(" to real number" )); } ScriptValue::operator double() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("real" ))); }
ScriptValue::operator Color() const { throw ScriptError( _("Can't convert from ")+typeName()+_(" to color" )); } ScriptValue::operator Color() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("color" ))); }
ScriptValueP ScriptValue::eval(Context&) const { throw ScriptError( _("Can't convert from ")+typeName()+_(" to function" )); } ScriptValueP ScriptValue::eval(Context&) const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("function"))); }
ScriptValueP ScriptValue::getMember(const String& name) const { throw ScriptError(typeName() + _(" has no member '") + name + _("'")); } ScriptValueP ScriptValue::getMember(const String& name) const { throw ScriptError(_ERROR_2_("has no member", typeName(), name)); }
ScriptValueP ScriptValue::next() { throw InternalError(_("Can't convert from ")+typeName()+_(" to iterator")); } ScriptValueP ScriptValue::next() { throw InternalError(_("Can't convert from ")+typeName()+_(" to iterator")); }
ScriptValueP ScriptValue::makeIterator() const { throw ScriptError( _("Can't convert from ")+typeName()+_(" to collection")); } ScriptValueP ScriptValue::makeIterator() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("collection"))); }
int ScriptValue::itemCount() const { throw ScriptError( _("Can't convert from ")+typeName()+_(" to collection")); } int ScriptValue::itemCount() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("collection"))); }
ScriptValueP ScriptValue::dependencyMember(const String& name, const Dependency&) const { return dependency_dummy; } ScriptValueP ScriptValue::dependencyMember(const String& name, const Dependency&) const { return dependency_dummy; }
ScriptValueP ScriptValue::dependencies(Context&, const Dependency&) const { return dependency_dummy; } ScriptValueP ScriptValue::dependencies(Context&, const Dependency&) const { return dependency_dummy; }
...@@ -63,7 +63,7 @@ class ScriptInt : public ScriptValue { ...@@ -63,7 +63,7 @@ class ScriptInt : public ScriptValue {
public: public:
ScriptInt(int v) : value(v) {} ScriptInt(int v) : value(v) {}
virtual ScriptType type() const { return SCRIPT_INT; } virtual ScriptType type() const { return SCRIPT_INT; }
virtual String typeName() const { return _("integer number"); } virtual String typeName() const { return _TYPE_("integer"); }
virtual operator String() const { return String() << value; } virtual operator String() const { return String() << value; }
virtual operator double() const { return value; } virtual operator double() const { return value; }
virtual operator int() const { return value; } virtual operator int() const { return value; }
...@@ -108,7 +108,7 @@ class ScriptBool : public ScriptValue { ...@@ -108,7 +108,7 @@ class ScriptBool : public ScriptValue {
public: public:
ScriptBool(bool v) : value(v) {} ScriptBool(bool v) : value(v) {}
virtual ScriptType type() const { return SCRIPT_INT; } virtual ScriptType type() const { return SCRIPT_INT; }
virtual String typeName() const { return _("boolean"); } virtual String typeName() const { return _TYPE_("boolean"); }
virtual operator String() const { return value ? _("true") : _("false"); } virtual operator String() const { return value ? _("true") : _("false"); }
virtual operator int() const { return value; } virtual operator int() const { return value; }
private: private:
...@@ -130,7 +130,7 @@ class ScriptDouble : public ScriptValue { ...@@ -130,7 +130,7 @@ class ScriptDouble : public ScriptValue {
public: public:
ScriptDouble(double v) : value(v) {} ScriptDouble(double v) : value(v) {}
virtual ScriptType type() const { return SCRIPT_DOUBLE; } virtual ScriptType type() const { return SCRIPT_DOUBLE; }
virtual String typeName() const { return _("real number"); } virtual String typeName() const { return _TYPE_("real"); }
virtual operator String() const { return String() << value; } virtual operator String() const { return String() << value; }
virtual operator double() const { return value; } virtual operator double() const { return value; }
virtual operator int() const { return (int)value; } virtual operator int() const { return (int)value; }
...@@ -149,14 +149,14 @@ class ScriptString : public ScriptValue { ...@@ -149,14 +149,14 @@ class ScriptString : public ScriptValue {
public: public:
ScriptString(const String& v) : value(v) {} ScriptString(const String& v) : value(v) {}
virtual ScriptType type() const { return SCRIPT_STRING; } virtual ScriptType type() const { return SCRIPT_STRING; }
virtual String typeName() const { return _("string"); } virtual String typeName() const { return _TYPE_("string"); }
virtual operator String() const { return value; } virtual operator String() const { return value; }
virtual operator double() const { virtual operator double() const {
double d; double d;
if (value.ToDouble(&d)) { if (value.ToDouble(&d)) {
return d; return d;
} else { } else {
throw ScriptError(_("Not a number: '") + value + _("'")); throw ScriptError(_ERROR_3_("can't convert value", value, typeName(), _TYPE_("double")));
} }
} }
virtual operator int() const { virtual operator int() const {
...@@ -168,7 +168,7 @@ class ScriptString : public ScriptValue { ...@@ -168,7 +168,7 @@ class ScriptString : public ScriptValue {
} else if (value == _("no") || value == _("false") || value.empty()) { } else if (value == _("no") || value == _("false") || value.empty()) {
return false; return false;
} else { } else {
throw ScriptError(_("Not a number: '") + value + _("'")); throw ScriptError(_ERROR_3_("can't convert value", value, typeName(), _TYPE_("integer")));
} }
} }
virtual operator Color() const { virtual operator Color() const {
...@@ -176,7 +176,7 @@ class ScriptString : public ScriptValue { ...@@ -176,7 +176,7 @@ class ScriptString : public ScriptValue {
if (wxSscanf(value.c_str(),_("rgb(%u,%u,%u)"),&r,&g,&b)) { if (wxSscanf(value.c_str(),_("rgb(%u,%u,%u)"),&r,&g,&b)) {
return Color(r, g, b); return Color(r, g, b);
} else { } else {
throw ScriptError(_("Not a color: '") + value + _("'")); throw ScriptError(_ERROR_3_("can't convert value", value, typeName(), _TYPE_("color")));
} }
} }
virtual int itemCount() const { return (int)value.size(); } virtual int itemCount() const { return (int)value.size(); }
...@@ -186,7 +186,7 @@ class ScriptString : public ScriptValue { ...@@ -186,7 +186,7 @@ class ScriptString : public ScriptValue {
if (name.ToLong(&index) && index >= 0 && (size_t)index < value.size()) { if (name.ToLong(&index) && index >= 0 && (size_t)index < value.size()) {
return toScript(String(1,value[index])); return toScript(String(1,value[index]));
} else { } else {
throw ScriptError(_("String \"") + value + _("\" has no member ") + name); throw ScriptError(_ERROR_2_("has no member value", value, name));
} }
} }
private: private:
...@@ -205,7 +205,7 @@ class ScriptColor : public ScriptValue { ...@@ -205,7 +205,7 @@ class ScriptColor : public ScriptValue {
public: public:
ScriptColor(const Color& v) : value(v) {} ScriptColor(const Color& v) : value(v) {}
virtual ScriptType type() const { return SCRIPT_COLOR; } virtual ScriptType type() const { return SCRIPT_COLOR; }
virtual String typeName() const { return _("color"); } virtual String typeName() const { return _TYPE_("color"); }
virtual operator Color() const { return value; } virtual operator Color() const { return value; }
virtual operator String() const { virtual operator String() const {
return String::Format(_("rgb(%u,%u,%u)"), value.Red(), value.Green(), value.Blue()); return String::Format(_("rgb(%u,%u,%u)"), value.Red(), value.Green(), value.Blue());
...@@ -225,7 +225,7 @@ ScriptValueP toScript(const Color& v) { ...@@ -225,7 +225,7 @@ ScriptValueP toScript(const Color& v) {
class ScriptNil : public ScriptValue { class ScriptNil : public ScriptValue {
public: public:
virtual ScriptType type() const { return SCRIPT_NIL; } virtual ScriptType type() const { return SCRIPT_NIL; }
virtual String typeName() const { return _("nil"); } virtual String typeName() const { return _TYPE_("nil"); }
virtual operator String() const { return wxEmptyString; } virtual operator String() const { return wxEmptyString; }
virtual operator double() const { return 0.0; } virtual operator double() const { return 0.0; }
virtual operator int() const { return 0; } virtual operator int() const { return 0; }
......
...@@ -48,6 +48,8 @@ class ScriptValue : public IntrusivePtrBase { ...@@ -48,6 +48,8 @@ class ScriptValue : public IntrusivePtrBase {
virtual operator double() const; virtual operator double() const;
/// Convert this value to an integer /// Convert this value to an integer
virtual operator int() const; virtual operator int() const;
/// Convert this value to a boolean
inline operator bool() const { return (int)*this; }
/// Convert this value to a color /// Convert this value to a color
virtual operator Color() const; virtual operator Color() const;
......
...@@ -85,12 +85,19 @@ ...@@ -85,12 +85,19 @@
} }
/// Declare typeof magic for a specific std::vector type /// Declare typeof magic for a specific std::vector type
#define DECLARE_TYPEOF_COLLECTION(T) DECLARE_TYPEOF(vector<T>); \ #define DECLARE_TYPEOF_COLLECTION(T) DECLARE_TYPEOF(vector< T >); \
// DECLARE_TYPEOF_CONST(set<T>) DECLARE_TYPEOF_CONST(set< T >)
#endif #endif
/// Use for template classes
/** i.e.
* DECLARE_TYPEOF(pair<a COMMA b>);
* instead of
* DECLARE_TYPEOF(pair<a,b>);
*/
#define COMMA ,
// ----------------------------------------------------------------------------- : Looping macros with iterators // ----------------------------------------------------------------------------- : Looping macros with iterators
/// Iterate over a collection, using an iterator it of type Type /// Iterate over a collection, using an iterator it of type Type
......
...@@ -97,8 +97,9 @@ String tr(const SymbolFont&, const String& key, const String& def); ...@@ -97,8 +97,9 @@ String tr(const SymbolFont&, const String& key, const String& def);
inline String format_string(const String& format, ...) { inline String format_string(const String& format, ...) {
va_list args; va_list args;
va_start(args, format); va_start(args, format);
return String::Format(format, args); String res = String::Format(format, args);
va_end(args); va_end(args);
return res;
} }
inline String format_string(const String& format, const String& a0) { inline String format_string(const String& format, const String& a0) {
return String::Format(format, a0.c_str()); return String::Format(format, a0.c_str());
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
/** @file util/platform.hpp /** @file util/platform.hpp
* *
* @brief Platform specific hacks * @brief Platform and compiler specific hacks.
*/ */
// ----------------------------------------------------------------------------- : Includes // ----------------------------------------------------------------------------- : Includes
...@@ -23,11 +23,22 @@ ...@@ -23,11 +23,22 @@
#ifdef __linux__ #ifdef __linux__
/// wxMkDir as documented
inline void wxMkDir(const String& dir) { inline void wxMkDir(const String& dir) {
wxMkDir(wxConvLocal.cWX2MB(dir), 0777); wxMkDir(wxConvLocal.cWX2MB(dir), 0777);
} }
#endif #endif
// ----------------------------------------------------------------------------- : GCC
#ifdef __GNUC__
/// Absolute value of integers
template <typename T>
inline T abs(T a) { return a < 0 ? -a : a; }
#endif
// ----------------------------------------------------------------------------- : EOF // ----------------------------------------------------------------------------- : EOF
#endif #endif
...@@ -113,7 +113,8 @@ String capitalize_sentence(const String&); ...@@ -113,7 +113,8 @@ String capitalize_sentence(const String&);
String cannocial_name_form(const String&); String cannocial_name_form(const String&);
/// Returns the singular form of a string /// Returns the singular form of a string
/** Used for reflection, for example "vector<T> apples" is written with keys "apple" /** Used for reflection, for example "vector<T> apples" is written with keys
* singular_form("apples"), which is "apple"
*/ */
String singular_form(const String&); String singular_form(const String&);
......
...@@ -121,6 +121,10 @@ size_t match_close_tag(const String& str, size_t start) { ...@@ -121,6 +121,10 @@ size_t match_close_tag(const String& str, size_t start) {
return String::npos; return String::npos;
} }
size_t match_close_tag_end(const String& str, size_t start) {
return skip_tag(str, match_close_tag(str, start));
}
size_t last_start_tag_before(const String& str, const String& tag, size_t start) { size_t last_start_tag_before(const String& str, const String& tag, size_t start) {
start = min(str.size(), start); start = min(str.size(), start);
for (size_t pos = start ; pos > 0 ; --pos) { for (size_t pos = start ; pos > 0 ; --pos) {
...@@ -178,7 +182,7 @@ size_t index_to_cursor(const String& str, size_t index, Movement dir) { ...@@ -178,7 +182,7 @@ size_t index_to_cursor(const String& str, size_t index, Movement dir) {
if (is_substr(str, i, _("<atom")) || is_substr(str, i, _("<sep"))) { if (is_substr(str, i, _("<atom")) || is_substr(str, i, _("<sep"))) {
// skip tag contents, tag counts as a single 'character' // skip tag contents, tag counts as a single 'character'
size_t before = i; size_t before = i;
size_t after = skip_tag(str, match_close_tag(str, i)); size_t after = match_close_tag_end(str, i);
if (index > before && index < after) { if (index > before && index < after) {
// index is inside an atom, determine on which side we want the cursor // index is inside an atom, determine on which side we want the cursor
if (dir == MOVE_RIGHT) { if (dir == MOVE_RIGHT) {
...@@ -215,7 +219,7 @@ void cursor_to_index_range(const String& str, size_t cursor, size_t& start, size ...@@ -215,7 +219,7 @@ void cursor_to_index_range(const String& str, size_t cursor, size_t& start, size
// a tag // a tag
if (is_substr(str, i, _("<atom")) || is_substr(str, i, _("<sep"))) { if (is_substr(str, i, _("<atom")) || is_substr(str, i, _("<sep"))) {
// skip tag contents, tag counts as a single 'character' // skip tag contents, tag counts as a single 'character'
i = skip_tag(str, match_close_tag(str, i)); i = match_close_tag_end(str, i);
} else { } else {
i = skip_tag(str, i); i = skip_tag(str, i);
has_width = false; has_width = false;
...@@ -259,6 +263,24 @@ size_t cursor_to_index(const String& str, size_t cursor, Movement dir) { ...@@ -259,6 +263,24 @@ size_t cursor_to_index(const String& str, size_t cursor, Movement dir) {
return dir == MOVE_RIGHT ? end - 1 : start; return dir == MOVE_RIGHT ? end - 1 : start;
} }
// ----------------------------------------------------------------------------- : Untagged position
size_t untagged_to_index(const String& str, size_t pos, bool inside) {
size_t i = 0, p = 0;
while (i < str.size()) {
Char c = str.GetChar(i);
if (c == _('<')) {
bool is_close = is_substr(str, i, _("</"));
if (p == pos && is_close == inside) break;
i = skip_tag(str, i);
} else {
if (p == pos) break;
i++;
p++;
}
}
return i;
}
// ----------------------------------------------------------------------------- : Global operations // ----------------------------------------------------------------------------- : Global operations
......
...@@ -57,6 +57,12 @@ size_t skip_tag(const String& str, size_t start); ...@@ -57,6 +57,12 @@ size_t skip_tag(const String& str, size_t start);
/** If not found returns String::npos */ /** If not found returns String::npos */
size_t match_close_tag(const String& str, size_t start); size_t match_close_tag(const String& str, size_t start);
/// Find the position of the closing tag matching the tag at start
/** Returns the position just after that tag.
* match_close_tag_end(s,i) == skip_tag(s, match_close_tag(s,i) )
* If not found returns String::npos */
size_t match_close_tag_end(const String& str, size_t start);
/// Find the last start tag before position start /// Find the last start tag before position start
/** If not found returns String::npos */ /** If not found returns String::npos */
size_t last_start_tag_before(const String& str, const String& tag, size_t start); size_t last_start_tag_before(const String& str, const String& tag, size_t start);
...@@ -103,6 +109,14 @@ void cursor_to_index_range(const String& str, size_t cursor, size_t& begin, size ...@@ -103,6 +109,14 @@ void cursor_to_index_range(const String& str, size_t cursor, size_t& begin, size
/// Find the character index corresponding to the given cursor position /// Find the character index corresponding to the given cursor position
size_t cursor_to_index(const String& str, size_t cursor, Movement dir = MOVE_MID); size_t cursor_to_index(const String& str, size_t cursor, Movement dir = MOVE_MID);
// ----------------------------------------------------------------------------- : Untagged position
/// Find the tagged position corresponding to the given untagged position.
/** An untagged position in str is a position in untag(str).
* @param inside if inside then it prefers to find positions inside tags (after open tags, before close tags)
*/
size_t untagged_to_index(const String& str, size_t pos, bool inside);
// ----------------------------------------------------------------------------- : Global operations // ----------------------------------------------------------------------------- : Global operations
/// Remove all instances of a tag and its close tag, but keep the contents. /// Remove all instances of a tag and its close tag, but keep the contents.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment