1 #include "CodeEditor.h"
2
3 namespace Upp {
4
InitFindReplace()5 void CodeEditor::InitFindReplace()
6 {
7 findreplace.find.AddButton().SetMonoImage(CtrlImg::smallright()).Tip("Wildcard")
8 <<= THISBACK(FindWildcard);
9 findreplace.replace.AddButton().SetMonoImage(CtrlImg::smallright()).Tip("Wildcard")
10 <<= THISBACK(ReplaceWildcard);
11 PutI(findreplace.find);
12 PutI(findreplace.replace);
13 findreplace.amend <<= THISBACK(Replace);
14 findreplace.amend_all <<= THISBACK1(ReplaceAll, false);
15 findreplace.amend_rest <<= THISBACK1(ReplaceAll, true);
16 findreplace.prev <<= THISBACK(DoFindBack);
17 findreplace.replacing = false;
18 found = notfoundfw = notfoundbk = foundsel = false;
19 persistent_find_replace = false;
20 findreplace.find <<= findreplace.wholeword <<= findreplace.wildcards
21 <<= findreplace.incremental <<= findreplace.regexp
22 <<= findreplace.ignorecase <<= THISBACK(IncrementalFind);
23 ff_start_pos = -1;
24 findreplace.find_all << [=] { FindAll(); };
25 }
26
FindReplaceDlg()27 FindReplaceDlg::FindReplaceDlg()
28 {
29 find.NoUpDownKeys();
30 samecase <<= true;
31 close.Cancel();
32 prev.SetImage(CtrlImg::SmallUp());
33 amend.SetImage(CodeEditorImg::Replace());
34 amend_all.SetImage(CodeEditorImg::ReplaceAll());
35 amend_rest.SetImage(CodeEditorImg::ReplaceRest());
36 find_all.SetImage(CodeEditorImg::FindAll());
37 incremental <<= true;
38 mode <<= THISBACK(Sync);
39 mode.Hide();
40 Sync();
41
42 find.NullText("Find");
43 replace.NullText("Replace");
44 }
45
Sync()46 void FindReplaceDlg::Sync()
47 {
48 samecase.Enable(ignorecase);
49 bool b = !regexp;
50 wildcards.Enable(b);
51 prev.Enable(b);
52 ignorecase.Enable(b);
53 wholeword.Enable(b);
54 incremental_from_cursor.Enable(IsIncremental());
55 b = !mode.IsVisible() || ~mode == 0;
56 replace.Enable(b);
57 }
58
59 dword CodeEditor::find_next_key = K_F3;
60 dword CodeEditor::find_prev_key = K_SHIFT_F3;
61 dword CodeEditor::replace_key = K_CTRL_R;
62
Key(dword key,int cnt)63 bool FindReplaceDlg::Key(dword key, int cnt) {
64 if(key == K_CTRL_I) {
65 if(find.HasFocus()) {
66 find <<= itext;
67 return true;
68 }
69 if(replace.HasFocus()) {
70 replace <<= itext;
71 return true;
72 }
73 }
74 if(key == K_ENTER) {
75 next.WhenAction();
76 return true;
77 }
78 if(findarg(key, K_TAB, K_SHIFT_TAB) >= 0 && replace.IsShown()) {
79 if(find.HasFocus())
80 replace.SetFocus();
81 else
82 find.SetFocus();
83 return true;
84 }
85 if(key == K_ESCAPE) {
86 close.WhenAction();
87 return true;
88 }
89 return TopWindow::Key(key, cnt);
90 }
91
Setup(bool doreplace)92 void FindReplaceDlg::Setup(bool doreplace)
93 {
94 CtrlLayout(*this);
95 close.SetImage(CodeEditorImg::Cancel());
96 close.Tip("Close (Esc)");
97 close.Normal();
98 close.SetLabel("");
99 next.SetImage(CtrlImg::SmallDown());
100 next.Tip("Find next (" + GetKeyDesc(CodeEditor::find_next_key) + ")");
101 next.Normal();
102 next.SetLabel("");
103 prev.Tip("Find prev (" + GetKeyDesc(CodeEditor::find_prev_key) + ")");
104 amend.Tip("Replace (" + GetKeyDesc(CodeEditor::replace_key) + ")");
105 find_all.Show();
106 find_all.Tip("Find all");
107 amend.Disable();
108 replacing = doreplace;
109 replace.Show(replacing);
110 amend.Show(replacing);
111 amend_all.Show(replacing);
112 amend_rest.Show(replacing);
113 Height(doreplace ? GetLayoutSize().cy : replace.GetRect().top);
114 SetFrame(TopSeparatorFrame());
115 Sync();
116 }
117
SetFound(int fi,int type,const WString & text)118 void CodeEditor::SetFound(int fi, int type, const WString& text)
119 {
120 Found& f = foundwild.At(fi);
121 f.type = type;
122 f.text = text;
123 }
124
Match(const wchar * f,const wchar * s,int line,bool we,bool ignorecase,int fi)125 int CodeEditor::Match(const wchar *f, const wchar *s, int line, bool we, bool ignorecase, int fi)
126 {
127 const wchar *b = s;
128 int n = 0;
129 WString ln;
130 while(*f) {
131 if(*f == WILDANY) {
132 f++;
133 WString wild;
134 for(;;) {
135 int nn = Match(f, s, line, we, ignorecase, fi + 1);
136 if(nn >= 0) {
137 SetFound(fi, WILDANY, wild);
138 return int(s - b) + n + nn;
139 }
140 wild.Cat(*s ? *s : '\n');
141 if(!*s++) return -1;
142 }
143 return -1;
144 }
145 else
146 if(*f == WILDONE) {
147 if(!*s) return -1;
148 SetFound(fi++, WILDONE, WString(*s, 1));
149 s++;
150 }
151 else
152 if(*f == WILDSPACE) {
153 const wchar *wb = s;
154 if(*s != ' ' && *s != '\t') return -1;
155 s++;
156 while(*s == ' ' || *s == '\t')
157 s++;
158 SetFound(fi++, WILDSPACE, WString(wb, s));
159 }
160 else
161 if(*f == WILDNUMBER) {
162 const wchar *wb = s;
163 if(*s < '0' || *s > '9') return -1;
164 s++;
165 while(*s >= '0' && *s <= '9')
166 s++;
167 SetFound(fi++, WILDNUMBER, WString(wb, s));
168 }
169 else
170 if(*f == WILDID) {
171 const wchar *wb = s;
172 if(!iscib(*s)) return -1;
173 s++;
174 while(iscidl(*s)) s++;
175 SetFound(fi++, WILDID, WString(wb, s));
176 }
177 else
178 if(*f == '\n') {
179 if(*s != '\0' || ++line >= GetLineCount()) return -1;
180 n += int(s - b) + 1;
181 ln = GetWLine(line);
182 s = b = ln;
183 }
184 else {
185 if(ignorecase ? ToUpper(*s) != ToUpper(*f) : *s != *f) return -1;
186 s++;
187 }
188 f++;
189 }
190 return we && iscidl(*s) ? -1 : int(s - b) + n;
191 }
192
Find(bool back,bool block)193 bool CodeEditor::Find(bool back, bool block)
194 {
195 foundsel = true;
196 if(notfoundfw) MoveTextBegin();
197 if(notfoundbk) MoveTextEnd();
198 foundsel = false;
199 int64 cursor, pos;
200 if(found)
201 GetSelection(pos, cursor);
202 else
203 GetSelection(cursor, pos);
204 pos = cursor;
205 bool b = FindFrom(pos, back, block);
206 findreplace.amend.Enable(b);
207 return b;
208 }
209
RegExpFind(int64 pos,bool block)210 bool CodeEditor::RegExpFind(int64 pos, bool block)
211 {
212 RegExp regex((String)~findreplace.find);
213
214 int line = GetLinePos64(pos);
215 String ln = ToUtf8(GetWLine(line).Mid(LimitSize(pos)));
216 for(;;) {
217 if(regex.Match(ln)) {
218 for(int i = 0; i < regex.GetCount(); i++)
219 SetFound(i, WILDANY, regex.GetString(i).ToWString());
220 int off = regex.GetOffset();
221 int len = utf8len(~ln + off, regex.GetLength());
222 pos = GetPos64(line, utf8len(~ln, off) + (int)pos);
223 foundtext = GetW(pos, len);
224 if(!block) {
225 foundsel = true;
226 SetSelection(pos, pos + len);
227 foundsel = false;
228 CenterCursor();
229 }
230 foundpos = pos;
231 foundsize = len;
232 found = true;
233 return true;
234 }
235 if(++line >= GetLineCount()) {
236 WaitView(line);
237 if(line >= GetLineCount())
238 return false;
239 }
240 ln = GetUtf8Line(line);
241 pos = 0;
242 if(!SearchProgress(line))
243 return false;
244 }
245 }
246
FindAll()247 void CodeEditor::FindAll()
248 {
249 Vector<Tuple<int64, int>> found;
250 foundpos = 0;
251 while(FindFrom(foundpos, false, true)) {
252 found.Add(MakeTuple(foundpos, foundsize));
253 foundpos += foundsize;
254 if(found.GetCount() >= 10000) {
255 Exclamation("Too many matches, only first 10000 will be shown.");
256 break;
257 }
258 }
259 WhenFindAll(found);
260 }
261
FindFrom(int64 pos,bool back,bool block)262 bool CodeEditor::FindFrom(int64 pos, bool back, bool block)
263 {
264 notfoundbk = notfoundfw = false;
265 if(findreplace.regexp) {
266 if(RegExpFind(pos, block))
267 return true;
268 if(back)
269 notfoundbk = true;
270 else
271 notfoundfw = true;
272 return false;
273 }
274 WString text = ~findreplace.find;
275 WString ft;
276 const wchar *s = text;
277 while(*s) {
278 int c = *s++;
279 if(c == '\\') {
280 c = *s++;
281 if(c == '\0') break;
282 if(c == 'n')
283 ft.Cat('\n');
284 else
285 if(c == 't')
286 ft.Cat('\t');
287 else
288 if(c >= ' ')
289 ft.Cat(c);
290 }
291 else
292 if(c >= ' ') {
293 if(findreplace.wildcards)
294 ft.Cat(c == '*' ? WILDANY :
295 c == '?' ? WILDONE :
296 c == '%' ? WILDSPACE :
297 c == '#' ? WILDNUMBER :
298 c == '$' ? WILDID :
299 c
300 );
301 else
302 ft.Cat(c);
303 }
304 }
305 bool wb = findreplace.wholeword ? iscidl(*ft) : false;
306 bool we = findreplace.wholeword ? iscidl(*ft.Last()) : false;
307 if(ft.IsEmpty()) return false;
308 foundwild.Clear();
309 int line = GetLinePos64(pos);
310 WString ln = GetWLine(line);
311 const wchar *l = ln;
312 s = l + pos;
313 bool ignorecase = findreplace.ignorecase;
314 for(;;) {
315 for(;;) {
316 if(!wb || (s == l || !iscidl(s[-1]))) {
317 int n = Match(ft, s, line, we, ignorecase);
318 if(n >= 0) {
319 int64 pos = GetPos64(line, int(s - l));
320 foundtext = GetW(pos, n);
321 if(!back || pos + n < cursor) {
322 if(!block) {
323 foundsel = true;
324 SetSelection(pos, pos + n);
325 foundsel = false;
326 CenterCursor();
327 }
328 foundpos = pos;
329 foundsize = n;
330 found = true;
331 return true;
332 }
333 }
334 }
335 if(back) {
336 if(s-- == l) break;
337 }
338 else
339 if(!*s++) break;
340 }
341 if(back) {
342 if(--line < 0) break;
343 ln = GetWLine(line);
344 l = ln;
345 s = ln.End();
346 }
347 else {
348 if(++line >= GetLineCount()) {
349 WaitView(line);
350 if(line >= GetLineCount())
351 break;
352 }
353 ln = GetWLine(line);
354 l = s = ln;
355 }
356 if(!SearchProgress(back ? GetLineCount() - line : line))
357 break;
358 }
359 if(back)
360 notfoundbk = true;
361 else
362 notfoundfw = true;
363 return false;
364 }
365
FindReplaceAddHistory()366 void CodeEditor::FindReplaceAddHistory()
367 {
368 if(!IsNull(findreplace.find))
369 findreplace.find.AddHistory();
370 if(!IsNull(findreplace.replace))
371 findreplace.replace.AddHistory();
372 }
373
NoFindError()374 void CodeEditor::NoFindError()
375 {
376 findreplace.find.Error(false);
377 }
378
NotFound()379 void CodeEditor::NotFound()
380 {
381 findreplace.find.Error();
382 if(!findreplace.IsIncremental())
383 SetFocus();
384 findreplace.amend.Disable();
385 }
386
Find(bool back,bool blockreplace,bool replace)387 bool CodeEditor::Find(bool back, bool blockreplace, bool replace)
388 {
389 NoFindError();
390 if(Find(back, blockreplace)) {
391 if(!blockreplace) {
392 if(!findreplace.IsOpen())
393 OpenNormalFindReplace(replace);
394 if(!findreplace.IsIncremental())
395 SetFocus();
396 }
397 return true;
398 }
399 else {
400 NotFound();
401 return false;
402 }
403 }
404
GetWild(int type,int & i)405 WString CodeEditor::GetWild(int type, int& i)
406 {
407 for(;;) {
408 if(i >= foundwild.GetCount()) break;
409 Found& f = foundwild[i++];
410 if(f.type == type) return f.text;
411 }
412 for(int j = 0; j < foundwild.GetCount(); j++) {
413 Found& f = foundwild[j++];
414 if(f.type == type) return f.text;
415 }
416 return WString();
417 }
418
GetReplaceText()419 WString CodeEditor::GetReplaceText()
420 {
421 WString rs = ~findreplace.replace;
422 bool wildcards = findreplace.wildcards;
423 bool samecase = findreplace.ignorecase && findreplace.samecase;
424
425 int anyi = 0, onei = 0, spacei = 0, numberi = 0, idi = 0;
426 WString rt;
427 const wchar *s = rs;
428 while(*s) {
429 int c = *s++;
430 if(c == '\\') {
431 c = *s++;
432 if(c == '\0') break;
433 if(c == 'n')
434 rt.Cat('\n');
435 else
436 if(c == 't')
437 rt.Cat('\t');
438 else
439 if(c >= ' ')
440 rt.Cat(c);
441 }
442 else
443 if(c >= ' ') {
444 if(wildcards) {
445 WString w;
446 if(c == '*')
447 w = GetWild(WILDANY, anyi);
448 else
449 if(c == '?')
450 w = GetWild(WILDONE, onei);
451 else
452 if(c == '%')
453 w = GetWild(WILDSPACE, spacei);
454 else
455 if(c == '#')
456 w = GetWild(WILDNUMBER, numberi);
457 else
458 if(c == '$')
459 w = GetWild(WILDID, idi);
460 else
461 if(c == '@') {
462 c = *s++;
463 if(c == '\0') break;
464 if(c == '@') {
465 rt << AsString(replacei).ToWString();
466 continue;
467 }
468 if(c == '#') {
469 rt << AsString(replacei + 1).ToWString();
470 continue;
471 }
472 if(c >= '1' && c <= '9') {
473 c -= '1';
474 w = c < foundwild.GetCount() ? foundwild[c].text : WString();
475 }
476 else {
477 rt.Cat('@');
478 if(c >= ' ' && c < 255) rt.Cat(c);
479 continue;
480 }
481 }
482 else {
483 rt.Cat(c);
484 continue;
485 }
486 if(*s == '+') {
487 w = ToUpper(w);
488 s++;
489 }
490 else
491 if(*s == '-') {
492 w = ToLower(w);
493 s++;
494 }
495 else
496 if(*s == '!') {
497 w = InitCaps(w);
498 s++;
499 }
500 rt.Cat(w);
501 }
502 else
503 rt.Cat(c);
504 }
505 }
506 if(samecase) {
507 if(foundtext.GetCount() && rt.GetCount()) {
508 if(IsUpper(foundtext[0]))
509 rt.Set(0, ToUpper(rt[0]));
510 if(IsLower(foundtext[0]))
511 rt.Set(0, ToLower(rt[0]));
512 }
513 if(foundtext.GetCount() > 1) {
514 if(IsUpper(foundtext[1]))
515 for(int i = 1; i < rt.GetCount(); i++)
516 rt.Set(i, ToUpper(rt[i]));
517 if(IsLower(foundtext[1]))
518 for(int i = 1; i < rt.GetCount(); i++)
519 rt.Set(i, ToLower(rt[i]));
520 }
521 }
522 replacei++;
523 return rt;
524 }
525
Replace()526 void CodeEditor::Replace()
527 {
528 if(!findreplace.replacing)
529 return;
530 NextUndo();
531 FindReplaceAddHistory();
532 if(!found) return;
533 bool h = persistent_find_replace;
534 persistent_find_replace = true; // avoid closing of findreplace by selection change
535 if(RemoveSelection()) {
536 Paste(GetReplaceText());
537 Find(false, false, true);
538 }
539 persistent_find_replace = h;
540 }
541
BlockReplace()542 int CodeEditor::BlockReplace()
543 {
544 NextUndo();
545 Refresh(); // Setting full-refresh here avoids Pre/Post Remove/Insert costs
546 int l, h;
547 if(!GetSelection32(l, h)) return 0;
548 PlaceCaret(l);
549 int count = 0;
550 foundpos = l;
551 Index<int> ln;
552 StartSearchProgress(l, h);
553 while(FindFrom(foundpos, false, true) && foundpos + foundsize <= h) {
554 CachePos(foundpos);
555 if(~findreplace.mode == 0) {
556 Remove((int)foundpos, foundsize);
557 WString rt = GetReplaceText();
558 Insert((int)foundpos, rt);
559 foundpos += rt.GetCount();
560 h = h - foundsize + rt.GetCount();
561 count++;
562 }
563 else {
564 ln.FindAdd(GetLine(foundpos));
565 foundpos += foundsize;
566 }
567 }
568 if(SearchCanceled())
569 return count;
570 EndSearchProgress();
571 Progress pi("Removing lines");
572 if(~findreplace.mode != 0) {
573 ClearSelection();
574 int ll = GetLine(l);
575 int lh = GetLine(h);
576 if(GetPos64(lh) == h)
577 lh--;
578 bool mm = ~findreplace.mode == 1;
579 String replace;
580 pi.SetTotal(lh - ll + 1);
581 for(int i = ll; i <= lh; i++) {
582 pi.Set(i, lh - ll + 1);
583 if(pi.Canceled())
584 return 0;
585 if((ln.Find(i) >= 0) == mm) {
586 replace << GetUtf8Line(i) << "\n";
587 count++;
588 }
589 }
590 int pos = GetPos32(ll);
591 Remove(pos, GetPos32(GetLine(h)) - pos);
592 SetSelection(pos, pos + Insert(pos, replace));
593 }
594 else
595 SetSelection(l, h);
596 return count;
597 }
598
OpenNormalFindReplace0(bool replace)599 void CodeEditor::OpenNormalFindReplace0(bool replace)
600 {
601 findreplace.incremental.Enable(GetLength64() < 2000000);
602 findreplace.Setup(replace);
603 findreplace.find_all.Show(!replace && WhenFindAll);
604 findreplace.itext = GetI();
605 findreplace.prev.Show();
606 findreplace.next <<= THISBACK(DoFind);
607 findreplace.close <<= THISBACK(EscapeFindReplace);
608 if(!findreplace.IsOpen())
609 InsertFrame(FindFrame(sb), findreplace);
610 WhenOpenFindReplace();
611 findreplace.find.SetFocus();
612 }
613
OpenNormalFindReplace(bool replace)614 void CodeEditor::OpenNormalFindReplace(bool replace)
615 {
616 OpenNormalFindReplace0(replace);
617 // if(!findreplace.incremental_from_cursor)
618 // IncrementalFind();
619 }
620
FindReplace(bool pick_selection,bool pick_text,bool replace)621 void CodeEditor::FindReplace(bool pick_selection, bool pick_text, bool replace)
622 {
623 if(IsReadOnly())
624 replace = false;
625
626 if(findreplace.IsOpen())
627 CloseFindReplace();
628
629 ff_start_pos = GetCursor32();
630
631 replacei = 0;
632 WString find_text;
633 int find_pos = -1;
634
635 findreplace.Setup(replace);
636
637 if(pick_text || pick_selection)
638 {
639 if(IsSelection()) {
640 int l, h;
641 GetSelection32(l, h);
642 if(h - l < 100) {
643 find_text = GetSelectionW();
644 if(find_text.Find('\n') >= 0)
645 find_text.Clear();
646 }
647 }
648 else
649 if(pick_text) {
650 int l, h;
651 l = h = GetCursor32();
652 while(l > 0 && CharFilterCIdent(GetChar(l - 1)))
653 l--;
654 while(h < GetLength64() && CharFilterCIdent(GetChar(h)))
655 h++;
656 find_text = Get(l, h - l).ToWString();
657 find_pos = h;
658 }
659 if(find_text.GetCount())
660 findreplace.find <<= find_text;
661 }
662 if(IsSelection() && replace) {
663 findreplace.itext = GetI();
664 SetLayout_BlockReplaceLayout(findreplace);
665 findreplace.SetRect(WithBlockReplaceLayout<EmptyClass>::GetLayoutSize());
666 findreplace.Title(t_("Replace in selection"));
667 findreplace.find_all.Hide();
668 findreplace.amend.Hide();
669 findreplace.amend_all.Hide();
670 findreplace.amend_rest.Hide();
671 findreplace.prev.Hide();
672 findreplace.next.Ok() <<= findreplace.Breaker(IDOK);
673 findreplace.close.Cancel() <<= findreplace.Breaker(IDCANCEL);
674 findreplace.close.SetImage(Null);
675 findreplace.close.Tip("");
676 findreplace.next.SetImage(Null);
677 findreplace.next.Tip("");
678 findreplace.mode.Show();
679 findreplace.mode <<= 0;
680 findreplace.Sync();
681 if(findreplace.Execute() == IDOK)
682 BlockReplace();
683 findreplace.mode.Hide();
684 }
685 else {
686 if(find_pos >= 0)
687 SetCursor(find_pos);
688 OpenNormalFindReplace(replace);
689 findreplace.find.SetFocus();
690 }
691 }
692
ReplaceAll(bool rest)693 void CodeEditor::ReplaceAll(bool rest)
694 {
695 int l, h;
696 GetSelection32(l, h);
697 int c = min(l, h);
698 findreplace.mode <<= 0;
699 SetSelection(rest * c, GetLength64());
700 BlockReplace();
701 SetCursor(c);
702 }
703
InsertWildcard(const char * s)704 void CodeEditor::InsertWildcard(const char *s)
705 {
706 iwc = s;
707 }
708
FindWildcardMenu(Callback1<const char * > cb,Point p,bool tablf,Ctrl * owner,bool regexp)709 void FindWildcardMenu(Callback1<const char *> cb, Point p, bool tablf, Ctrl *owner, bool regexp)
710 {
711 MenuBar menu;
712 if(regexp) {
713 menu.Add(t_("One or more spaces"), callback1(cb, " +"));
714 menu.Add(t_("One or more any characters"), callback1(cb, ".+"));
715 menu.Add(t_("Word"), callback1(cb, "\\w+"));
716 menu.Add(t_("Number"), callback1(cb, "\\d+"));
717 menu.Add(t_("Any character"), callback1(cb, "."));
718 if(tablf) {
719 menu.Separator();
720 menu.Add(t_("Tab"), callback1(cb, "\\t"));
721 }
722 }
723 else {
724 menu.Add(t_("One or more spaces"), callback1(cb, "%"));
725 menu.Add(t_("One or more any characters"), callback1(cb, "*"));
726 menu.Add(t_("C++ identifier"), callback1(cb, "$"));
727 menu.Add(t_("Number"), callback1(cb, "#"));
728 menu.Add(t_("Any character"), callback1(cb, "?"));
729 if(tablf) {
730 menu.Separator();
731 menu.Add(t_("Tab"), callback1(cb, "\\t"));
732 menu.Add(t_("Line feed"), callback1(cb, "\\n"));
733 }
734 }
735 menu.Execute(owner, p);
736 }
737
FindWildcard()738 void CodeEditor::FindWildcard()
739 {
740 int l, h;
741 findreplace.find.GetSelection(l, h);
742 iwc.Clear();
743 FindWildcardMenu(THISBACK(InsertWildcard), findreplace.find.GetPushScreenRect().TopRight(), true,
744 &findreplace, findreplace.regexp);
745 if(iwc.GetCount()) {
746 if(!findreplace.regexp)
747 findreplace.wildcards = true;
748 findreplace.find.SetFocus();
749 findreplace.find.SetSelection(l, h);
750 findreplace.find.RemoveSelection();
751 findreplace.find.Insert(iwc);
752 }
753 }
754
ReplaceWildcard()755 void CodeEditor::ReplaceWildcard()
756 {
757 MenuBar menu;
758 String ptxt;
759 if(findreplace.regexp)
760 ptxt = t_("Matched subpattern %d");
761 else {
762 menu.Add(t_("Matched spaces"), THISBACK1(InsertWildcard, "%"));
763 menu.Add(t_("Matched one or more any characters"), THISBACK1(InsertWildcard, "*"));
764 menu.Add(t_("Matched C++ identifier"), THISBACK1(InsertWildcard, "$"));
765 menu.Add(t_("Matched number"), THISBACK1(InsertWildcard, "#"));
766 menu.Add(t_("Matched any character"), THISBACK1(InsertWildcard, "?"));
767 ptxt = t_("Matched wildcard %d");
768 }
769 menu.Add(t_("0-based replace index"), THISBACK1(InsertWildcard, "@@"));
770 menu.Add(t_("1-based replace index"), THISBACK1(InsertWildcard, "@#"));
771 menu.Separator();
772 for(int i = 1; i <= 9; i++)
773 menu.Add(Format(ptxt, i), THISBACK1(InsertWildcard, "@"+AsString(i)));
774 menu.Separator();
775 menu.Add(t_("To upper"), THISBACK1(InsertWildcard, "+"));
776 menu.Add(t_("To lower"), THISBACK1(InsertWildcard, "-"));
777 menu.Add(t_("InitCaps"), THISBACK1(InsertWildcard, "!"));
778 menu.Separator();
779 menu.Add(t_("Tab"), THISBACK1(InsertWildcard, "\\t"));
780 menu.Add(t_("Line feed"), THISBACK1(InsertWildcard, "\\n"));
781 int l, h;
782 findreplace.replace.GetSelection(l, h);
783 iwc.Clear();
784 menu.Execute(&findreplace, findreplace.replace.GetPushScreenRect().TopRight());
785 if(iwc.GetCount()) {
786 if(!findreplace.regexp)
787 findreplace.wildcards = true;
788 findreplace.replace.SetFocus();
789 findreplace.replace.SetSelection(l, h);
790 findreplace.replace.RemoveSelection();
791 findreplace.replace.Insert(iwc);
792 }
793 }
794
CloseFindReplace()795 void CodeEditor::CloseFindReplace()
796 {
797 if(findreplace.IsOpen()) {
798 FindReplaceAddHistory();
799 RemoveFrame(findreplace);
800 }
801 }
802
EscapeFindReplace()803 void CodeEditor::EscapeFindReplace()
804 {
805 CloseFindReplace();
806 if(ff_start_pos >= 0 && ff_start_pos < GetLength64() && findreplace.IsIncremental() && do_ff_restore_pos) {
807 SetCursor(ff_start_pos);
808 ff_start_pos = -1;
809 }
810 }
811
IncrementalFind()812 void CodeEditor::IncrementalFind()
813 {
814 NoFindError();
815 findreplace.Sync();
816 if(!findreplace.IsIncremental() || findreplace.GetTopCtrl() == &findreplace) // || we are block replace
817 return;
818 bool b = FindFrom(ff_start_pos >= 0 && ff_start_pos < GetLength64()
819 && findreplace.incremental_from_cursor ? ff_start_pos : 0, false, false);
820 findreplace.amend.Enable(b);
821 if(!b)
822 NotFound();
823 }
824
DoFind()825 void CodeEditor::DoFind()
826 {
827 Find(false, false);
828 }
829
DoFindBack()830 void CodeEditor::DoFindBack()
831 {
832 Find(true, false);
833 }
834
SerializeFind(Stream & s)835 void CodeEditor::SerializeFind(Stream& s)
836 {
837 int version = 2;
838 s / version;
839 s % findreplace.find;
840 findreplace.find.SerializeList(s);
841 s % findreplace.wholeword % findreplace.ignorecase % findreplace.wildcards;
842 if(version >= 0)
843 s % findreplace.samecase;
844 s % findreplace.replace;
845 if(version >= 1)
846 s % findreplace.incremental;
847 if(version >= 2)
848 s % findreplace.regexp;
849 findreplace.replace.SerializeList(s);
850 }
851
ReadList(WithDropChoice<EditString> & e)852 String ReadList(WithDropChoice<EditString>& e)
853 {
854 StringStream ss;
855 e.SerializeList(ss);
856 return ss;
857 }
858
WriteList(WithDropChoice<EditString> & e,const String & data)859 void WriteList(WithDropChoice<EditString>& e, const String& data)
860 {
861 StringStream ss(data);
862 e.SerializeList(ss);
863 }
864
GetFindReplaceData()865 CodeEditor::FindReplaceData CodeEditor::GetFindReplaceData()
866 {
867 FindReplaceData r;
868 r.find = ~findreplace.find;
869 r.replace = ~findreplace.replace;
870 r.wholeword = ~findreplace.wholeword;
871 r.ignorecase = ~findreplace.ignorecase;
872 r.wildcards = ~findreplace.wildcards;
873 r.samecase = ~findreplace.samecase;
874 r.regexp = ~findreplace.regexp;
875 r.find_list = ReadList(findreplace.find);
876 r.replace_list = ReadList(findreplace.replace);
877 return r;
878 }
879
SetFindReplaceData(const FindReplaceData & r)880 void CodeEditor::SetFindReplaceData(const FindReplaceData& r)
881 {
882 findreplace.find <<= r.find;
883 findreplace.replace <<= r.replace;
884 findreplace.wholeword <<= r.wholeword;
885 findreplace.ignorecase <<= r.ignorecase;
886 findreplace.wildcards <<= r.wildcards;
887 findreplace.samecase <<= r.samecase;
888 findreplace.regexp <<= r.regexp;
889 findreplace.mode <<= 0;
890 WriteList(findreplace.find, r.find_list);
891 WriteList(findreplace.replace, r.replace_list);
892 }
893
FindPrevNext(bool prev)894 void CodeEditor::FindPrevNext(bool prev)
895 {
896 StartSearchProgress(-1, -1);
897 if(!findreplace.IsOpen()) {
898 WString find_text;
899 if(IsSelection()) {
900 int l, h;
901 GetSelection32(l, h);
902 if(h - l < 100) {
903 find_text = GetSelectionW();
904 if(find_text.Find('\n') >= 0)
905 find_text.Clear();
906 }
907 }
908 if(find_text.GetCount())
909 findreplace.find <<= find_text;
910 OpenNormalFindReplace0(false);
911 }
912 if(Find(prev, false))
913 NoFindError();
914 else
915 NotFound();
916 EndSearchProgress();
917 }
918
FindNext()919 void CodeEditor::FindNext()
920 {
921 FindPrevNext(false);
922 }
923
FindPrev()924 void CodeEditor::FindPrev()
925 {
926 FindPrevNext(true);
927 }
928
StartSearchProgress(int64,int64)929 void CodeEditor::StartSearchProgress(int64, int64)
930 {
931 search_canceled = false;
932 search_progress.Create();
933 search_progress->SetText("Scanning the file");
934 search_time0 = msecs();
935 }
936
SearchProgress(int line)937 bool CodeEditor::SearchProgress(int line)
938 {
939 if(search_progress && !search_canceled && msecs(search_time0) > 20) {
940 search_time0 = msecs();
941 search_progress->Create();
942 search_canceled = IsView() ? search_progress->SetCanceled(int(GetPos64(line) >> 8), int(GetViewSize() >> 8))
943 : search_progress->SetCanceled(line, GetLineCount());
944 }
945 return !search_canceled;
946 }
947
SearchCanceled()948 bool CodeEditor::SearchCanceled()
949 {
950 return search_canceled;
951 }
952
EndSearchProgress()953 void CodeEditor::EndSearchProgress()
954 {
955 search_progress.Clear();
956 search_canceled = false;
957 }
958
959 }
960