mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-12 13:37:00 -04:00
The check_spelling function now has support for additional dictionaries and regexes to match.
The magic game uses these features. git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@1269 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
@@ -0,0 +1,34 @@
|
|||||||
|
33
|
||||||
|
mana
|
||||||
|
untap/MSDRJZG
|
||||||
|
face-down
|
||||||
|
nonwhite
|
||||||
|
nonblue
|
||||||
|
nonblack
|
||||||
|
nonred
|
||||||
|
nongreen
|
||||||
|
non-land
|
||||||
|
unblock/USDG
|
||||||
|
precombat
|
||||||
|
postcombat
|
||||||
|
scry
|
||||||
|
Plainswalk
|
||||||
|
Islandwalk
|
||||||
|
Swampwalk
|
||||||
|
Mountainwalk
|
||||||
|
Forestwalk
|
||||||
|
Landwalk
|
||||||
|
Desertwalk
|
||||||
|
Plainshome
|
||||||
|
Islandhome
|
||||||
|
Swamphome
|
||||||
|
Mountainhome
|
||||||
|
Foresthome
|
||||||
|
Landhome
|
||||||
|
Soulshift
|
||||||
|
Ninjitsu
|
||||||
|
Bushido
|
||||||
|
Lifelink
|
||||||
|
Gravestorm
|
||||||
|
Fateseal
|
||||||
|
Bloodthirst
|
||||||
@@ -334,8 +334,17 @@ mana_context :=
|
|||||||
| <param-cost>[ ]*<match></param-cost> # keyword argument that is declared as cost
|
| <param-cost>[ ]*<match></param-cost> # keyword argument that is declared as cost
|
||||||
| <param-cost><match>, # keyword argument that is declared as cost
|
| <param-cost><match>, # keyword argument that is declared as cost
|
||||||
";
|
";
|
||||||
|
|
||||||
# truncates the name of legends
|
# truncates the name of legends
|
||||||
legend_filter := replace@(match:"(, | of | the ).*", replace: "" )
|
legend_filter := replace@(match:"(, | of | the ).*", replace: "" )
|
||||||
|
|
||||||
|
# these are considered a correct 'word' for spellchecking in the text box:
|
||||||
|
additional_text_words := match@(match:
|
||||||
|
"(?ix)^(?: # match whole word
|
||||||
|
<atom-[^>]*>.*?</atom-[^>]*> # cardnames and stuff
|
||||||
|
| [+-]?[0-9X]+ / [+-]?[0-9X]+ # '3/3', '+X/+X'
|
||||||
|
)$")
|
||||||
|
|
||||||
# the rule text filter
|
# the rule text filter
|
||||||
# - adds mana symbols
|
# - adds mana symbols
|
||||||
# - makes text in parentheses italic
|
# - makes text in parentheses italic
|
||||||
@@ -413,7 +422,11 @@ text_filter :=
|
|||||||
replace: { _1 + to_upper(_2) }) +
|
replace: { _1 + to_upper(_2) }) +
|
||||||
curly_quotes +
|
curly_quotes +
|
||||||
# step 9 : spellcheck
|
# step 9 : spellcheck
|
||||||
{ check_spelling(language:language().spellcheck_code) }
|
{ check_spelling(
|
||||||
|
language: language().spellcheck_code,
|
||||||
|
extra_dictionary: "/magic.mse-game/magic-words",
|
||||||
|
extra_match: additional_text_words
|
||||||
|
)}
|
||||||
|
|
||||||
|
|
||||||
############################################################## Other boxes
|
############################################################## Other boxes
|
||||||
|
|||||||
@@ -193,6 +193,12 @@ void SymbolControl::draw(DC& dc) {
|
|||||||
}
|
}
|
||||||
dc.SetLogicalFunction(wxCOPY);
|
dc.SetLogicalFunction(wxCOPY);
|
||||||
}
|
}
|
||||||
|
// draw aspect ratio indicators
|
||||||
|
double ar = symbol->aspectRatio();
|
||||||
|
// TODO: limit aspect ratio
|
||||||
|
if (ar > 0) {
|
||||||
|
} else if (ar < 0) {
|
||||||
|
}
|
||||||
// draw editing overlay
|
// draw editing overlay
|
||||||
if (editor) {
|
if (editor) {
|
||||||
editor->draw(dc);
|
editor->draw(dc);
|
||||||
|
|||||||
+38
-1
@@ -3948,11 +3948,48 @@
|
|||||||
</File>
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
Name="tests"
|
Name="template-stuff"
|
||||||
Filter="">
|
Filter="">
|
||||||
<File
|
<File
|
||||||
RelativePath="..\data\magic-test.mse-style\script-language-tests">
|
RelativePath="..\data\magic-test.mse-style\script-language-tests">
|
||||||
</File>
|
</File>
|
||||||
|
<Filter
|
||||||
|
Name="magic"
|
||||||
|
Filter="">
|
||||||
|
<File
|
||||||
|
RelativePath="..\data\magic.mse-game\add_cards_scripts">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\data\magic.mse-game\auto_replace">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\data\magic.mse-game\card_fields">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\data\magic.mse-game\game">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\data\magic.mse-game\keywords">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\data\magic.mse-game\language">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\data\magic.mse-game\packs">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\data\magic.mse-game\script">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\data\magic.mse-game\set_fields">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\data\magic.mse-game\statistics">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\data\magic.mse-game\word_lists">
|
||||||
|
</File>
|
||||||
|
</Filter>
|
||||||
</Filter>
|
</Filter>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\code_template.cpp">
|
RelativePath=".\code_template.cpp">
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Functions
|
// ----------------------------------------------------------------------------- : Functions
|
||||||
|
|
||||||
bool spelled_correctly(const String& input, size_t start, size_t end, SpellChecker& checker) {
|
inline bool spelled_correctly(const String& input, size_t start, size_t end, SpellChecker** checkers, const ScriptValueP& extra_test, Context& ctx) {
|
||||||
// untag
|
// untag
|
||||||
String word = untag(input.substr(start,end-start));
|
String word = untag(input.substr(start,end-start));
|
||||||
if (word.empty()) return true;
|
if (word.empty()) return true;
|
||||||
@@ -33,28 +33,48 @@ bool spelled_correctly(const String& input, size_t start, size_t end, SpellCheck
|
|||||||
// symbols are always spelled correctly
|
// symbols are always spelled correctly
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// run through spellchecker
|
// run through spellchecker(s)
|
||||||
return checker.spell(word.substr(start_u,end_u));
|
word.erase(end_u,String::npos);
|
||||||
|
word.erase(0,start_u);
|
||||||
|
for (SpellChecker** c = checkers ; *c ; ++c) {
|
||||||
|
if ((*c)->spell(word)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// run through additional words regex
|
||||||
|
if (extra_test) {
|
||||||
|
ctx.setVariable(SCRIPT_VAR_input, to_script(input.substr(start2,end2-start2)));
|
||||||
|
if (*extra_test->eval(ctx)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_word(const String& input, String& out, size_t start, size_t end, SpellChecker& checker) {
|
void check_word(const String& input, String& out, size_t start, size_t end, SpellChecker** checkers, const ScriptValueP& extra_test, Context& ctx) {
|
||||||
if (start >= end) return;
|
if (start >= end) return;
|
||||||
bool good = spelled_correctly(input, start, end, checker);
|
bool good = spelled_correctly(input, start, end, checkers, extra_test, ctx);
|
||||||
if (!good) out += _("<error-spelling>");
|
if (!good) out += _("<error-spelling>");
|
||||||
out.append(input, start, end-start);
|
out.append(input, start, end-start);
|
||||||
if (!good) out += _("</error-spelling>");
|
if (!good) out += _("</error-spelling>");
|
||||||
}
|
}
|
||||||
|
|
||||||
SCRIPT_FUNCTION(check_spelling) {
|
SCRIPT_FUNCTION(check_spelling) {
|
||||||
SCRIPT_PARAM(String,language);
|
SCRIPT_PARAM_C(String,language);
|
||||||
SCRIPT_PARAM(String,input);
|
SCRIPT_PARAM_C(String,input);
|
||||||
if (language.empty()) {
|
SCRIPT_OPTIONAL_PARAM_N_(String,_("extra dictionary"),extra_dictionary);
|
||||||
// no language -> spelling checking
|
SCRIPT_OPTIONAL_PARAM_N_(ScriptValueP,_("extra match"),extra_match);
|
||||||
SCRIPT_RETURN(true);
|
|
||||||
}
|
|
||||||
SpellChecker& checker = SpellChecker::get(language);
|
|
||||||
// remove old spelling error tags
|
// remove old spelling error tags
|
||||||
input = remove_tag(input, _("<error-spelling"));
|
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);
|
||||||
|
}
|
||||||
// now walk over the words in the input, and mark misspellings
|
// now walk over the words in the input, and mark misspellings
|
||||||
String result;
|
String result;
|
||||||
size_t word_start = 0, word_end = 0, pos = 0;
|
size_t word_start = 0, word_end = 0, pos = 0;
|
||||||
@@ -71,7 +91,7 @@ SCRIPT_FUNCTION(check_spelling) {
|
|||||||
}
|
}
|
||||||
} else if (isSpace(c) || c == EM_DASH || c == EN_DASH) {
|
} else if (isSpace(c) || c == EM_DASH || c == EN_DASH) {
|
||||||
// word boundary -> check word
|
// word boundary -> check word
|
||||||
check_word(input, result, word_start, word_end, checker);
|
check_word(input, result, word_start, word_end, checkers, extra_match, ctx);
|
||||||
// non-word characters
|
// non-word characters
|
||||||
result.append(input, word_end, pos - word_end + 1);
|
result.append(input, word_end, pos - word_end + 1);
|
||||||
// next
|
// next
|
||||||
@@ -81,15 +101,15 @@ SCRIPT_FUNCTION(check_spelling) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// last word
|
// last word
|
||||||
check_word(input, result, word_start, word_end, checker);
|
check_word(input, result, word_start, word_end, checkers, extra_match, ctx);
|
||||||
result.append(input, word_end, String::npos);
|
result.append(input, word_end, String::npos);
|
||||||
// done
|
// done
|
||||||
SCRIPT_RETURN(result);
|
SCRIPT_RETURN(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
SCRIPT_FUNCTION(check_spelling_word) {
|
SCRIPT_FUNCTION(check_spelling_word) {
|
||||||
SCRIPT_PARAM(String,language);
|
SCRIPT_PARAM_C(String,language);
|
||||||
SCRIPT_PARAM(String,input);
|
SCRIPT_PARAM_C(String,input);
|
||||||
if (language.empty()) {
|
if (language.empty()) {
|
||||||
// no language -> spelling checking
|
// no language -> spelling checking
|
||||||
SCRIPT_RETURN(true);
|
SCRIPT_RETURN(true);
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ void init_script_variables() {
|
|||||||
Var(styling);
|
Var(styling);
|
||||||
Var(value);
|
Var(value);
|
||||||
Var(condition);
|
Var(condition);
|
||||||
|
Var(language);
|
||||||
assert(variables.size() == SCRIPT_VAR_CUSTOM_FIRST);
|
assert(variables.size() == SCRIPT_VAR_CUSTOM_FIRST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ enum Variable
|
|||||||
, SCRIPT_VAR_styling
|
, SCRIPT_VAR_styling
|
||||||
, SCRIPT_VAR_value
|
, SCRIPT_VAR_value
|
||||||
, SCRIPT_VAR_condition
|
, SCRIPT_VAR_condition
|
||||||
|
, SCRIPT_VAR_language
|
||||||
, SCRIPT_VAR_CUSTOM_FIRST // other variables start from here
|
, SCRIPT_VAR_CUSTOM_FIRST // other variables start from here
|
||||||
, SCRIPT_VAR_CUSTOM_LOTS = 0xFFFFFF // ensure that sizeof(Variable) is large enough
|
, SCRIPT_VAR_CUSTOM_LOTS = 0xFFFFFF // ensure that sizeof(Variable) is large enough
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -120,6 +120,27 @@ InputStreamP PackageManager::openFileFromPackage(Packaged*& package, const Strin
|
|||||||
throw FileNotFoundError(name, _("No package name specified, use '/package/filename'"));
|
throw FileNotFoundError(name, _("No package name specified, use '/package/filename'"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String PackageManager::openFilenameFromPackage(Packaged*& package, const String& name) {
|
||||||
|
if (!name.empty() && name.GetChar(0) == _('/')) {
|
||||||
|
// absolute name; break name
|
||||||
|
size_t start = name.find_first_not_of(_("/\\"), 1); // allow "//package/name" from incorrect scripts
|
||||||
|
size_t pos = name.find_first_of(_("/\\"), start);
|
||||||
|
if (start < pos && pos != String::npos) {
|
||||||
|
// open package
|
||||||
|
PackagedP p = openAny(name.substr(start, pos-start));
|
||||||
|
if (package && !is_substr(name,start,_(":NO-WARN-DEP:"))) {
|
||||||
|
package->requireDependency(p.get());
|
||||||
|
}
|
||||||
|
package = p.get();
|
||||||
|
return p->absoluteFilename() + _("/") + name.substr(pos + 1);
|
||||||
|
}
|
||||||
|
} else if (package) {
|
||||||
|
// relative name
|
||||||
|
return package->absoluteFilename() + _("/") + name;
|
||||||
|
}
|
||||||
|
throw FileNotFoundError(name, _("No package name specified, use '/package/filename'"));
|
||||||
|
}
|
||||||
|
|
||||||
String PackageManager::getDictionaryDir(bool l) const {
|
String PackageManager::getDictionaryDir(bool l) const {
|
||||||
String dir = (l ? local : global).getDirectory();
|
String dir = (l ? local : global).getDirectory();
|
||||||
if (dir.empty()) return wxEmptyString;
|
if (dir.empty()) return wxEmptyString;
|
||||||
|
|||||||
@@ -150,6 +150,12 @@ class PackageManager {
|
|||||||
*/
|
*/
|
||||||
InputStreamP openFileFromPackage(Packaged*& package, const String& name);
|
InputStreamP openFileFromPackage(Packaged*& package, const String& name);
|
||||||
|
|
||||||
|
/// Get a filename to open from a package
|
||||||
|
/** WARNING: this is a bit of a hack, since not all package types support names in this way.
|
||||||
|
* It is needed for third party libraries (i.e. hunspell) that load stuff from files.
|
||||||
|
*/
|
||||||
|
String openFilenameFromPackage(Packaged*& package, const String& name);
|
||||||
|
|
||||||
// --------------------------------------------------- : Packages on disk
|
// --------------------------------------------------- : Packages on disk
|
||||||
|
|
||||||
/// Check if the given dependency is currently installed
|
/// Check if the given dependency is currently installed
|
||||||
|
|||||||
@@ -35,6 +35,31 @@ SpellChecker& SpellChecker::get(const String& language) {
|
|||||||
return *speller;
|
return *speller;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SpellChecker& SpellChecker::get(const String& filename, const String& language) {
|
||||||
|
SpellCheckerP& speller = spellers[filename + _(".") + language];
|
||||||
|
if (!speller) {
|
||||||
|
Packaged* package = nullptr;
|
||||||
|
String prefix = package_manager.openFilenameFromPackage(package, filename) + _(".");
|
||||||
|
String local_dir = package_manager.getDictionaryDir(true);
|
||||||
|
String global_dir = package_manager.getDictionaryDir(false);
|
||||||
|
String aff_path = language + _(".aff");
|
||||||
|
String dic_path = language + _(".dic");
|
||||||
|
if (wxFileExists(prefix + aff_path) && wxFileExists(prefix + dic_path)) {
|
||||||
|
speller = SpellCheckerP(new SpellChecker((prefix + aff_path).mb_str(),
|
||||||
|
(prefix + dic_path).mb_str()));
|
||||||
|
} else if (wxFileExists(local_dir + aff_path) && wxFileExists(prefix + dic_path)) {
|
||||||
|
speller = SpellCheckerP(new SpellChecker((local_dir + aff_path).mb_str(),
|
||||||
|
(prefix + dic_path).mb_str()));
|
||||||
|
} else if (wxFileExists(global_dir + aff_path) && wxFileExists(prefix + dic_path)) {
|
||||||
|
speller = SpellCheckerP(new SpellChecker((global_dir + aff_path).mb_str(),
|
||||||
|
(prefix + dic_path).mb_str()));
|
||||||
|
} else {
|
||||||
|
throw Error(_("Dictionary '") + filename + _("' not found for language: ") + language);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *speller;
|
||||||
|
}
|
||||||
|
|
||||||
SpellChecker::SpellChecker(const char* aff_path, const char* dic_path)
|
SpellChecker::SpellChecker(const char* aff_path, const char* dic_path)
|
||||||
: Hunspell(aff_path,dic_path)
|
: Hunspell(aff_path,dic_path)
|
||||||
, encoding(String(get_dic_encoding(), IF_UNICODE(wxConvLibc, wxSTRING_MAXLEN)))
|
, encoding(String(get_dic_encoding(), IF_UNICODE(wxConvLibc, wxSTRING_MAXLEN)))
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ class SpellChecker : public Hunspell, public IntrusivePtrBase<SpellChecker> {
|
|||||||
/// Get a SpellChecker object for the given language.
|
/// Get a SpellChecker object for the given language.
|
||||||
/** Note: This is not threadsafe yet */
|
/** Note: This is not threadsafe yet */
|
||||||
static SpellChecker& get(const String& language);
|
static SpellChecker& get(const String& language);
|
||||||
|
/// Get a SpellChecker object for the given language and filename
|
||||||
|
/** Note: This is not threadsafe yet */
|
||||||
|
static SpellChecker& get(const String& filename, const String& language);
|
||||||
/// Destroy all cached SpellChecker objects
|
/// Destroy all cached SpellChecker objects
|
||||||
static void destroyAll();
|
static void destroyAll();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user