ultimatepp/uppsrc/CodeEditor/FindReplace.cpp
2023-04-11 23:28:50 +02:00

963 lines
22 KiB
C++

#include "CodeEditor.h"
namespace Upp {
void CodeEditor::InitFindReplace()
{
findreplace.find.AddButton().SetMonoImage(CtrlImg::smallright()).Tip("Wildcard")
<<= THISBACK(FindWildcard);
findreplace.replace.AddButton().SetMonoImage(CtrlImg::smallright()).Tip("Wildcard")
<<= THISBACK(ReplaceWildcard);
PutI(findreplace.find);
PutI(findreplace.replace);
findreplace.amend <<= THISBACK(Replace);
findreplace.amend_all <<= THISBACK1(ReplaceAll, false);
findreplace.amend_rest <<= THISBACK1(ReplaceAll, true);
findreplace.prev <<= THISBACK(DoFindBack);
findreplace.replacing = false;
found = notfoundfw = notfoundbk = foundsel = false;
persistent_find_replace = false;
findreplace.find <<= findreplace.wholeword <<= findreplace.wildcards
<<= findreplace.incremental <<= findreplace.regexp
<<= findreplace.ignorecase <<= THISBACK(IncrementalFind);
ff_start_pos = -1;
findreplace.find_all << [=] { FindAll(); };
}
FindReplaceDlg::FindReplaceDlg()
{
find.NoUpDownKeys();
samecase <<= true;
close.Cancel();
prev.SetImage(CtrlImg::SmallUp());
amend.SetImage(CodeEditorImg::Replace());
amend_all.SetImage(CodeEditorImg::ReplaceAll());
amend_rest.SetImage(CodeEditorImg::ReplaceRest());
find_all.SetImage(CodeEditorImg::FindAll());
incremental <<= true;
mode <<= THISBACK(Sync);
mode.Hide();
Sync();
find.NullText("Find");
replace.NullText("Replace");
}
void FindReplaceDlg::Sync()
{
samecase.Enable(ignorecase);
bool b = !regexp;
wildcards.Enable(b);
prev.Enable(b);
ignorecase.Enable(b);
wholeword.Enable(b);
incremental_from_cursor.Enable(IsIncremental());
b = !mode.IsVisible() || ~mode == 0;
replace.Enable(b);
}
dword CodeEditor::find_next_key = K_F3;
dword CodeEditor::find_prev_key = K_SHIFT_F3;
dword CodeEditor::replace_key = K_CTRL_R;
bool FindReplaceDlg::Key(dword key, int cnt) {
if(key == K_CTRL_I) {
if(find.HasFocus()) {
find <<= itext;
return true;
}
if(replace.HasFocus()) {
replace <<= itext;
return true;
}
}
if(key == K_ENTER) {
next.WhenAction();
return true;
}
if(findarg(key, K_TAB, K_SHIFT_TAB) >= 0 && replace.IsShown()) {
if(find.HasFocus())
replace.SetFocus();
else
find.SetFocus();
return true;
}
if(key == K_ESCAPE) {
close.WhenAction();
return true;
}
return TopWindow::Key(key, cnt);
}
void FindReplaceDlg::Setup(bool doreplace)
{
CtrlLayout(*this);
close.SetImage(CodeEditorImg::Cancel());
close.Tip("Close (Esc)");
close.Normal();
close.SetLabel("");
next.SetImage(CtrlImg::SmallDown());
next.Tip("Find next (" + GetKeyDesc(CodeEditor::find_next_key) + ")");
next.Normal();
next.SetLabel("");
prev.Tip("Find prev (" + GetKeyDesc(CodeEditor::find_prev_key) + ")");
amend.Tip("Replace (" + GetKeyDesc(CodeEditor::replace_key) + ")");
find_all.Show();
find_all.Tip("Find all");
amend.Disable();
replacing = doreplace;
replace.Show(replacing);
amend.Show(replacing);
amend_all.Show(replacing);
amend_rest.Show(replacing);
Height(doreplace ? GetLayoutSize().cy : replace.GetRect().top);
SetFrame(TopSeparatorFrame());
Sync();
}
void CodeEditor::SetFound(int fi, int type, const WString& text)
{
Found& f = foundwild.At(fi);
f.type = type;
f.text = text;
}
int CodeEditor::Match(const wchar *f, const wchar *s, int line, bool we, bool ignorecase, int fi)
{
const wchar *b = s;
int n = 0;
WString ln;
while(*f) {
if(*f == WILDANY) {
f++;
WString wild;
for(;;) {
int nn = Match(f, s, line, we, ignorecase, fi + 1);
if(nn >= 0) {
SetFound(fi, WILDANY, wild);
return int(s - b) + n + nn;
}
wild.Cat(*s ? *s : '\n');
if(!*s++) return -1;
}
return -1;
}
else
if(*f == WILDONE) {
if(!*s) return -1;
SetFound(fi++, WILDONE, WString(*s, 1));
s++;
}
else
if(*f == WILDSPACE) {
const wchar *wb = s;
if(*s != ' ' && *s != '\t') return -1;
s++;
while(*s == ' ' || *s == '\t')
s++;
SetFound(fi++, WILDSPACE, WString(wb, s));
}
else
if(*f == WILDNUMBER) {
const wchar *wb = s;
if(*s < '0' || *s > '9') return -1;
s++;
while(*s >= '0' && *s <= '9')
s++;
SetFound(fi++, WILDNUMBER, WString(wb, s));
}
else
if(*f == WILDID) {
const wchar *wb = s;
if(!iscib(*s)) return -1;
s++;
while(iscidl(*s)) s++;
SetFound(fi++, WILDID, WString(wb, s));
}
else
if(*f == '\n') {
if(*s != '\0' || ++line >= GetLineCount()) return -1;
n += int(s - b) + 1;
ln = GetWLine(line);
s = b = ln;
}
else {
if(ignorecase ? ToUpper(*s) != ToUpper(*f) : *s != *f) return -1;
s++;
}
f++;
}
return we && iscidl(*s) ? -1 : int(s - b) + n;
}
bool CodeEditor::Find(bool back, bool block)
{
foundsel = true;
if(notfoundfw) MoveTextBegin();
if(notfoundbk) MoveTextEnd();
foundsel = false;
int64 cursor, pos;
if(found)
GetSelection(pos, cursor);
else
GetSelection(cursor, pos);
pos = cursor;
bool b = FindFrom(pos, back, block);
findreplace.amend.Enable(b);
return b;
}
bool CodeEditor::RegExpFind(int64 pos, bool block)
{
RegExp regex((String)~findreplace.find);
int line = GetLinePos64(pos);
String ln = ToUtf8(GetWLine(line).Mid(LimitSize(pos)));
for(;;) {
if(regex.Match(ln)) {
for(int i = 0; i < regex.GetCount(); i++)
SetFound(i, WILDANY, regex.GetString(i).ToWString());
int off = regex.GetOffset();
int len = Utf32Len(~ln + off, regex.GetLength());
pos = GetPos64(line, Utf32Len(~ln, off) + (int)pos);
foundtext = GetW(pos, len);
if(!block) {
foundsel = true;
SetSelection(pos, pos + len);
foundsel = false;
CenterCursor();
}
foundpos = pos;
foundsize = len;
found = true;
return true;
}
if(++line >= GetLineCount()) {
WaitView(line);
if(line >= GetLineCount())
return false;
}
ln = GetUtf8Line(line);
pos = 0;
if(!SearchProgress(line))
return false;
}
}
void CodeEditor::FindAll()
{
Vector<Tuple<int64, int>> found;
foundpos = 0;
while(FindFrom(foundpos, false, true)) {
found.Add(MakeTuple(foundpos, foundsize));
foundpos += foundsize;
if(found.GetCount() >= 10000) {
Exclamation("Too many matches, only first 10000 will be shown.");
break;
}
}
WhenFindAll(found);
}
bool CodeEditor::FindFrom(int64 pos, bool back, bool block)
{
notfoundbk = notfoundfw = false;
if(findreplace.regexp) {
if(RegExpFind(pos, block))
return true;
if(back)
notfoundbk = true;
else
notfoundfw = true;
return false;
}
WString text = ~findreplace.find;
WString ft;
const wchar *s = text;
while(*s) {
int c = *s++;
if(c == '\\') {
c = *s++;
if(c == '\0') break;
if(c == 'n')
ft.Cat('\n');
else
if(c == 't')
ft.Cat('\t');
else
if(c >= ' ')
ft.Cat(c);
}
else
if(c >= ' ') {
if(findreplace.wildcards)
ft.Cat(c == '*' ? WILDANY :
c == '?' ? WILDONE :
c == '%' ? WILDSPACE :
c == '#' ? WILDNUMBER :
c == '$' ? WILDID :
c
);
else
ft.Cat(c);
}
}
bool wb = findreplace.wholeword ? iscidl(*ft) : false;
bool we = findreplace.wholeword ? iscidl(*ft.Last()) : false;
if(ft.IsEmpty()) return false;
foundwild.Clear();
int line = GetLinePos64(pos);
WString ln = GetWLine(line);
const wchar *l = ln;
s = l + pos;
bool ignorecase = findreplace.ignorecase;
for(;;) {
for(;;) {
if(!wb || (s == l || !iscidl(s[-1]))) {
int n = Match(ft, s, line, we, ignorecase);
if(n >= 0) {
int64 pos = GetPos64(line, int(s - l));
foundtext = GetW(pos, n);
if(!back || pos + n < cursor) {
if(!block) {
foundsel = true;
SetSelection(pos, pos + n);
foundsel = false;
CenterCursor();
}
foundpos = pos;
foundsize = n;
found = true;
return true;
}
}
}
if(back) {
if(s-- == l) break;
}
else
if(!*s++) break;
}
if(back) {
if(--line < 0) break;
ln = GetWLine(line);
l = ln;
s = ln.End();
}
else {
if(++line >= GetLineCount()) {
WaitView(line);
if(line >= GetLineCount())
break;
}
ln = GetWLine(line);
l = s = ln;
}
if(!SearchProgress(back ? GetLineCount() - line : line))
break;
}
if(back)
notfoundbk = true;
else
notfoundfw = true;
return false;
}
void CodeEditor::FindReplaceAddHistory()
{
if(!IsNull(findreplace.find))
findreplace.find.AddHistory();
if(!IsNull(findreplace.replace))
findreplace.replace.AddHistory();
}
void CodeEditor::NoFindError()
{
findreplace.find.Error(false);
}
void CodeEditor::NotFound()
{
findreplace.find.Error();
if(!findreplace.IsIncremental())
SetFocus();
findreplace.amend.Disable();
}
bool CodeEditor::Find(bool back, bool blockreplace, bool replace)
{
NoFindError();
if(Find(back, blockreplace)) {
if(!blockreplace) {
if(!findreplace.IsOpen())
OpenNormalFindReplace(replace);
if(!findreplace.IsIncremental())
SetFocus();
}
return true;
}
else {
NotFound();
return false;
}
}
WString CodeEditor::GetWild(int type, int& i)
{
for(;;) {
if(i >= foundwild.GetCount()) break;
Found& f = foundwild[i++];
if(f.type == type) return f.text;
}
for(int j = 0; j < foundwild.GetCount(); j++) {
Found& f = foundwild[j++];
if(f.type == type) return f.text;
}
return WString();
}
WString CodeEditor::GetReplaceText()
{
WString rs = ~findreplace.replace;
bool wildcards = findreplace.wildcards;
bool samecase = findreplace.ignorecase && findreplace.samecase;
int anyi = 0, onei = 0, spacei = 0, numberi = 0, idi = 0;
WString rt;
const wchar *s = rs;
while(*s) {
int c = *s++;
if(c == '\\') {
c = *s++;
if(c == '\0') break;
if(c == 'n')
rt.Cat('\n');
else
if(c == 't')
rt.Cat('\t');
else
if(c >= ' ')
rt.Cat(c);
}
else
if(c >= ' ') {
if(wildcards) {
WString w;
if(c == '*')
w = GetWild(WILDANY, anyi);
else
if(c == '?')
w = GetWild(WILDONE, onei);
else
if(c == '%')
w = GetWild(WILDSPACE, spacei);
else
if(c == '#')
w = GetWild(WILDNUMBER, numberi);
else
if(c == '$')
w = GetWild(WILDID, idi);
else
if(c == '@') {
c = *s++;
if(c == '\0') break;
if(c == '@') {
rt << AsString(replacei).ToWString();
continue;
}
if(c == '#') {
rt << AsString(replacei + 1).ToWString();
continue;
}
if(c >= '1' && c <= '9') {
c -= '1';
w = c < foundwild.GetCount() ? foundwild[c].text : WString();
}
else {
rt.Cat('@');
if(c >= ' ' && c < 255) rt.Cat(c);
continue;
}
}
else {
rt.Cat(c);
continue;
}
if(*s == '+') {
w = ToUpper(w);
s++;
}
else
if(*s == '-') {
w = ToLower(w);
s++;
}
else
if(*s == '!') {
w = InitCaps(w);
s++;
}
rt.Cat(w);
}
else
rt.Cat(c);
}
}
if(samecase) {
if(foundtext.GetCount() && rt.GetCount()) {
if(IsUpper(foundtext[0]))
rt.Set(0, ToUpper(rt[0]));
if(IsLower(foundtext[0]))
rt.Set(0, ToLower(rt[0]));
}
if(foundtext.GetCount() > 1) {
if(IsUpper(foundtext[1]))
for(int i = 1; i < rt.GetCount(); i++)
rt.Set(i, ToUpper(rt[i]));
if(IsLower(foundtext[1]))
for(int i = 1; i < rt.GetCount(); i++)
rt.Set(i, ToLower(rt[i]));
}
}
replacei++;
return rt;
}
void CodeEditor::Replace()
{
if(!findreplace.replacing)
return;
NextUndo();
FindReplaceAddHistory();
if(!found) return;
bool h = persistent_find_replace;
persistent_find_replace = true; // avoid closing of findreplace by selection change
if(RemoveSelection()) {
Paste(GetReplaceText());
Find(false, false, true);
}
persistent_find_replace = h;
}
int CodeEditor::BlockReplace()
{
NextUndo();
Refresh(); // Setting full-refresh here avoids Pre/Post Remove/Insert costs
int l, h;
if(!GetSelection32(l, h)) return 0;
PlaceCaret(l);
int count = 0;
foundpos = l;
Index<int> ln;
StartSearchProgress(l, h);
while(foundpos < GetLength() && FindFrom(foundpos, false, true) && foundpos + foundsize <= h) {
CachePos(foundpos);
if(~findreplace.mode == 0) {
Remove((int)foundpos, foundsize);
WString rt = GetReplaceText();
Insert((int)foundpos, rt);
foundpos += rt.GetCount();
if(foundsize + rt.GetCount() == 0 && foundpos < GetLength())
foundpos++;
h = h - foundsize + rt.GetCount();
count++;
}
else {
ln.FindAdd(GetLine(foundpos));
foundpos += foundsize;
}
}
if(SearchCanceled())
return count;
EndSearchProgress();
Progress pi("Removing lines");
if(~findreplace.mode != 0) {
ClearSelection();
int ll = GetLine(l);
int lh = GetLine(h);
if(GetPos64(lh) == h)
lh--;
bool mm = ~findreplace.mode == 1;
String replace;
pi.SetTotal(lh - ll + 1);
for(int i = ll; i <= lh; i++) {
pi.Set(i, lh - ll + 1);
if(pi.Canceled())
return 0;
if((ln.Find(i) >= 0) == mm) {
replace << GetUtf8Line(i) << "\n";
count++;
}
}
int pos = GetPos32(ll);
Remove(pos, GetPos32(GetLine(h)) - pos);
SetSelection(pos, pos + Insert(pos, replace));
}
else
SetSelection(l, h);
return count;
}
void CodeEditor::OpenNormalFindReplace0(bool replace)
{
findreplace.incremental.Enable(GetLength64() < 2000000);
findreplace.Setup(replace);
findreplace.find_all.Show(!replace && WhenFindAll);
findreplace.itext = GetI();
findreplace.prev.Show();
findreplace.next <<= THISBACK(DoFind);
findreplace.close <<= THISBACK(EscapeFindReplace);
if(!findreplace.IsOpen())
InsertFrame(FindFrame(sb), findreplace);
WhenOpenFindReplace();
findreplace.find.SetFocus();
}
void CodeEditor::OpenNormalFindReplace(bool replace)
{
OpenNormalFindReplace0(replace);
// if(!findreplace.incremental_from_cursor)
// IncrementalFind();
}
void CodeEditor::FindReplace(bool pick_selection, bool pick_text, bool replace)
{
if(IsReadOnly())
replace = false;
if(findreplace.IsOpen())
CloseFindReplace();
ff_start_pos = GetCursor32();
replacei = 0;
WString find_text;
int find_pos = -1;
findreplace.Setup(replace);
if(pick_text || pick_selection)
{
if(IsSelection()) {
int l, h;
GetSelection32(l, h);
if(h - l < 100) {
find_text = GetSelectionW();
if(find_text.Find('\n') >= 0)
find_text.Clear();
}
}
else
if(pick_text) {
int l, h;
l = h = GetCursor32();
while(l > 0 && CharFilterCIdent(GetChar(l - 1)))
l--;
while(h < GetLength64() && CharFilterCIdent(GetChar(h)))
h++;
find_text = Get(l, h - l).ToWString();
find_pos = h;
}
if(find_text.GetCount())
findreplace.find <<= find_text;
}
if(IsSelection() && replace) {
findreplace.itext = GetI();
SetLayout_BlockReplaceLayout(findreplace);
findreplace.SetRect(WithBlockReplaceLayout<EmptyClass>::GetLayoutSize());
findreplace.Title(t_("Replace in selection"));
findreplace.find_all.Hide();
findreplace.amend.Hide();
findreplace.amend_all.Hide();
findreplace.amend_rest.Hide();
findreplace.prev.Hide();
findreplace.next.Ok() <<= findreplace.Breaker(IDOK);
findreplace.close.Cancel() <<= findreplace.Breaker(IDCANCEL);
findreplace.close.SetImage(Null);
findreplace.close.Tip("");
findreplace.next.SetImage(Null);
findreplace.next.Tip("");
findreplace.mode.Show();
findreplace.mode <<= 0;
findreplace.Sync();
if(findreplace.Execute() == IDOK)
BlockReplace();
findreplace.mode.Hide();
}
else {
if(find_pos >= 0)
SetCursor(find_pos);
OpenNormalFindReplace(replace);
findreplace.find.SetFocus();
}
}
void CodeEditor::ReplaceAll(bool rest)
{
int l, h;
GetSelection32(l, h);
int c = min(l, h);
findreplace.mode <<= 0;
SetSelection(rest * c, GetLength64());
BlockReplace();
SetCursor(c);
}
void CodeEditor::InsertWildcard(const char *s)
{
iwc = s;
}
void FindWildcardMenu(Callback1<const char *> cb, Point p, bool tablf, Ctrl *owner, bool regexp)
{
MenuBar menu;
if(regexp) {
menu.Add(t_("One or more spaces"), callback1(cb, " +"));
menu.Add(t_("One or more any characters"), callback1(cb, ".+"));
menu.Add(t_("Word"), callback1(cb, "\\w+"));
menu.Add(t_("Number"), callback1(cb, "\\d+"));
menu.Add(t_("Any character"), callback1(cb, "."));
if(tablf) {
menu.Separator();
menu.Add(t_("Tab"), callback1(cb, "\\t"));
}
}
else {
menu.Add(t_("One or more spaces"), callback1(cb, "%"));
menu.Add(t_("One or more any characters"), callback1(cb, "*"));
menu.Add(t_("C++ identifier"), callback1(cb, "$"));
menu.Add(t_("Number"), callback1(cb, "#"));
menu.Add(t_("Any character"), callback1(cb, "?"));
if(tablf) {
menu.Separator();
menu.Add(t_("Tab"), callback1(cb, "\\t"));
menu.Add(t_("Line feed"), callback1(cb, "\\n"));
}
}
menu.Execute(owner, p);
}
void CodeEditor::FindWildcard()
{
int l, h;
findreplace.find.GetSelection(l, h);
iwc.Clear();
FindWildcardMenu(THISBACK(InsertWildcard), findreplace.find.GetPushScreenRect().TopRight(), true,
&findreplace, findreplace.regexp);
if(iwc.GetCount()) {
if(!findreplace.regexp)
findreplace.wildcards = true;
findreplace.find.SetFocus();
findreplace.find.SetSelection(l, h);
findreplace.find.RemoveSelection();
findreplace.find.Insert(iwc);
}
}
void CodeEditor::ReplaceWildcard()
{
MenuBar menu;
String ptxt;
if(findreplace.regexp)
ptxt = t_("Matched subpattern %d");
else {
menu.Add(t_("Matched spaces"), THISBACK1(InsertWildcard, "%"));
menu.Add(t_("Matched one or more any characters"), THISBACK1(InsertWildcard, "*"));
menu.Add(t_("Matched C++ identifier"), THISBACK1(InsertWildcard, "$"));
menu.Add(t_("Matched number"), THISBACK1(InsertWildcard, "#"));
menu.Add(t_("Matched any character"), THISBACK1(InsertWildcard, "?"));
ptxt = t_("Matched wildcard %d");
}
menu.Add(t_("0-based replace index"), THISBACK1(InsertWildcard, "@@"));
menu.Add(t_("1-based replace index"), THISBACK1(InsertWildcard, "@#"));
menu.Separator();
for(int i = 1; i <= 9; i++)
menu.Add(Format(ptxt, i), THISBACK1(InsertWildcard, "@"+AsString(i)));
menu.Separator();
menu.Add(t_("To upper"), THISBACK1(InsertWildcard, "+"));
menu.Add(t_("To lower"), THISBACK1(InsertWildcard, "-"));
menu.Add(t_("InitCaps"), THISBACK1(InsertWildcard, "!"));
menu.Separator();
menu.Add(t_("Tab"), THISBACK1(InsertWildcard, "\\t"));
menu.Add(t_("Line feed"), THISBACK1(InsertWildcard, "\\n"));
int l, h;
findreplace.replace.GetSelection(l, h);
iwc.Clear();
menu.Execute(&findreplace, findreplace.replace.GetPushScreenRect().TopRight());
if(iwc.GetCount()) {
if(!findreplace.regexp)
findreplace.wildcards = true;
findreplace.replace.SetFocus();
findreplace.replace.SetSelection(l, h);
findreplace.replace.RemoveSelection();
findreplace.replace.Insert(iwc);
}
}
void CodeEditor::CloseFindReplace()
{
if(findreplace.IsOpen()) {
FindReplaceAddHistory();
RemoveFrame(findreplace);
}
}
void CodeEditor::EscapeFindReplace()
{
CloseFindReplace();
if(ff_start_pos >= 0 && ff_start_pos < GetLength64() && findreplace.IsIncremental() && do_ff_restore_pos) {
SetCursor(ff_start_pos);
ff_start_pos = -1;
}
}
void CodeEditor::IncrementalFind()
{
NoFindError();
findreplace.Sync();
if(!findreplace.IsIncremental() || findreplace.GetTopCtrl() == &findreplace) // || we are block replace
return;
bool b = FindFrom(ff_start_pos >= 0 && ff_start_pos < GetLength64()
&& findreplace.incremental_from_cursor ? ff_start_pos : 0, false, false);
findreplace.amend.Enable(b);
if(!b)
NotFound();
}
void CodeEditor::DoFind()
{
Find(false, false);
}
void CodeEditor::DoFindBack()
{
Find(true, false);
}
void CodeEditor::SerializeFind(Stream& s)
{
int version = 2;
s / version;
s % findreplace.find;
findreplace.find.SerializeList(s);
s % findreplace.wholeword % findreplace.ignorecase % findreplace.wildcards;
if(version >= 0)
s % findreplace.samecase;
s % findreplace.replace;
if(version >= 1)
s % findreplace.incremental;
if(version >= 2)
s % findreplace.regexp;
findreplace.replace.SerializeList(s);
}
String ReadList(WithDropChoice<EditString>& e)
{
StringStream ss;
e.SerializeList(ss);
return ss;
}
void WriteList(WithDropChoice<EditString>& e, const String& data)
{
StringStream ss(data);
e.SerializeList(ss);
}
CodeEditor::FindReplaceData CodeEditor::GetFindReplaceData()
{
FindReplaceData r;
r.find = ~findreplace.find;
r.replace = ~findreplace.replace;
r.wholeword = ~findreplace.wholeword;
r.ignorecase = ~findreplace.ignorecase;
r.wildcards = ~findreplace.wildcards;
r.samecase = ~findreplace.samecase;
r.regexp = ~findreplace.regexp;
r.find_list = ReadList(findreplace.find);
r.replace_list = ReadList(findreplace.replace);
return r;
}
void CodeEditor::SetFindReplaceData(const FindReplaceData& r)
{
findreplace.find <<= r.find;
findreplace.replace <<= r.replace;
findreplace.wholeword <<= r.wholeword;
findreplace.ignorecase <<= r.ignorecase;
findreplace.wildcards <<= r.wildcards;
findreplace.samecase <<= r.samecase;
findreplace.regexp <<= r.regexp;
findreplace.mode <<= 0;
WriteList(findreplace.find, r.find_list);
WriteList(findreplace.replace, r.replace_list);
}
void CodeEditor::FindPrevNext(bool prev)
{
StartSearchProgress(-1, -1);
if(!findreplace.IsOpen()) {
WString find_text;
if(IsSelection()) {
int l, h;
GetSelection32(l, h);
if(h - l < 100) {
find_text = GetSelectionW();
if(find_text.Find('\n') >= 0)
find_text.Clear();
}
}
if(find_text.GetCount())
findreplace.find <<= find_text;
OpenNormalFindReplace0(false);
}
if(Find(prev, false))
NoFindError();
else
NotFound();
EndSearchProgress();
}
void CodeEditor::FindNext()
{
FindPrevNext(false);
}
void CodeEditor::FindPrev()
{
FindPrevNext(true);
}
void CodeEditor::StartSearchProgress(int64, int64)
{
search_canceled = false;
search_progress.Create();
search_progress->SetText("Scanning the file");
search_time0 = msecs();
}
bool CodeEditor::SearchProgress(int line)
{
if(!search_progress)
return true;
if(!search_canceled && msecs(search_time0) > 20) {
search_time0 = msecs();
search_progress->Create();
search_canceled = IsView() ? search_progress->SetCanceled(int(GetPos64(line) >> 8), int(GetViewSize() >> 8))
: search_progress->SetCanceled(line, GetLineCount());
}
return !search_canceled;
}
bool CodeEditor::SearchCanceled()
{
return search_progress && search_canceled;
}
void CodeEditor::EndSearchProgress()
{
search_progress.Clear();
search_canceled = false;
}
}