mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57: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>, # keyword argument that is declared as cost
|
||||
";
|
||||
|
||||
# truncates the name of legends
|
||||
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
|
||||
# - adds mana symbols
|
||||
# - makes text in parentheses italic
|
||||
@@ -413,7 +422,11 @@ text_filter :=
|
||||
replace: { _1 + to_upper(_2) }) +
|
||||
curly_quotes +
|
||||
# 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
|
||||
|
||||
@@ -193,6 +193,12 @@ void SymbolControl::draw(DC& dc) {
|
||||
}
|
||||
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
|
||||
if (editor) {
|
||||
editor->draw(dc);
|
||||
|
||||
+38
-1
@@ -3948,11 +3948,48 @@
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="tests"
|
||||
Name="template-stuff"
|
||||
Filter="">
|
||||
<File
|
||||
RelativePath="..\data\magic-test.mse-style\script-language-tests">
|
||||
</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>
|
||||
<File
|
||||
RelativePath=".\code_template.cpp">
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
// ----------------------------------------------------------------------------- : 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
|
||||
String word = untag(input.substr(start,end-start));
|
||||
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
|
||||
return true;
|
||||
}
|
||||
// run through spellchecker
|
||||
return checker.spell(word.substr(start_u,end_u));
|
||||
// run through spellchecker(s)
|
||||
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;
|
||||
bool good = spelled_correctly(input, start, end, checker);
|
||||
bool good = spelled_correctly(input, start, end, checkers, extra_test, ctx);
|
||||
if (!good) out += _("<error-spelling>");
|
||||
out.append(input, start, end-start);
|
||||
if (!good) out += _("</error-spelling>");
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(check_spelling) {
|
||||
SCRIPT_PARAM(String,language);
|
||||
SCRIPT_PARAM(String,input);
|
||||
if (language.empty()) {
|
||||
// no language -> spelling checking
|
||||
SCRIPT_RETURN(true);
|
||||
}
|
||||
SpellChecker& checker = SpellChecker::get(language);
|
||||
SCRIPT_PARAM_C(String,language);
|
||||
SCRIPT_PARAM_C(String,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);
|
||||
}
|
||||
// now walk over the words in the input, and mark misspellings
|
||||
String result;
|
||||
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) {
|
||||
// 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
|
||||
result.append(input, word_end, pos - word_end + 1);
|
||||
// next
|
||||
@@ -81,15 +101,15 @@ SCRIPT_FUNCTION(check_spelling) {
|
||||
}
|
||||
}
|
||||
// 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);
|
||||
// done
|
||||
SCRIPT_RETURN(result);
|
||||
}
|
||||
|
||||
SCRIPT_FUNCTION(check_spelling_word) {
|
||||
SCRIPT_PARAM(String,language);
|
||||
SCRIPT_PARAM(String,input);
|
||||
SCRIPT_PARAM_C(String,language);
|
||||
SCRIPT_PARAM_C(String,input);
|
||||
if (language.empty()) {
|
||||
// no language -> spelling checking
|
||||
SCRIPT_RETURN(true);
|
||||
|
||||
@@ -77,6 +77,7 @@ void init_script_variables() {
|
||||
Var(styling);
|
||||
Var(value);
|
||||
Var(condition);
|
||||
Var(language);
|
||||
assert(variables.size() == SCRIPT_VAR_CUSTOM_FIRST);
|
||||
}
|
||||
|
||||
|
||||
@@ -136,6 +136,7 @@ enum Variable
|
||||
, SCRIPT_VAR_styling
|
||||
, SCRIPT_VAR_value
|
||||
, SCRIPT_VAR_condition
|
||||
, SCRIPT_VAR_language
|
||||
, SCRIPT_VAR_CUSTOM_FIRST // other variables start from here
|
||||
, 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'"));
|
||||
}
|
||||
|
||||
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 dir = (l ? local : global).getDirectory();
|
||||
if (dir.empty()) return wxEmptyString;
|
||||
|
||||
@@ -150,6 +150,12 @@ class PackageManager {
|
||||
*/
|
||||
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
|
||||
|
||||
/// Check if the given dependency is currently installed
|
||||
|
||||
@@ -35,6 +35,31 @@ SpellChecker& SpellChecker::get(const String& language) {
|
||||
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)
|
||||
: Hunspell(aff_path,dic_path)
|
||||
, 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.
|
||||
/** Note: This is not threadsafe yet */
|
||||
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
|
||||
static void destroyAll();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user