// Return true if a spelling error occurs in the word that is the specified substring of m_text. bool CheckWord(int ichMinWord, int ichLimWord) { string word = TsStringUtils.NormalizeToNFC(m_text.Substring(ichMinWord, ichLimWord - ichMinWord)); TsRunInfo tri; ITsTextProps props = m_tss.FetchRunInfoAt(ichMinWord, out tri); int var; int ws = props.GetIntPropValues((int)FwTextPropType.ktptWs, out var); bool fFoundOurWs = (ws == m_ws); bool fFoundOtherWs = (ws != m_ws); while (tri.ichLim < ichLimWord) { props = m_tss.FetchRunInfoAt(tri.ichLim, out tri); ws = props.GetIntPropValues((int)FwTextPropType.ktptWs, out var); fFoundOurWs |= (ws == m_ws); fFoundOtherWs |= (ws != m_ws); } if (!fFoundOurWs) { return(false); // don't check words with nothing in interesting WS. } if (fFoundOtherWs) { return(true); // mixed writing system in a 'word' always counts as a 'spelling' error. } return(!m_dict.Check(word)); // succeed if check fails! }
public ICollection<SpellCorrectMenuItem> GetSuggestions(Point mousePos, SimpleRootSite rootsite, out int hvoObj, out int tag, out int wsAlt, out int wsText, out string word, out ISpellEngine dict, out bool nonSpellingError) { hvoObj = tag = wsAlt = wsText = 0; // make compiler happy for early returns word = null; dict = null; nonSpellingError = true; IVwRootBox rootb = rootsite != null ? rootsite.RootBox : null; if (rootb == null) return null; // Get a selection at the indicated point. IVwSelection sel = rootsite.GetSelectionAtPoint(mousePos, false); // Get the selected word and verify that it is a single run within a single // editable string. if (sel != null) sel = sel.GrowToWord(); if (sel == null || !sel.IsRange || sel.SelType != VwSelType.kstText || !SelectionHelper.IsEditable(sel)) return null; ITsString tss; bool fAssocPrev; int ichAnchor; sel.TextSelInfo(false, out tss, out ichAnchor, out fAssocPrev, out hvoObj, out tag, out wsAlt); int ichEnd, hvoObjE, tagE, wsE; sel.TextSelInfo(true, out tss, out ichEnd, out fAssocPrev, out hvoObjE, out tagE, out wsE); if (hvoObj != hvoObjE || tag != tagE || wsAlt != wsE) return null; int ichMin = Math.Min(ichEnd, ichAnchor); int ichLim = Math.Max(ichEnd, ichAnchor); ILgWritingSystemFactory wsf = rootsite.RootBox.DataAccess.WritingSystemFactory; // May need to enlarge the word beyond what GrowToWord does, if there is adjacent wordforming material. int ichMinAdjust = AdjustWordBoundary(wsf, tss, ichMin, -1, 0) + 1; // further expanded start of word. int ichLimAdjust = AdjustWordBoundary(wsf, tss, ichLim - 1, 1, tss.Length); // further expanded lim of word. // From the ends we can strip stuff with different spell-checking properties. IVwStylesheet styles = rootsite.RootBox.Stylesheet; int spellProps = SpellCheckProps(tss, ichMin, styles); while (ichMinAdjust < ichMin && SpellCheckProps(tss, ichMinAdjust, styles) != spellProps) ichMinAdjust++; while (ichLimAdjust > ichLim && SpellCheckProps(tss, ichLimAdjust - 1, styles) != spellProps) ichLimAdjust--; ichMin = ichMinAdjust; ichLim = ichLimAdjust; ITsStrFactory tsf = TsStrFactoryClass.Create(); // Now we have the specific range we will check. Get the actual string. ITsStrBldr bldr = tss.GetBldr(); if (ichLim < bldr.Length) bldr.ReplaceTsString(ichLim, bldr.Length, null); if (ichMin > 0) bldr.ReplaceTsString(0, ichMin, null); ITsString tssWord = bldr.GetString(); // See whether we need the special blue underline, which is used mainly for adjacent words in different writing systems. List<int> wss = TsStringUtils.GetWritingSystems(tssWord); if (wss.Count > 1) return MakeWssSuggestions(tssWord, wss, rootb, hvoObj, tag, wsAlt, ichMin, ichLim); ITsString keepOrcs; // holds any ORCs we found in the original word that we need to keep rather than reporting. IList<SpellCorrectMenuItem> result = MakeEmbeddedNscSuggestion(ref tssWord, styles, rootb, hvoObj, tag, wsAlt, ichMin, ichLim, out keepOrcs); if (result.Count > 0) return result; // Determine whether it is a spelling problem. wsText = TsStringUtils.GetWsOfRun(tssWord, 0); dict = SpellingHelper.GetSpellChecker(wsText, wsf); if (dict == null) return null; word = tssWord.get_NormalizedForm(FwNormalizationMode.knmNFC).Text; if (word == null) return null; // don't think this can happen, but... if (dict.Check(word)) return null; // not mis-spelled. // Get suggestions. Make sure to return an empty collection rather than null, even if no suggestions, // to indicate an error. ICollection<string> suggestions = dict.Suggest(word); foreach (string suggest in suggestions) { ITsString replacement = tsf.MakeStringRgch(suggest, suggest.Length, wsText); if (keepOrcs != null) { ITsStrBldr bldrRep = keepOrcs.GetBldr(); bldrRep.ReplaceTsString(0, 0, replacement); replacement = bldrRep.GetString(); } result.Add(new SpellCorrectMenuItem(rootb, hvoObj, tag, wsAlt, ichMin, ichLim, suggest, replacement)); } nonSpellingError = false; // it IS a spelling problem. return result; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Get a list of suggested corrections if the selection is a spelling or similar error. /// Returns null if there is no problem at the selection location. /// Note that it may also return an empty list; this has a distinct meaning, namely, /// that there IS a problem, but we have no useful suggestions for what to change it to. /// nonSpellingError is set true when the error is not simply a mis-spelled word in a /// single writing system; currently this should disable or hide the commands to add /// the word to the dictionary or change multiple occurrences. /// The input arguments indicate where the user clicked and allow us to find the /// text he might be trying to correct. The other output arguments indicate which WS /// (wasAlt -- 0 for simple string) of which property (tag) of which object (hvoObj) /// is affected by the change, the ws of the mis-spelled word, and the corresponding /// spelling engine. Much of this information is already known to the /// SpellCorrectMenuItems returned, but some clients use it in creating other menu options. /// </summary> /// ------------------------------------------------------------------------------------ public ICollection <SpellCorrectMenuItem> GetSuggestions(Point mousePos, SimpleRootSite rootsite, out int hvoObj, out int tag, out int wsAlt, out int wsText, out string word, out ISpellEngine dict, out bool nonSpellingError) { hvoObj = tag = wsAlt = wsText = 0; // make compiler happy for early returns word = null; dict = null; nonSpellingError = true; IVwRootBox rootb = rootsite != null ? rootsite.RootBox : null; if (rootb == null) { return(null); } // Get a selection at the indicated point. IVwSelection sel = rootsite.GetSelectionAtPoint(mousePos, false); // Get the selected word and verify that it is a single run within a single // editable string. if (sel != null) { sel = sel.GrowToWord(); } if (sel == null || !sel.IsRange || sel.SelType != VwSelType.kstText || !SelectionHelper.IsEditable(sel)) { return(null); } ITsString tss; bool fAssocPrev; int ichAnchor; sel.TextSelInfo(false, out tss, out ichAnchor, out fAssocPrev, out hvoObj, out tag, out wsAlt); int ichEnd, hvoObjE, tagE, wsE; sel.TextSelInfo(true, out tss, out ichEnd, out fAssocPrev, out hvoObjE, out tagE, out wsE); if (hvoObj != hvoObjE || tag != tagE || wsAlt != wsE) { return(null); } int ichMin = Math.Min(ichEnd, ichAnchor); int ichLim = Math.Max(ichEnd, ichAnchor); ILgWritingSystemFactory wsf = rootsite.RootBox.DataAccess.WritingSystemFactory; // May need to enlarge the word beyond what GrowToWord does, if there is adjacent wordforming material. int ichMinAdjust = AdjustWordBoundary(wsf, tss, false, ichMin, 0) + 1; // further expanded start of word. int ichLimAdjust = AdjustWordBoundary(wsf, tss, true, ichLim - 1, tss.Length); // further expanded lim of word. // From the ends we can strip stuff with different spell-checking properties. IVwStylesheet styles = rootsite.RootBox.Stylesheet; int spellProps = SpellCheckProps(tss, ichMin, styles); while (ichMinAdjust < ichMin && SpellCheckProps(tss, ichMinAdjust, styles) != spellProps) { ichMinAdjust++; } while (ichLimAdjust > ichLim && SpellCheckProps(tss, ichLimAdjust - 1, styles) != spellProps) { ichLimAdjust--; } ichMin = ichMinAdjust; ichLim = ichLimAdjust; // Now we have the specific range we will check. Get the actual string. ITsStrBldr bldr = tss.GetBldr(); if (ichLim < bldr.Length) { bldr.ReplaceTsString(ichLim, bldr.Length, null); } if (ichMin > 0) { bldr.ReplaceTsString(0, ichMin, null); } ITsString tssWord = bldr.GetString(); // See whether we need the special blue underline, which is used mainly for adjacent words in different writing systems. List <int> wss = TsStringUtils.GetWritingSystems(tssWord); if (wss.Count > 1) { return(MakeWssSuggestions(tssWord, wss, rootb, hvoObj, tag, wsAlt, ichMin, ichLim)); } ITsString keepOrcs; // holds any ORCs we found in the original word that we need to keep rather than reporting. IList <SpellCorrectMenuItem> result = MakeEmbeddedNscSuggestion(ref tssWord, styles, rootb, hvoObj, tag, wsAlt, ichMin, ichLim, out keepOrcs); if (result.Count > 0) { return(result); } // Determine whether it is a spelling problem. wsText = TsStringUtils.GetWsOfRun(tssWord, 0); dict = SpellingHelper.GetSpellChecker(wsText, wsf); if (dict == null) { return(null); } word = tssWord.get_NormalizedForm(FwNormalizationMode.knmNFC).Text; if (word == null) { return(null); // don't think this can happen, but... } if (dict.Check(word)) { return(null); // not mis-spelled. } // Get suggestions. Make sure to return an empty collection rather than null, even if no suggestions, // to indicate an error. ICollection <string> suggestions = dict.Suggest(word); foreach (string suggest in suggestions) { ITsString replacement = TsStringUtils.MakeString(suggest, wsText); if (keepOrcs != null) { ITsStrBldr bldrRep = keepOrcs.GetBldr(); bldrRep.ReplaceTsString(0, 0, replacement); replacement = bldrRep.GetString(); } result.Add(new SpellCorrectMenuItem(rootb, hvoObj, tag, wsAlt, ichMin, ichLim, suggest, replacement)); } nonSpellingError = false; // it IS a spelling problem. return(result); }