mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-07-11 22:03:01 -06:00
RichEdit: Now suggesting spelling fixes
git-svn-id: svn://ultimatepp.org/upp/trunk@12679 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
4603d561e2
commit
89febbfa1d
5 changed files with 142 additions and 4 deletions
|
|
@ -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;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -579,6 +579,7 @@ private:
|
|||
|
||||
void AddUserDict();
|
||||
WString GetWordAtCursor();
|
||||
void GetWordAtCursorPos(int& pos, int& count);
|
||||
|
||||
Rect GetCaretRect(const RichCaret& pr) const;
|
||||
Rect GetCaretRect() const;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue