ultimatepp/uppsrc/CodeEditor/FindReplace.cpp
mdelfede d2b54f7989 changed svn layout
git-svn-id: svn://ultimatepp.org/upp/trunk@281 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2008-06-07 22:31:27 +00:00

520 lines
11 KiB
C++

#include "CodeEditor.h"
NAMESPACE_UPP
bool CodeEditor::FindReplace::Key(dword key, int cnt) {
if(key == K_CTRL_I) {
if(find.HasFocus()) {
find <<= itext;
return true;
}
if(replace.HasFocus()) {
replace <<= itext;
return true;
}
}
return TopWindow::Key(key, cnt);
}
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(iscid(*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 && iscid(*s) ? -1 : int(s - b) + n;
}
bool CodeEditor::Find(bool back, const wchar *text, bool wholeword, bool ignorecase,
bool wildcards, bool block)
{
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(wildcards)
ft.Cat(c == '*' ? WILDANY :
c == '?' ? WILDONE :
c == '%' ? WILDSPACE :
c == '#' ? WILDNUMBER :
c == '$' ? WILDID :
c
);
else
ft.Cat(c);
}
foundwild.Clear();
if(ft.IsEmpty()) return false;
if(notfoundfw) MoveTextBegin();
if(notfoundbk) MoveTextEnd();
bool wb = wholeword ? iscid(*ft) : false;
bool we = wholeword ? iscid(*ft.Last()) : false;
int cursor = GetCursor();
int pos = cursor;
int line = GetLinePos(pos);
int linecount = GetLineCount();
WString ln = GetWLine(line);
const wchar *l = ln;
s = l + pos;
for(;;) {
for(;;) {
if(!wb || (s == l || !iscid(s[-1]))) {
int n = Match(ft, s, line, we, ignorecase);
if(n >= 0) {
int pos = GetPos(line, int(s - l));
if(!back || pos + n < cursor) {
foundsel = true;
SetSelection(pos, pos + n);
foundsel = false;
if(!block)
CenterCursor();
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 >= linecount) break;
ln = GetWLine(line);
l = s = ln;
}
}
if(back)
notfoundbk = true;
else
notfoundfw = true;
ClearSelection();
return false;
}
void CodeEditor::FindReplaceAddHistory()
{
if(!IsNull(findreplace.find))
findreplace.find.AddHistory();
if(!IsNull(findreplace.replace))
findreplace.replace.AddHistory();
}
bool CodeEditor::Find(bool back, bool blockreplace)
{
FindReplaceAddHistory();
if(Find(back, (WString)~findreplace.find, findreplace.wholeword,
findreplace.ignorecase, findreplace.wildcards, blockreplace)) {
if(!blockreplace) {
Rect lr = GetLineScreenRect(GetLine(GetCursor()));
Size fsz = findreplace.GetRect().Size();
Rect r = GetTopCtrl()->GetRect();
int y = r.bottom - fsz.cy;
if(lr.bottom > y) y = r.top;
Rect wa = Ctrl::GetWorkArea();
findreplace.SetRect(RectC(wa.left + (wa.Width() - fsz.cx) / 2, y, fsz.cx, fsz.cy));
findreplace.amend.Enable();
if(!findreplace.IsOpen()) {
findreplace.NoCenter();
OpenNormalFindReplace();
}
SetFocus();
}
return true;
}
else {
CloseFindReplace();
return false;
}
}
WString CodeEditor::GetWild(int type, int& i)
{
for(;;) {
if(i >= foundwild.GetCount()) return WString();
Found& f = foundwild[i++];
if(f.type == type) return f.text;
}
}
WString CodeEditor::GetReplaceText()
{
return GetReplaceText(findreplace.replace.GetText(), findreplace.wildcards);
}
WString CodeEditor::GetReplaceText(WString rs, bool wildcards)
{
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) {
if(c == '*')
rt.Cat(GetWild(WILDANY, anyi));
else
if(c == '?')
rt.Cat(GetWild(WILDONE, onei));
else
if(c == '%')
rt.Cat(GetWild(WILDSPACE, spacei));
else
if(c == '#')
rt.Cat(GetWild(WILDNUMBER, numberi));
else
if(c == '$')
rt.Cat(GetWild(WILDID, idi));
else
if(c == '@') {
c = *s++;
if(c == '\0') break;
if(c >= '1' && c <= '9') {
c -= '1';
rt.Cat(c < foundwild.GetCount() ? foundwild[c].text : WString());
}
else {
rt.Cat('@');
if(c >= ' ' && c < 255) rt.Cat(c);
}
}
else
rt.Cat(c);
}
else
rt.Cat(c);
}
}
return rt;
}
void CodeEditor::Replace()
{
NextUndo();
FindReplaceAddHistory();
if(!found) return;
if(RemoveSelection()) {
Paste(GetReplaceText());
Find();
}
}
int CodeEditor::BlockReplace(WString find, WString replace, bool wholeword, bool ignorecase, bool wildcards)
{
NextUndo();
int l, h;
if(!GetSelection(l, h)) return 0;
PlaceCaret(l);
int count = 0;
for(;;) {
if(!Find(false, find, wholeword, ignorecase, wildcards, true) || cursor >= h) break;
int hh, ll;
GetSelection(ll, hh);
CachePos(ll);
h = h - (hh - ll) + Paste(GetReplaceText(replace, wildcards));
count++;
}
SetSelection(l, h);
Refresh();
return count;
}
void CodeEditor::BlockReplace()
{
BlockReplace(~findreplace.find, ~findreplace.replace, findreplace.wholeword,
findreplace.ignorecase, findreplace.wildcards);
/*
NextUndo();
int l, h;
if(!GetSelection(l, h)) return;
PlaceCaret(l);
for(;;) {
if(!Find(false, true) || cursor >= h) break;
Refresh();
int hh, ll;
GetSelection(ll, hh);
CachePos(ll);
h = h - (hh - ll) + Paste(GetReplaceText());
}
SetSelection(l, h);
*/
}
void CodeEditor::OpenNormalFindReplace()
{
findreplace.itext = GetI();
findreplace.Title("Find / Replace");
findreplace.amend.Show();
findreplace.findback.Show();
findreplace.ok.SetLabel("Find");
findreplace.ok <<= THISBACK(DoFind);
findreplace.cancel <<= findreplace.WhenClose = THISBACK(CloseFindReplace);
findreplace.Open();
}
void CodeEditor::FindReplace(bool pick_text)
{
CloseFindReplace();
findreplace.CenterOwner();
WString find_text;
int find_pos = -1;
if(pick_text)
{
WString s = GetSelection().ToWString();
if(!IsNull(s)) {
if(s.Find('\n') >= 0)
BeepExclamation();
else {
find_text = s;
int l;
GetSelection(l, find_pos);
}
}
else { // pick identifier / number at cursor
int l, h;
l = h = GetCursor();
while(l > 0 && CharFilterCIdent(GetChar(l - 1)))
l--;
while(h < GetLength() && CharFilterCIdent(GetChar(h)))
h++;
find_text = Get(l, h - l).ToWString();
find_pos = h;
}
findreplace.find <<= find_text;
}
if(IsSelection()) {
findreplace.itext = GetI();
findreplace.Title("Replace in selection");
findreplace.amend.Hide();
findreplace.findback.Hide();
findreplace.ok.SetLabel("Replace");
findreplace.ok <<= findreplace.Breaker(IDOK);
findreplace.cancel <<= findreplace.Breaker(IDCANCEL);
if(findreplace.Execute() == IDOK)
{
BlockReplace();
}
}
else {
if(find_pos >= 0)
SetCursor(find_pos);
OpenNormalFindReplace();
findreplace.find.SetWantFocus();
}
}
void CodeEditor::InsertWildcard(int c)
{
iwc = c;
}
void FindWildcardMenu(Callback1<int> cb, Point p, bool tablf, Ctrl *owner)
{
MenuBar menu;
menu.Add("One or more spaces", callback1(cb, '%'));
menu.Add("One or more any characters", callback1(cb, '*'));
menu.Add("C++ identifier", callback1(cb, '$'));
menu.Add("Number", callback1(cb, '#'));
menu.Add("Any character", callback1(cb, '?'));
if(tablf) {
menu.Separator();
menu.Add("Tab", callback1(cb, '\t'));
menu.Add("Line feed", callback1(cb, '\n'));
}
menu.Execute(owner, p);
}
void CodeEditor::FindWildcard()
{
int l, h;
findreplace.find.GetSelection(l, h);
iwc = 0;
FindWildcardMenu(THISBACK(InsertWildcard), findreplace.find.GetPushScreenRect().TopRight(), true,
&findreplace);
if(iwc) {
findreplace.wildcards = true;
findreplace.find.SetFocus();
findreplace.find.SetSelection(l, h);
findreplace.find.RemoveSelection();
if(iwc == '\t') {
findreplace.find.Insert('\\');
findreplace.find.Insert('t');
}
else
if(iwc == '\n') {
findreplace.find.Insert('\\');
findreplace.find.Insert('n');
}
else
findreplace.find.Insert(iwc);
}
}
void CodeEditor::ReplaceWildcard()
{
MenuBar menu;
menu.Add("Matched spaces", THISBACK1(InsertWildcard, '%'));
menu.Add("Matched one or more any characters", THISBACK1(InsertWildcard, '*'));
menu.Add("Matched C++ identifier", THISBACK1(InsertWildcard, '$'));
menu.Add("Matched number", THISBACK1(InsertWildcard, '#'));
menu.Add("Matched any character", THISBACK1(InsertWildcard, '?'));
menu.Separator();
for(int i = 1; i <= 9; i++)
menu.Add(Format("Matched wildcard %d", i), THISBACK1(InsertWildcard, i));
menu.Separator();
menu.Add("Tab", THISBACK1(InsertWildcard, 20));
menu.Add("Line feed", THISBACK1(InsertWildcard, 21));
int l, h;
findreplace.replace.GetSelection(l, h);
iwc = 0;
menu.Execute(&findreplace, findreplace.replace.GetPushScreenRect().TopRight());
if(iwc) {
findreplace.wildcards = true;
findreplace.replace.SetFocus();
findreplace.replace.SetSelection(l, h);
findreplace.replace.RemoveSelection();
if(iwc == 20) {
findreplace.replace.Insert('\\');
findreplace.replace.Insert('t');
}
else
if(iwc == 21) {
findreplace.replace.Insert('\\');
findreplace.replace.Insert('n');
}
else
if(iwc >= 1 && iwc <= 9) {
findreplace.replace.Insert('@');
findreplace.replace.Insert(iwc + '0');
}
else
findreplace.replace.Insert(iwc);
}
}
void CodeEditor::CloseFindReplace()
{
findreplace.Close();
}
void CodeEditor::DoFind()
{
Find();
}
void CodeEditor::DoFindBack()
{
Find(true);
}
void CodeEditor::SerializeFind(Stream& s)
{
s % findreplace.find;
findreplace.find.SerializeList(s);
s % findreplace.wholeword % findreplace.ignorecase % findreplace.wildcards;
s % findreplace.replace;
findreplace.replace.SerializeList(s);
}
END_UPP_NAMESPACE