RichEdit: Now suggesting spelling fixes

git-svn-id: svn://ultimatepp.org/upp/trunk@12679 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2019-01-19 15:32:48 +00:00
parent 4603d561e2
commit 89febbfa1d
5 changed files with 142 additions and 4 deletions

View file

@ -319,4 +319,115 @@ void SpellerAdd(const WString& w, int lang)
}
}
struct WordDistanceTester {
byte pchars[256];
byte wchars[256];
byte pairs[256 * 256];
int used_pairs[256]; // store used positions in pairs to be able to clear them at exit
int used_pairs_count; // count of pairs
int Get(const String& w, const String& p);
WordDistanceTester();
};
WordDistanceTester::WordDistanceTester()
{
Zero(pchars);
Zero(wchars);
Zero(pairs);
Zero(used_pairs);
used_pairs_count = 0;
}
int WordDistanceTester::Get(const String& p, const String& w)
{
if(abs(p.GetLength() - w.GetLength()) > 4 || w.GetCount() > 200 || p.GetCount() > 200)
return INT_MAX;
VectorMap<int, int> chars;
for(int i = 0; i < p.GetCount(); i++)
pchars[(byte)p[i]]++;
int score = 0;
String pp;
VectorMap<int, int> found;
for(int i = 0; i < w.GetCount(); i++) {
int c = (byte)w[i];
if(pchars[c]) {
pchars[c]--;
wchars[c]++;
score++;
LLOG("Letter " << (char)w[i]);
}
}
int first = 0;
used_pairs_count = 0;
for(int i = 0; i < p.GetCount(); i++) {
int c = p[i];
if(wchars[c]) {
wchars[c]--;
if(first) {
LLOG("Pair " << (char)first << (char)c);
int pairi = MAKEWORD(first, c);
pairs[pairi]++;
used_pairs[used_pairs_count++] = pairi;
}
first = c;
}
}
for(int i = 1; i < w.GetCount(); i++) {
int pairi = MAKEWORD(w[i - 1], w[i]);
if(pairs[pairi]) {
pairs[pairi]--;
score++;
}
}
score -= abs(p.GetLength() - w.GetLength());
Zero(pchars);
Zero(wchars);
for(int i = 0; i < used_pairs_count; i++)
pairs[used_pairs[i]] = 0;
return -score;
}
Vector<String> SpellerFindCloseWords(int lang, const String& w, int n)
{
Vector<String> r;
Vector<int> min_distance;
if(n < 1)
return r;
String aw = ToUpper(ToAscii(w));
One<WordDistanceTester> tester;
tester.Create();
AllSpellerWords(lang, [&] (String h) -> bool {
if(abs(h.GetLength() - w.GetLength()) < 5) {
int d = tester->Get(Utf8ToUpperAscii(h), aw);
if(min_distance.GetCount() == 0) {
min_distance.Add(d);
r.Add(h);
}
else
if(d <= min_distance.Top()) {
int ii = min_distance.GetCount() - 1;
while(ii > 0 && d < min_distance[ii - 1])
ii--;
min_distance.Insert(ii, d);
r.Insert(ii, h);
if(r.GetCount() > n) {
r.Trim(n);
min_distance.Trim(n);
}
}
}
return false;
});
return r;
}
};

View file

@ -493,6 +493,7 @@ bool SpellWord(const WString& ws, int lang);
bool SpellWord(const wchar *ws, int len, int lang);
void SpellerAdd(const WString& w, int lang);
bool AllSpellerWords(int lang, Gate<String> iter);
Vector<String> SpellerFindCloseWords(int lang, const String& w, int n);
String GetP7Signature(const void *data, int length, const String& cert_pem, const String& pkey_pem);
String GetP7Signature(const String& data, const String& cert_pem, const String& pkey_pem);

View file

@ -365,18 +365,28 @@ bool RichEdit::RemoveSelection(bool back)
return false;
}
WString RichEdit::GetWordAtCursor()
void RichEdit::GetWordAtCursorPos(int& pos, int& count)
{
WString w;
int c = cursor;
pos = count = 0;
if(IsLetter(text[c])) {
while(c > 0 && IsLetter(text[c - 1]))
c--;
while(w.GetLength() < 64 && IsLetter(text[c])) {
w.Cat(text[c]);
pos = c;
while(w.GetLength() < 64 && IsLetter(text[c]))
c++;
}
count = c - pos;
}
}
WString RichEdit::GetWordAtCursor()
{
int pos, count;
GetWordAtCursorPos(pos, count);
WString w;
for(int i = 0; i < count; i++)
w.Cat(text[i + pos]);
return w;
}

View file

@ -275,6 +275,21 @@ void RichEdit::StdBar(Bar& menu)
WString w = GetWordAtCursor();
if(!w.IsEmpty() && !SpellWord(w, w.GetLength(),
fixedlang ? fixedlang : formatinfo.language)) {
if(true) {
Vector<String> h = SpellerFindCloseWords(fixedlang ? fixedlang : formatinfo.language, w.ToString(), 10);
for(String s : h)
menu.Add(s, [=] {
int pos, count;
GetWordAtCursorPos(pos, count);
if(count) {
Remove(pos, count);
WString h = s.ToWString();
Insert(pos, AsRichText(h, formatinfo));
Move(pos + h.GetCount());
Finish();
}
});
}
menu.Add(t_("Add to user dictionary"), THISBACK(AddUserDict));
menu.Separator();
}

View file

@ -579,6 +579,7 @@ private:
void AddUserDict();
WString GetWordAtCursor();
void GetWordAtCursorPos(int& pos, int& count);
Rect GetCaretRect(const RichCaret& pr) const;
Rect GetCaretRect() const;