Index: gc_core/py/lang_core/gc_engine.py ================================================================== --- gc_core/py/lang_core/gc_engine.py +++ gc_core/py/lang_core/gc_engine.py @@ -12,10 +12,11 @@ from ..graphspell.echo import echo from .. import text from . import gc_options +from . import gc_engine_func as gce_func try: # LibreOffice / OpenOffice from com.sun.star.linguistic2 import SingleProofreadingError from com.sun.star.text.TextMarkupType import PROOFREADING @@ -26,11 +27,10 @@ _bWriterError = False __all__ = [ "lang", "locales", "pkg", "name", "version", "author", \ "load", "parse", "getSpellChecker", \ - "setOption", "setOptions", "getOptions", "getDefaultOptions", "getOptionsLabels", "resetOptions", "displayOptions", \ "ignoreRule", "resetIgnoreRules", "reactivateRule", "listRules", "displayRules", "setWriterUnderliningStyle" ] __version__ = "${version}" @@ -44,38 +44,34 @@ # Modules _rules = None # module gc_rules _rules_graph = None # module gc_rules_graph # Data -_sAppContext = "" # what software is running -_dOptions = None -_dOptionsColors = None _oSpellChecker = None _oTokenizer = None _aIgnoredRules = set() # Writer underlining style +_dOptionsColors = None _bMulticolor = True _nUnderliningStyle = 0 #### Initialization def load (sContext="Python", sColorType="aRGB"): "initialization of the grammar checker" global _oSpellChecker - global _sAppContext - global _dOptions global _dOptionsColors global _oTokenizer try: _oSpellChecker = SpellChecker("${lang}", "${dic_main_filename_py}", "${dic_community_filename_py}", "${dic_personal_filename_py}") - _sAppContext = sContext - _dOptions = gc_options.getOptions(sContext).copy() # duplication necessary, to be able to reset to default - _dOptionsColors = gc_options.getOptionsColors(sContext, sColorType) + _oSpellChecker.activateStorage() _oTokenizer = _oSpellChecker.getTokenizer() - _oSpellChecker.activateStorage() + gce_func.load(sContext, _oSpellChecker) + gc_options.load(sContext) + _dOptionsColors = gc_options.getOptionsColors(sContext, sColorType) except: traceback.print_exc() def getSpellChecker (): @@ -155,53 +151,10 @@ "display the name of rules, with the filter " echo("List of rules. Filter: << " + str(sFilter) + " >>") for sOption, sLineId, sRuleId, sType in listRules(sFilter): echo("{:<8} {:<10} {:<10} {}".format(sOption, sLineId, sRuleId, sType)) - -#### Options - -def setOption (sOpt, bVal): - "set option with if it exists" - if sOpt in _dOptions: - _dOptions[sOpt] = bVal - - -def setOptions (dOpt): - "update the dictionary of options with " - for sKey, bVal in dOpt.items(): - if sKey in _dOptions: - _dOptions[sKey] = bVal - - -def getOptions (): - "return the dictionary of current options" - return _dOptions - - -def getDefaultOptions (): - "return the dictionary of default options" - return gc_options.getOptions(_sAppContext).copy() - - -def getOptionsLabels (sLang): - "return options labels" - return gc_options.getUI(sLang) - - -def displayOptions (sLang="${lang}"): - "display the list of grammar checking options" - echo("Options:") - echo("\n".join( [ k+":\t"+str(v)+"\t"+gc_options.getUI(sLang).get(k, ("?", ""))[0] for k, v in sorted(_dOptions.items()) ] )) - echo("") - - -def resetOptions (): - "set options to default values" - global _dOptions - _dOptions = getDefaultOptions() - def setWriterUnderliningStyle (sStyle="BOLDWAVE", bMulticolor=True): "set underlining style for Writer (WAVE, BOLDWAVE, BOLD)" global _nUnderliningStyle global _bMulticolor @@ -262,12 +215,12 @@ return s def parse (self, sCountry="${country_default}", bDebug=False, dOptions=None, bContext=False, bFullInfo=False): "analyses and returns an iterable of errors or (with option ) paragraphs errors and sentences with tokens and errors" #sText = unicodedata.normalize("NFC", sText) - dOpt = dOptions or _dOptions - bShowRuleId = option('idrule') + dOpt = dOptions or gc_options.dOptions + bShowRuleId = gc_options.dOptions.get('idrule', False) # parse paragraph try: self.parseText(self.sText, self.sText0, True, 0, sCountry, dOpt, bShowRuleId, bDebug, bContext) except: raise @@ -340,11 +293,11 @@ for m in zRegex.finditer(sText): bCondMemo = None for sFuncCond, cActionType, sWhat, *eAct in lActions: # action in lActions: [ condition, action type, replacement/suggestion/action[, iGroup[, message, URL]] ] try: - bCondMemo = not sFuncCond or globals()[sFuncCond](sText, sText0, m, self.dTokenPos, sCountry, bCondMemo) + bCondMemo = not sFuncCond or getattr(gce_func, sFuncCond)(sText, sText0, m, self.dTokenPos, sCountry, bCondMemo) if bCondMemo: if bDebug: echo("RULE: " + sLineId) if cActionType == "-": # grammar error @@ -360,11 +313,11 @@ if bDebug: echo("~ " + sText + " -- " + m.group(eAct[0]) + " # " + sLineId) elif cActionType == "=": # disambiguation if not bParagraph: - globals()[sWhat](sText, m, self.dTokenPos) + getattr(gce_func, sWhat)(sText, m, self.dTokenPos) if bDebug: echo("= " + m.group(0) + " # " + sLineId) elif cActionType == ">": # we do nothing, this test is just a condition to apply all following actions pass @@ -586,18 +539,18 @@ for sRuleId in dGraph[nextNodeKey]: try: if bDebug: echo(" >TRY: " + sRuleId + " " + sLineId) _, sOption, sFuncCond, cActionType, sWhat, *eAct = _rules_graph.dRule[sRuleId] - # Suggestion [ option, condition, "-", replacement/suggestion/action, iTokenStart, iTokenEnd, cStartLimit, cEndLimit, bCaseSvty, nPriority, sMessage, sURL ] - # TextProcessor [ option, condition, "~", replacement/suggestion/action, iTokenStart, iTokenEnd, bCaseSvty ] - # Disambiguator [ option, condition, "=", replacement/suggestion/action ] - # Tag [ option, condition, "/", replacement/suggestion/action, iTokenStart, iTokenEnd ] - # Immunity [ option, condition, "!", "", iTokenStart, iTokenEnd ] - # Test [ option, condition, ">", "" ] + # Suggestion [ sActionLineId, option, condition, "-", replacement/suggestion/action, iTokenStart, iTokenEnd, cStartLimit, cEndLimit, bCaseSvty, nPriority, sMessage, sURL ] + # TextProcessor [ sActionLineId, option, condition, "~", replacement/suggestion/action, iTokenStart, iTokenEnd, bCaseSvty ] + # Disambiguator [ sActionLineId, option, condition, "=", replacement/suggestion/action ] + # Tag [ sActionLineId, option, condition, "/", replacement/suggestion/action, iTokenStart, iTokenEnd ] + # Immunity [ sActionLineId, option, condition, "!", "", iTokenStart, iTokenEnd ] + # Test [ sActionLineId, option, condition, ">", "" ] if not sOption or dOptions.get(sOption, False): - bCondMemo = not sFuncCond or globals()[sFuncCond](self.lToken, nTokenOffset, nLastToken, sCountry, bCondMemo, self.dTags, self.sSentence, self.sSentence0) + bCondMemo = not sFuncCond or getattr(gce_func, sFuncCond)(self.lToken, nTokenOffset, nLastToken, sCountry, bCondMemo, self.dTags, self.sSentence, self.sSentence0) if bCondMemo: if cActionType == "-": # grammar error iTokenStart, iTokenEnd, cStartLimit, cEndLimit, bCaseSvty, nPriority, sMessage, sURL = eAct nTokenErrorStart = nTokenOffset + iTokenStart if iTokenStart > 0 else nLastToken + iTokenStart @@ -619,11 +572,11 @@ bChange = True if bDebug: echo(" TEXT_PROCESSOR: [{}:{}] > {}".format(self.lToken[nTokenStart]["sValue"], self.lToken[nTokenEnd]["sValue"], sWhat)) elif cActionType == "=": # disambiguation - globals()[sWhat](self.lToken, nTokenOffset, nLastToken) + getattr(gce_func, sWhat)(self.lToken, nTokenOffset, nLastToken) if bDebug: echo(" DISAMBIGUATOR: ({}) [{}:{}]".format(sWhat, self.lToken[nTokenOffset+1]["sValue"], self.lToken[nLastToken]["sValue"])) elif cActionType == ">": # we do nothing, this test is just a condition to apply all following actions if bDebug: @@ -674,20 +627,20 @@ def _createErrorFromRegex (self, sText, sText0, sRepl, nOffset, m, iGroup, sLineId, sRuleId, bUppercase, sMsg, sURL, bShowRuleId, sOption, bContext): nStart = nOffset + m.start(iGroup) nEnd = nOffset + m.end(iGroup) # suggestions if sRepl[0:1] == "=": - sSugg = globals()[sRepl[1:]](sText, m) + sSugg = getattr(gce_func, sRepl[1:])(sText, m) lSugg = sSugg.split("|") if sSugg else [] elif sRepl == "_": lSugg = [] else: lSugg = m.expand(sRepl).split("|") if bUppercase and lSugg and m.group(iGroup)[0:1].isupper(): lSugg = list(map(lambda s: s[0:1].upper()+s[1:], lSugg)) # Message - sMessage = globals()[sMsg[1:]](sText, m) if sMsg[0:1] == "=" else m.expand(sMsg) + sMessage = getattr(gce_func, sMsg[1:])(sText, m) if sMsg[0:1] == "=" else m.expand(sMsg) if bShowRuleId: sMessage += " #" + sLineId + " / " + sRuleId # if _bWriterError: return self._createErrorForWriter(nStart, nEnd - nStart, sRuleId, sOption, sMessage, lSugg, sURL) @@ -694,20 +647,20 @@ return self._createErrorAsDict(nStart, nEnd, sLineId, sRuleId, sOption, sMessage, lSugg, sURL, bContext) def _createErrorFromTokens (self, sSugg, nTokenOffset, nLastToken, iFirstToken, nStart, nEnd, sLineId, sRuleId, bCaseSvty, sMsg, sURL, bShowRuleId, sOption, bContext): # suggestions if sSugg[0:1] == "=": - sSugg = globals()[sSugg[1:]](self.lToken, nTokenOffset, nLastToken) + sSugg = getattr(gce_func, sSugg[1:])(self.lToken, nTokenOffset, nLastToken) lSugg = sSugg.split("|") if sSugg else [] elif sSugg == "_": lSugg = [] else: lSugg = self._expand(sSugg, nTokenOffset, nLastToken).split("|") if bCaseSvty and lSugg and self.lToken[iFirstToken]["sValue"][0:1].isupper(): lSugg = list(map(lambda s: s[0:1].upper()+s[1:], lSugg)) # Message - sMessage = globals()[sMsg[1:]](self.lToken, nTokenOffset, nLastToken) if sMsg[0:1] == "=" else self._expand(sMsg, nTokenOffset, nLastToken) + sMessage = getattr(gce_func, sMsg[1:])(self.lToken, nTokenOffset, nLastToken) if sMsg[0:1] == "=" else self._expand(sMsg, nTokenOffset, nLastToken) if bShowRuleId: sMessage += " #" + sLineId + " / " + sRuleId # if _bWriterError: return self._createErrorForWriter(nStart, nEnd - nStart, sRuleId, sOption, sMessage, lSugg, sURL) @@ -767,11 +720,11 @@ elif sRepl == "_": sNew = "_" * nLen elif sRepl == "@": sNew = "@" * nLen elif sRepl[0:1] == "=": - sNew = globals()[sRepl[1:]](sText, m) + sNew = getattr(gce_func, sRepl[1:])(sText, m) sNew = sNew + " " * (nLen-len(sNew)) if bUppercase and m.group(iGroup)[0:1].isupper(): sNew = sNew.capitalize() else: sNew = m.expand(sRepl) @@ -797,11 +750,11 @@ else: for i in range(nTokenRewriteStart, nTokenRewriteEnd+1): self.lToken[i]["sNewValue"] = "_" else: if sWhat.startswith("="): - sWhat = globals()[sWhat[1:]](self.lToken, nTokenOffset, nLastToken) + sWhat = getattr(gce_func, sWhat[1:])(self.lToken, nTokenOffset, nLastToken) else: sWhat = self._expand(sWhat, nTokenOffset, nLastToken) bUppercase = bCaseSvty and self.lToken[nTokenRewriteStart]["sValue"][0:1].isupper() if nTokenRewriteEnd - nTokenRewriteStart == 0: # one token @@ -871,410 +824,5 @@ echo(dToken) if bDebug: echo(" TEXT REWRITED: " + self.sSentence) self.lToken.clear() self.lToken = lNewToken - - -#### common functions - -def option (sOpt): - "return True if option is active" - return _dOptions.get(sOpt, False) - - -#### Functions to get text outside pattern scope - -# warning: check compile_rules.py to understand how it works - -_zNextWord = re.compile(r" +(\w[\w-]*)") -_zPrevWord = re.compile(r"(\w[\w-]*) +$") - -def nextword (s, iStart, n): - "get the nth word of the input string or empty string" - m = re.match("(?: +[\\w%-]+){" + str(n-1) + "} +([\\w%-]+)", s[iStart:]) - if not m: - return None - return (iStart+m.start(1), m.group(1)) - - -def prevword (s, iEnd, n): - "get the (-)nth word of the input string or empty string" - m = re.search("([\\w%-]+) +(?:[\\w%-]+ +){" + str(n-1) + "}$", s[:iEnd]) - if not m: - return None - return (m.start(1), m.group(1)) - - -def nextword1 (s, iStart): - "get next word (optimization)" - m = _zNextWord.match(s[iStart:]) - if not m: - return None - return (iStart+m.start(1), m.group(1)) - - -def prevword1 (s, iEnd): - "get previous word (optimization)" - m = _zPrevWord.search(s[:iEnd]) - if not m: - return None - return (m.start(1), m.group(1)) - - -def look (s, sPattern, sNegPattern=None): - "seek sPattern in s (before/after/fulltext), if sNegPattern not in s" - if sNegPattern and re.search(sNegPattern, s): - return False - if re.search(sPattern, s): - return True - return False - - -def look_chk1 (dTokenPos, s, nOffset, sPattern, sPatternGroup1, sNegPatternGroup1=""): - "returns True if s has pattern sPattern and m.group(1) has pattern sPatternGroup1" - m = re.search(sPattern, s) - if not m: - return False - try: - sWord = m.group(1) - nPos = m.start(1) + nOffset - except IndexError: - return False - return morph(dTokenPos, (nPos, sWord), sPatternGroup1, sNegPatternGroup1) - - - -#### Analyse groups for regex rules - -def displayInfo (dTokenPos, tWord): - "for debugging: retrieve info of word" - if not tWord: - echo("> nothing to find") - return True - lMorph = _oSpellChecker.getMorph(tWord[1]) - if not lMorph: - echo("> not in dictionary") - return True - echo("TOKENS:", dTokenPos) - if tWord[0] in dTokenPos and "lMorph" in dTokenPos[tWord[0]]: - echo("DA: " + str(dTokenPos[tWord[0]]["lMorph"])) - echo("FSA: " + str(lMorph)) - return True - - -def morph (dTokenPos, tWord, sPattern, sNegPattern="", bNoWord=False): - "analyse a tuple (position, word), returns True if not sNegPattern in word morphologies and sPattern in word morphologies (disambiguation on)" - if not tWord: - return bNoWord - lMorph = dTokenPos[tWord[0]]["lMorph"] if tWord[0] in dTokenPos and "lMorph" in dTokenPos[tWord[0]] else _oSpellChecker.getMorph(tWord[1]) - if not lMorph: - return False - # check negative condition - if sNegPattern: - if sNegPattern == "*": - # all morph must match sPattern - zPattern = re.compile(sPattern) - return all(zPattern.search(sMorph) for sMorph in lMorph) - zNegPattern = re.compile(sNegPattern) - if any(zNegPattern.search(sMorph) for sMorph in lMorph): - return False - # search sPattern - zPattern = re.compile(sPattern) - return any(zPattern.search(sMorph) for sMorph in lMorph) - - -def analyse (sWord, sPattern, sNegPattern=""): - "analyse a word, returns True if not sNegPattern in word morphologies and sPattern in word morphologies (disambiguation off)" - lMorph = _oSpellChecker.getMorph(sWord) - if not lMorph: - return False - # check negative condition - if sNegPattern: - if sNegPattern == "*": - zPattern = re.compile(sPattern) - return all(zPattern.search(sMorph) for sMorph in lMorph) - zNegPattern = re.compile(sNegPattern) - if any(zNegPattern.search(sMorph) for sMorph in lMorph): - return False - # search sPattern - zPattern = re.compile(sPattern) - return any(zPattern.search(sMorph) for sMorph in lMorph) - - -#### Analyse tokens for graph rules - -def g_value (dToken, sValues, nLeft=None, nRight=None): - "test if is in sValues (each value should be separated with |)" - sValue = "|"+dToken["sValue"]+"|" if nLeft is None else "|"+dToken["sValue"][slice(nLeft, nRight)]+"|" - if sValue in sValues: - return True - if dToken["sValue"][0:2].istitle(): # we test only 2 first chars, to make valid words such as "Laissez-les", "Passe-partout". - if sValue.lower() in sValues: - return True - elif dToken["sValue"].isupper(): - #if sValue.lower() in sValues: - # return True - sValue = "|"+sValue[1:].capitalize() - if sValue in sValues: - return True - sValue = sValue.lower() - if sValue in sValues: - return True - return False - - -def g_morph (dToken, sPattern, sNegPattern="", nLeft=None, nRight=None, bMemorizeMorph=True): - "analyse a token, return True if not in morphologies and in morphologies" - if "lMorph" in dToken: - lMorph = dToken["lMorph"] - else: - if nLeft is not None: - lMorph = _oSpellChecker.getMorph(dToken["sValue"][slice(nLeft, nRight)]) - if bMemorizeMorph: - dToken["lMorph"] = lMorph - else: - lMorph = _oSpellChecker.getMorph(dToken["sValue"]) - if not lMorph: - return False - # check negative condition - if sNegPattern: - if sNegPattern == "*": - # all morph must match sPattern - zPattern = re.compile(sPattern) - return all(zPattern.search(sMorph) for sMorph in lMorph) - zNegPattern = re.compile(sNegPattern) - if any(zNegPattern.search(sMorph) for sMorph in lMorph): - return False - # search sPattern - zPattern = re.compile(sPattern) - return any(zPattern.search(sMorph) for sMorph in lMorph) - - -def g_analyse (dToken, sPattern, sNegPattern="", nLeft=None, nRight=None, bMemorizeMorph=True): - "analyse a token, return True if not in morphologies and in morphologies (disambiguation off)" - if nLeft is not None: - lMorph = _oSpellChecker.getMorph(dToken["sValue"][slice(nLeft, nRight)]) - if bMemorizeMorph: - dToken["lMorph"] = lMorph - else: - lMorph = _oSpellChecker.getMorph(dToken["sValue"]) - if not lMorph: - return False - # check negative condition - if sNegPattern: - if sNegPattern == "*": - # all morph must match sPattern - zPattern = re.compile(sPattern) - return all(zPattern.search(sMorph) for sMorph in lMorph) - zNegPattern = re.compile(sNegPattern) - if any(zNegPattern.search(sMorph) for sMorph in lMorph): - return False - # search sPattern - zPattern = re.compile(sPattern) - return any(zPattern.search(sMorph) for sMorph in lMorph) - - -def g_merged_analyse (dToken1, dToken2, cMerger, sPattern, sNegPattern="", bSetMorph=True): - "merge two token values, return True if not in morphologies and in morphologies (disambiguation off)" - lMorph = _oSpellChecker.getMorph(dToken1["sValue"] + cMerger + dToken2["sValue"]) - if not lMorph: - return False - # check negative condition - if sNegPattern: - if sNegPattern == "*": - # all morph must match sPattern - zPattern = re.compile(sPattern) - bResult = all(zPattern.search(sMorph) for sMorph in lMorph) - if bResult and bSetMorph: - dToken1["lMorph"] = lMorph - return bResult - zNegPattern = re.compile(sNegPattern) - if any(zNegPattern.search(sMorph) for sMorph in lMorph): - return False - # search sPattern - zPattern = re.compile(sPattern) - bResult = any(zPattern.search(sMorph) for sMorph in lMorph) - if bResult and bSetMorph: - dToken1["lMorph"] = lMorph - return bResult - - -def g_tag_before (dToken, dTags, sTag): - "returns True if is present on tokens before " - if sTag not in dTags: - return False - if dToken["i"] > dTags[sTag][0]: - return True - return False - - -def g_tag_after (dToken, dTags, sTag): - "returns True if is present on tokens after " - if sTag not in dTags: - return False - if dToken["i"] < dTags[sTag][1]: - return True - return False - - -def g_tag (dToken, sTag): - "returns True if is present on token " - return "aTags" in dToken and sTag in dToken["aTags"] - - -def g_meta (dToken, sType): - "returns True if is equal to the token type" - return dToken["sType"] == sType - - -def g_space_between_tokens (dToken1, dToken2, nMin, nMax=None): - "checks if spaces between tokens is >= and <= " - nSpace = dToken2["nStart"] - dToken1["nEnd"] - if nSpace < nMin: - return False - if nMax is not None and nSpace > nMax: - return False - return True - - -def g_token (lToken, i): - "return token at index in lToken (or the closest one)" - if i < 0: - return lToken[0] - if i >= len(lToken): - return lToken[-1] - return lToken[i] - - - -#### Disambiguator for regex rules - -def select (dTokenPos, nPos, sWord, sPattern, lDefault=None): - "Disambiguation: select morphologies of matching " - if not sWord: - return True - if nPos not in dTokenPos: - echo("Error. There should be a token at this position: ", nPos) - return True - lMorph = _oSpellChecker.getMorph(sWord) - if not lMorph or len(lMorph) == 1: - return True - lSelect = [ sMorph for sMorph in lMorph if re.search(sPattern, sMorph) ] - if lSelect: - if len(lSelect) != len(lMorph): - dTokenPos[nPos]["lMorph"] = lSelect - elif lDefault: - dTokenPos[nPos]["lMorph"] = lDefault - return True - - -def exclude (dTokenPos, nPos, sWord, sPattern, lDefault=None): - "Disambiguation: exclude morphologies of matching " - if not sWord: - return True - if nPos not in dTokenPos: - echo("Error. There should be a token at this position: ", nPos) - return True - lMorph = _oSpellChecker.getMorph(sWord) - if not lMorph or len(lMorph) == 1: - return True - lSelect = [ sMorph for sMorph in lMorph if not re.search(sPattern, sMorph) ] - if lSelect: - if len(lSelect) != len(lMorph): - dTokenPos[nPos]["lMorph"] = lSelect - elif lDefault: - dTokenPos[nPos]["lMorph"] = lDefault - return True - - -def define (dTokenPos, nPos, lMorph): - "Disambiguation: set morphologies of token at with " - if nPos not in dTokenPos: - echo("Error. There should be a token at this position: ", nPos) - return True - dTokenPos[nPos]["lMorph"] = lMorph - return True - - -#### Disambiguation for graph rules - -def g_select (dToken, sPattern, lDefault=None): - "Disambiguation: select morphologies for according to , always return True" - lMorph = dToken["lMorph"] if "lMorph" in dToken else _oSpellChecker.getMorph(dToken["sValue"]) - if not lMorph or len(lMorph) == 1: - if lDefault: - dToken["lMorph"] = lDefault - #echo("DA:", dToken["sValue"], dToken["lMorph"]) - return True - lSelect = [ sMorph for sMorph in lMorph if re.search(sPattern, sMorph) ] - if lSelect: - if len(lSelect) != len(lMorph): - dToken["lMorph"] = lSelect - elif lDefault: - dToken["lMorph"] = lDefault - #echo("DA:", dToken["sValue"], dToken["lMorph"]) - return True - - -def g_exclude (dToken, sPattern, lDefault=None): - "Disambiguation: select morphologies for according to , always return True" - lMorph = dToken["lMorph"] if "lMorph" in dToken else _oSpellChecker.getMorph(dToken["sValue"]) - if not lMorph or len(lMorph) == 1: - if lDefault: - dToken["lMorph"] = lDefault - #echo("DA:", dToken["sValue"], dToken["lMorph"]) - return True - lSelect = [ sMorph for sMorph in lMorph if not re.search(sPattern, sMorph) ] - if lSelect: - if len(lSelect) != len(lMorph): - dToken["lMorph"] = lSelect - elif lDefault: - dToken["lMorph"] = lDefault - #echo("DA:", dToken["sValue"], dToken["lMorph"]) - return True - - -def g_add_morph (dToken, lNewMorph): - "Disambiguation: add a morphology to a token" - lMorph = dToken["lMorph"] if "lMorph" in dToken else _oSpellChecker.getMorph(dToken["sValue"]) - lMorph.extend(lNewMorph) - dToken["lMorph"] = lMorph - return True - - -def g_define (dToken, lMorph): - "Disambiguation: set morphologies of , always return True" - dToken["lMorph"] = lMorph - #echo("DA:", dToken["sValue"], lMorph) - return True - - -def g_define_from (dToken, nLeft=None, nRight=None): - "Disambiguation: set morphologies of with slicing its value with and " - if nLeft is not None: - dToken["lMorph"] = _oSpellChecker.getMorph(dToken["sValue"][slice(nLeft, nRight)]) - else: - dToken["lMorph"] = _oSpellChecker.getMorph(dToken["sValue"]) - return True - - -def g_change_meta (dToken, sType): - "Disambiguation: change type of token" - dToken["sType"] = sType - return True - - - -#### GRAMMAR CHECKER PLUGINS - -${plugins} - - -#### CALLABLES FOR REGEX RULES (generated code) - -${callables} - - -#### CALLABLES FOR GRAPH RULES (generated code) - -${graph_callables} Index: gc_core/py/lang_core/gc_options.py ================================================================== --- gc_core/py/lang_core/gc_options.py +++ gc_core/py/lang_core/gc_options.py @@ -1,42 +1,83 @@ """ Grammar checker default options """ # generated code, do not edit +# source: gc_core/py/lang_core/gc_options.py import traceback + +dOptions = {} + +_sAppContext = "Python" + + +def load (sContext="Python"): + global dOptions + global _sAppContext + _sAppContext = sContext + dOptions = getDefaultOptions(sContext) + + +def setOption (sOpt, bVal): + "set option with if it exists" + if sOpt in dOptions: + dOptions[sOpt] = bVal + + +def setOptions (dOpt): + "update the dictionary of options with " + for sKey, bVal in dOpt.items(): + if sKey in dOptions: + dOptions[sKey] = bVal + + +def resetOptions (): + "set options to default values" + global dOptions + dOptions = getDefaultOptions() + + +def displayOptions (sLang="${lang}"): + "display the list of grammar checking options" + print("Options:") + print("\n".join( [ k+":\t"+str(v)+"\t"+getUI(sLang).get(k, ("?", ""))[0] for k, v in sorted(dOptions.items()) ] )) + print("") + def getUI (sLang): "returns dictionary of UI labels" if sLang in _dOptLabel: return _dOptLabel[sLang] return _dOptLabel["fr"] -def getOptions (sContext="Python"): +def getDefaultOptions (sContext=""): "returns dictionary of options" - if sContext in _dOpt: - return _dOpt[sContext] - return _dOpt["Python"] + if not sContext: + sContext = _sAppContext + if sContext in _dDefaultOpt: + return _dDefaultOpt[sContext].copy() # duplication necessary, to be able to reset to default + return _dDefaultOpt["Python"].copy() # duplication necessary, to be able to reset to default def getOptionsColors (sTheme="Default", sColorType="aRGB"): "returns dictionary of options colors" dOptColor = _dOptColor[sTheme] if sTheme in _dOptColor else _dOptColor["Default"] dColorType = _dColorType[sColorType] if sColorType in _dColorType else _dColorType["aRGB"] try: - return { sOpt: dColorType[sColor] for sOpt, sColor in dOptColor.items() } + return { sOpt: dColorType[sColor] for sOpt, sColor in dOptColor.items() } except KeyError: traceback.print_exc() return {} lStructOpt = ${lStructOpt} -_dOpt = { +_dDefaultOpt = { "Python": ${dOptPython}, "Server": ${dOptServer}, "Writer": ${dOptWriter} } Index: gc_core/py/oxt/Grammalecte.py ================================================================== --- gc_core/py/oxt/Grammalecte.py +++ gc_core/py/oxt/Grammalecte.py @@ -13,36 +13,36 @@ from com.sun.star.linguistic2 import ProofreadingResult from com.sun.star.lang import XServiceInfo, XServiceName, XServiceDisplayName from com.sun.star.lang import Locale import helpers -import grammalecte.${lang} as gce +import grammalecte.${lang} as gc_engine #import lightproof_handler_${implname} as opt_handler import Options class Grammalecte (unohelper.Base, XProofreader, XServiceInfo, XServiceName, XServiceDisplayName, XSupportedLocales): def __init__ (self, ctx, *args): self.ctx = ctx self.ServiceName = "com.sun.star.linguistic2.Proofreader" - self.ImplementationName = "org.openoffice.comp.pyuno.Lightproof." + gce.pkg + self.ImplementationName = "org.openoffice.comp.pyuno.Lightproof." + gc_engine.pkg self.SupportedServiceNames = (self.ServiceName, ) self.locales = [] - for i in gce.locales: - l = gce.locales[i] + for i in gc_engine.locales: + l = gc_engine.locales[i] self.locales.append(Locale(l[0], l[1], l[2])) self.locales = tuple(self.locales) # debug #helpers.startConsole() # init - gce.load("Writer", "nInt") + gc_engine.load("Writer", "nInt") # GC options #xContext = uno.getComponentContext() #opt_handler.load(xContext) dOpt = Options.loadOptions("${lang}") - gce.setOptions(dOpt) + gc_engine.gc_options.setOptions(dOpt) # dictionaries options self.loadUserDictionaries() # underlining options self.setWriterUnderliningStyle() # store for results of big paragraphs @@ -109,11 +109,11 @@ # WORKAROUND ->>> xRes.nBehindEndOfSentencePosition = xRes.nStartOfNextSentencePosition try: - xRes.aErrors = tuple(gce.parse(rText, rLocale.Country)) + xRes.aErrors = tuple(gc_engine.parse(rText, rLocale.Country)) # ->>> WORKAROUND if xRes.nStartOfNextSentencePosition > 3000: self.dResult[nHashedVal] = xRes self.nRes += 1 if self.nRes > self.nMaxRes: @@ -124,31 +124,31 @@ except: traceback.print_exc() return xRes def ignoreRule (self, rid, aLocale): - gce.ignoreRule(rid) + gc_engine.ignoreRule(rid) def resetIgnoreRules (self): - gce.resetIgnoreRules() + gc_engine.resetIgnoreRules() # XServiceDisplayName def getServiceDisplayName (self, aLocale): - return gce.name + return gc_engine.name # Grammalecte def getSpellChecker (self): - return gce.getSpellChecker() + return gc_engine.getSpellChecker() def loadUserDictionaries (self): try: xSettingNode = helpers.getConfigSetting("/org.openoffice.Lightproof_${implname}/Other/", False) xChild = xSettingNode.getByName("o_${lang}") if xChild.getPropertyValue("use_personal_dic"): sJSON = xChild.getPropertyValue("personal_dic") if sJSON: - oSpellChecker = gce.getSpellChecker(); + oSpellChecker = gc_engine.getSpellChecker(); oSpellChecker.setPersonalDictionary(json.loads(sJSON)) except: traceback.print_exc() def setWriterUnderliningStyle (self): @@ -155,15 +155,15 @@ try: xSettingNode = helpers.getConfigSetting("/org.openoffice.Lightproof_${implname}/Other/", False) xChild = xSettingNode.getByName("o_${lang}") sLineType = xChild.getPropertyValue("line_type") bMulticolor = bool(xChild.getPropertyValue("line_multicolor")) - gce.setWriterUnderliningStyle(sLineType, bMulticolor) + gc_engine.setWriterUnderliningStyle(sLineType, bMulticolor) except: traceback.print_exc() g_ImplementationHelper = unohelper.ImplementationHelper() -g_ImplementationHelper.addImplementation(Grammalecte, "org.openoffice.comp.pyuno.Lightproof."+gce.pkg, ("com.sun.star.linguistic2.Proofreader",),) +g_ImplementationHelper.addImplementation(Grammalecte, "org.openoffice.comp.pyuno.Lightproof."+gc_engine.pkg, ("com.sun.star.linguistic2.Proofreader",),) # g_ImplementationHelper.addImplementation( opt_handler.LightproofOptionsEventHandler, \ -# "org.openoffice.comp.pyuno.LightproofOptionsEventHandler." + gce.pkg, ("com.sun.star.awt.XContainerWindowEventHandler",),) +# "org.openoffice.comp.pyuno.LightproofOptionsEventHandler." + gc_engine.pkg, ("com.sun.star.awt.XContainerWindowEventHandler",),) Index: gc_core/py/oxt/Options.py ================================================================== --- gc_core/py/oxt/Options.py +++ gc_core/py/oxt/Options.py @@ -11,30 +11,30 @@ import helpers import op_strings try: - import grammalecte.${lang} as gce + import grammalecte.${lang} as gc_engine except: traceback.print_exc() def loadOptions (sLang): "load options from Grammalecte and change them according to LibreOffice settings, returns a dictionary {option_name: boolean}" try: xNode = helpers.getConfigSetting("/org.openoffice.Lightproof_${implname}/Leaves", False) xChild = xNode.getByName(sLang) - dOpt = gce.gc_options.getOptions("Writer") + dOpt = gc_engine.gc_options.getDefaultOptions("Writer") for sKey in dOpt: sValue = xChild.getPropertyValue(sKey) if sValue != '': dOpt[sKey] = bool(int(sValue)) return dOpt except: print("# Error. Unable to load options of language:", sLang) traceback.print_exc() - return gce.gc_options.getOptions("Writer") + return gc_engine.gc_options.getDefaultOptions("Writer") def saveOptions (sLang, dOpt): "save options in LibreOffice profile" try: @@ -70,11 +70,11 @@ return xWidget def run (self, sUI): try: dUI = op_strings.getUI(sUI) - dOptionUI = gce.gc_options.getUI(sUI) + dOptionUI = gc_engine.gc_options.getUI(sUI) # fonts xFDTitle = uno.createUnoStruct("com.sun.star.awt.FontDescriptor") xFDTitle.Height = 9 xFDTitle.Weight = uno.getConstantByName("com.sun.star.awt.FontWeight.BOLD") @@ -99,11 +99,11 @@ self.lOptionWidgets = [] sProdName, sVersion = helpers.getProductNameAndVersion() if True: # no tab available (bug) - for sOptionType, lOptions in gce.gc_options.lStructOpt: + for sOptionType, lOptions in gc_engine.gc_options.lStructOpt: x = 10 y += 10 self._addWidget(sOptionType, 'FixedLine', x, y, nWidth, nHeight, Label = dOptionUI.get(sOptionType, "#err")[0], FontDescriptor= xFDTitle) y += 3 for lOptLine in lOptions: @@ -162,11 +162,11 @@ # XActionListener def actionPerformed (self, xActionEvent): try: if xActionEvent.ActionCommand == 'Default': - self._setWidgets(gce.gc_options.getOptions("Writer")) + self._setWidgets(gc_engine.gc_options.getDefaultOptions("Writer")) elif xActionEvent.ActionCommand == 'Apply': self._save("${lang}") self.xContainer.endExecute() elif xActionEvent.ActionCommand == 'Cancel': self.xContainer.endExecute() @@ -181,8 +181,8 @@ w.State = dOpt.get(w.Name, False) def _save (self, sLang): try: saveOptions(sLang, { w.Name: str(w.State) for w in self.lOptionWidgets }) - gce.setOptions({ w.Name: bool(w.State) for w in self.lOptionWidgets }) + gc_engine.gc_options.setOptions({ w.Name: bool(w.State) for w in self.lOptionWidgets }) except: traceback.print_exc() Index: gc_lang/fr/modules/tests.py ================================================================== --- gc_lang/fr/modules/tests.py +++ gc_lang/fr/modules/tests.py @@ -10,11 +10,12 @@ import time from contextlib import contextmanager from ..graphspell.ibdawg import IBDAWG from ..graphspell.echo import echo -from . import gc_engine as gce +from . import gc_engine +from . import gc_options from . import conj from . import phonet from . import mfsp @@ -32,20 +33,20 @@ def perf (sVersion, hDst=None): "performance tests" print("\nPerformance tests") - gce.load() - gce.parse("Texte sans importance… utile pour la compilation des règles avant le calcul des perfs.") + gc_engine.load() + gc_engine.parse("Texte sans importance… utile pour la compilation des règles avant le calcul des perfs.") spHere, _ = os.path.split(__file__) with open(os.path.join(spHere, "perf.txt"), "r", encoding="utf-8") as hSrc: if hDst: hDst.write("{:<12}{:<20}".format(sVersion, time.strftime("%Y.%m.%d %H:%M"))) for sText in ( s.strip() for s in hSrc if not s.startswith("#") and s.strip() ): with timeblock(sText[:sText.find(".")], hDst): - gce.parse(sText) + gc_engine.parse(sText) if hDst: hDst.write("\n") def _fuckBackslashUTF8 (s): @@ -157,11 +158,11 @@ class TestGrammarChecking (unittest.TestCase): "Tests du correcteur grammatical" @classmethod def setUpClass (cls): - gce.load() + gc_engine.load() cls._zError = re.compile(r"\{\{.*?\}\}") cls._aTestedRules = set() def test_parse (self): zOption = re.compile("^__([a-zA-Z0-9]+)__ ") @@ -205,11 +206,11 @@ if nError: print("Unexpected errors:", nError) # untested rules i = 0 echo("Untested rules:") - for _, sOpt, sLineId, sRuleId in gce.listRules(): + for _, sOpt, sLineId, sRuleId in gc_engine.listRules(): if sOpt != "@@@@" and sRuleId not in self._aTestedRules and not re.search("^[0-9]+[sp]$|^[pd]_", sRuleId): echo(sLineId + "/" + sRuleId) i += 1 echo("[{} untested rules]".format(i)) @@ -217,15 +218,15 @@ sText, sSugg = sLine.split("->>") return (sText.strip(), sSugg.strip()) def _getFoundErrors (self, sLine, sOption): if sOption: - gce.setOption(sOption, True) - aErrs = gce.parse(sLine) - gce.setOption(sOption, False) + gc_options.setOption(sOption, True) + aErrs = gc_engine.parse(sLine) + gc_options.setOption(sOption, False) else: - aErrs = gce.parse(sLine) + aErrs = gc_engine.parse(sLine) sRes = " " * len(sLine) sListErr = "" lAllSugg = [] for dErr in aErrs: sRes = sRes[:dErr["nStart"]] + "~" * (dErr["nEnd"] - dErr["nStart"]) + sRes[dErr["nEnd"]:]