1 #include "ide.h"
2
3 #if 0
4 #define LDUMP(x) DDUMP(x)
5 #define LDUMPC(x) DDUMPC(x)
6 #define LLOG(x) DLOG(x)
7 #else
8 #define LDUMP(x)
9 #define LDUMPC(x)
10 #define LLOG(x)
11 #endif
12
13 #define LTIMING(x) // DTIMING(x)
14
15 class IndexSeparatorFrameCls : public CtrlFrame {
FrameLayout(Rect & r)16 virtual void FrameLayout(Rect& r) { r.right -= 1; }
FramePaint(Draw & w,const Rect & r)17 virtual void FramePaint(Draw& w, const Rect& r) {
18 w.DrawRect(r.right - 1, r.top, 1, r.Height(), SColorShadow);
19 }
FrameAddSize(Size & sz)20 virtual void FrameAddSize(Size& sz) { sz.cx += 2; }
21 };
22
Format(const Value & q) const23 Value AssistEditor::AssistItemConvert::Format(const Value& q) const
24 {
25 int ii = q;
26 if(ii >= 0 && ii < editor->assist_item_ndx.GetCount()) {
27 ii = editor->assist_item_ndx[ii];
28 if(ii < editor->assist_item.GetCount())
29 return RawToValue(editor->assist_item[ii]);
30 }
31 CppItemInfo empty;
32 return RawToValue(empty);
33 }
34
SyncNavigatorPlacement()35 void AssistEditor::SyncNavigatorPlacement()
36 {
37 int sz = navigatorframe.GetSize();
38 if(navigator_right)
39 navigatorframe.Right(navigatorpane, sz);
40 else
41 navigatorframe.Left(navigatorpane, sz);
42 }
43
AssistEditor()44 AssistEditor::AssistEditor()
45 {
46 assist_convert.editor = this;
47 assist.NoHeader();
48 assist.NoGrid();
49 assist.AddRowNumColumn().Margin(0).SetConvert(assist_convert).SetDisplay(Single<CppItemInfoDisplay>());
50 assist.NoWantFocus();
51 assist.WhenLeftClick = THISBACK(AssistInsert);
52 type.NoHeader();
53 type.NoGrid();
54 type.AddColumn();
55 type.WhenCursor = THISBACK(SyncAssist);
56 type.NoWantFocus();
57 popup.Horz(type, assist);
58 popup.SetPos(2000);
59 auto_assist = auto_check = true;
60 commentdp = false;
61
62 SyncNavigatorPlacement();
63 navigatorframe.Left(navigatorpane, HorzLayoutZoom(140));
64 navigating = false;
65
66 int cy = search.GetMinSize().cy;
67 navigatorpane.Add(search.TopPos(0, cy).HSizePos(0, cy + 4));
68 navigatorpane.Add(sortitems.TopPos(0, cy).RightPos(0, cy));
69 navigatorpane.Add(navigator_splitter.VSizePos(cy, 0).HSizePos());
70 navigator_splitter.Vert() << scope << list << navlines;
71 navigator_splitter.SetPos(1500, 0);
72 navigator_splitter.SetPos(9500, 1);
73
74 navigator = true;
75
76 WhenAnnotationMove = THISBACK(SyncAnnotationPopup);
77 WhenAnnotationClick = THISBACK1(EditAnnotation, true);
78 WhenAnnotationRightClick = THISBACK1(EditAnnotation, false);
79 Annotations(Zx(12));
80 annotation_popup.Background(SColorPaper());
81 annotation_popup.SetFrame(BlackFrame());
82 annotation_popup.Margins(6);
83 annotation_popup.NoSb();
84
85 thisback = false;
86
87 cachedpos = INT_MAX;
88 cachedln = -1;
89
90 parami = 0;
91
92 param_info.Margins(2);
93 param_info.Background(SColorPaper());
94 param_info.SetFrame(BlackFrame());
95 param_info.BackPaint();
96 param_info.NoSb();
97
98 include_assist = false;
99
100 NoFindReplace();
101 }
102
CppItemInfoOrder(const Value & va,const Value & vb)103 int CppItemInfoOrder(const Value& va, const Value& vb) {
104 const CppItemInfo& a = ValueTo<CppItemInfo>(va);
105 const CppItemInfo& b = ValueTo<CppItemInfo>(vb);
106 return CombineCompare(a.name, b.name)(a.natural, b.natural);
107 }
108
CloseAssist()109 void AssistEditor::CloseAssist()
110 {
111 if(popup.IsOpen())
112 popup.Close();
113 if(annotation_popup.IsOpen())
114 annotation_popup.Close();
115 assist_item.Clear();
116 CloseTip();
117 }
118
isincludefnchar(int c)119 bool isincludefnchar(int c)
120 {
121 return c && c != '<' && c != '>' && c != '?' &&
122 c != ' ' && c != '\"' && c != '/' && c != '\\' && c >= 32 && c < 65536;
123 }
124
ReadIdBackPos(int & pos,bool include)125 String AssistEditor::ReadIdBackPos(int& pos, bool include)
126 {
127 String id;
128 bool (*test)(int c) = include ? isincludefnchar : iscid;
129 while(pos > 0 && (*test)(GetChar(pos - 1)))
130 pos--;
131 int q = pos;
132 while(q < GetLength64() && (*test)(GetChar(q)))
133 id << (char)GetChar(q++);
134 return id;
135 }
136
ReadIdBack(int q,bool include,bool * destructor)137 String AssistEditor::ReadIdBack(int q, bool include, bool *destructor)
138 {
139 String id = ReadIdBackPos(q, include);
140 if(destructor) {
141 int n = 0;
142 while(q > 0 && isspace(GetChar(q - 1)) && n < 100) {
143 q--;
144 n++;
145 }
146 *destructor = q > 0 && GetChar(q - 1) == '~';
147 }
148 return id;
149 }
150
DirtyFrom(int line)151 void AssistEditor::DirtyFrom(int line)
152 {
153 if(line >= cachedln) {
154 cachedpos = INT_MAX;
155 cachedline.Clear();
156 cachedln = -1;
157 }
158 CodeEditor::DirtyFrom(line);
159 }
160
Ch(int i)161 int AssistEditor::Ch(int i)
162 {
163 if(i >= 0 && i < GetLength64()) {
164 if(i < cachedpos || i - cachedpos > cachedline.GetCount()) {
165 cachedln = GetLine(i);
166 cachedline = GetWLine(cachedln);
167 cachedpos = GetPos32(cachedln);
168 }
169 i -= cachedpos;
170 return i < cachedline.GetCount() ? cachedline[i] : '\n';
171 }
172 return 0;
173 }
174
ParsBack(int q)175 int AssistEditor::ParsBack(int q)
176 {
177 int level = 1;
178 --q;
179 while(q > 0) {
180 if(isrbrkt(Ch(q)))
181 level++;
182 if(islbrkt(Ch(q)))
183 if(--level <= 0)
184 break;
185 --q;
186 }
187 return max(0, q);
188 }
189
IsSpc(int c)190 bool IsSpc(int c)
191 {
192 return c > 0 && c <= 32;
193 }
194
SkipSpcBack(int & q)195 void AssistEditor::SkipSpcBack(int& q)
196 {
197 while(q > 0 && IsSpc(Ch(q - 1)))
198 q--;
199 }
200
IdBack(int & qq)201 String AssistEditor::IdBack(int& qq)
202 {
203 String r;
204 if(iscid(Ch(qq - 1))) {
205 int q = qq;
206 while(iscid(Ch(q - 1)))
207 q--;
208 if(iscib(Ch(q))) {
209 qq = q;
210 while(q < GetLength64() && iscid(Ch(q)))
211 r.Cat(Ch(q++));
212 }
213 }
214 return r;
215 }
216
CompleteIdBack(int & q,const Index<String> & locals)217 String AssistEditor::CompleteIdBack(int& q, const Index<String>& locals)
218 {
219 String id;
220 for(;;) {
221 SkipSpcBack(q);
222 if(Ch(q - 1) == ',') {
223 q--;
224 id = ',' + id;
225 }
226 else
227 if(Ch(q - 1) == '>') {
228 q--;
229 id = '>' + id;
230 }
231 else
232 if(Ch(q - 1) == '<') {
233 q--;
234 id = '<' + id;
235 }
236 else
237 if(Ch(q - 1) == ':' && Ch(q - 2) == ':') {
238 q -= 2;
239 id = "::" + id;
240 }
241 else {
242 if(iscib(*id))
243 break;
244 String nid = IdBack(q);
245 if(IsNull(nid))
246 break;
247 if(locals.Find(nid) >= 0 && findarg(*id, '<', '>') >= 0)
248 return id.Mid(1);
249 id = nid + id;
250 }
251 }
252 return id;
253 }
254
ReadBack(int q,const Index<String> & locals)255 Vector<String> AssistEditor::ReadBack(int q, const Index<String>& locals)
256 {
257 Vector<String> r;
258 type.Clear();
259 bool wasid = true;
260 for(;;) {
261 if(r.GetCount() > 200) {
262 r.Clear();
263 type.Clear();
264 break;
265 }
266 SkipSpcBack(q);
267 int c = Ch(q - 1);
268 if(c == '>' && !wasid) {
269 q--;
270 r.Add() = CompleteIdBack(q, locals) + ">";
271 wasid = true;
272 continue;
273 }
274 if(iscid(c)) {
275 if(wasid)
276 break;
277 String id;
278 for(;;) {
279 id = IdBack(q) + id;
280 SkipSpcBack(q);
281 if(!(Ch(q - 1) == ':' && Ch(q - 2) == ':'))
282 break;
283 q -= 2;
284 id = "::" + id;
285 SkipSpcBack(q);
286 }
287 r.Add() = id;
288 wasid = true;
289 continue;
290 }
291 else {
292 // if(findarg(c, '(', '[', '{') >= 0)
293 // break;
294 if(c == ']') {
295 if(wasid)
296 break;
297 r.Add("[]");
298 q = ParsBack(q - 1);
299 wasid = false;
300 continue;
301 }
302 else
303 if(c == ')') {
304 if(wasid)
305 break;
306 r.Add("()");
307 q = ParsBack(q - 1);
308 wasid = false;
309 continue;
310 }
311 wasid = false;
312 c = Ch(q - 1);
313 if(c == '>' && Ch(q - 2) == '-') {
314 r.Add("->");
315 q -= 2;
316 continue;
317 }
318 if(c == '.') {
319 r.Add(".");
320 q--;
321 continue;
322 }
323 }
324 break;
325 }
326 Reverse(r);
327 return r;
328 }
329
SyncAssist()330 void AssistEditor::SyncAssist()
331 {
332 LTIMING("SyncAssist");
333 bool destructor;
334 String name = ReadIdBack(GetCursor32(), include_assist, &destructor);
335 String uname = ToUpper(name);
336 assist_item_ndx.Clear();
337 int typei = type.GetCursor() - 1;
338 Buffer<bool> found(assist_item.GetCount(), false);
339 for(int pass = 0; pass < 2; pass++) {
340 VectorMap<String, int> over;
341 for(int i = 0; i < assist_item.GetCount(); i++) {
342 const CppItemInfo& m = assist_item[i];
343 if(!found[i] &&
344 (typei < 0 || m.typei == typei) &&
345 (pass ? m.uname.StartsWith(uname) : m.name.StartsWith(name)) &&
346 (!destructor || m.kind == DESTRUCTOR && m.scope == current_type + "::")) {
347 int q = include_assist ? -1 : over.Find(m.qitem);
348 if(q < 0 || over[q] == m.typei && m.scope.GetCount()) {
349 found[i] = true;
350 assist_item_ndx.Add(i);
351 if(q < 0)
352 over.Add(m.qitem, m.typei);
353 }
354 }
355 }
356 }
357 assist.Clear();
358 assist.SetVirtualCount(assist_item_ndx.GetCount());
359 }
360
IncludeAssist()361 bool AssistEditor::IncludeAssist()
362 {
363 Vector<String> include;
364 String ln = GetUtf8Line(GetCursorLine());
365 CParser p(ln);
366 try {
367 if(!p.Char('#') || !p.Id("include"))
368 return false;
369 if(p.Char('\"')) {
370 include.Add(GetFileFolder(theide->editfile));
371 include_local = true;
372 }
373 else {
374 p.Char('<');
375 include = SplitDirs(theide->GetIncludePath());
376 include_local = false;
377 }
378 include_path.Clear();
379 include_back = 0;
380 if(include_local)
381 while(p.Char3('.', '.', '/') || p.Char3('.', '.', '\\')) {
382 include.Top() = GetFileFolder(include.Top());
383 include_back++;
384 }
385 for(;;) {
386 String dir;
387 while(isincludefnchar(p.PeekChar()))
388 dir.Cat(p.GetChar());
389 if(dir.GetCount() && (p.Char('/') || p.Char('\\'))) {
390 if(include_path.GetCount())
391 include_path << '/';
392 include_path << dir;
393 }
394 else
395 break;
396 }
397 }
398 catch(CParser::Error) {
399 return false;
400 }
401 Vector<String> folder, upper_folder, file, upper_file;
402 for(int i = 0; i < include.GetCount(); i++) {
403 FindFile ff(AppendFileName(AppendFileName(include[i], include_path), "*.*"));
404 while(ff) {
405 String fn = ff.GetName();
406 if(!ff.IsHidden()) {
407 if(ff.IsFolder()) {
408 folder.Add(fn);
409 upper_folder.Add(ToUpper(fn));
410 }
411 else {
412 static Index<String> ext(Split(".h;.hpp;.hh;.hxx;.i;.lay;.iml;.t;.dli", ';'));
413 String fext = GetFileExt(fn);
414 if(fext.GetCount() == 0 || ext.Find(ToLower(fext)) >= 0) {
415 file.Add(fn);
416 upper_file.Add(ToUpper(fn));
417 }
418 }
419 }
420 ff.Next();
421 }
422 }
423 IndexSort(upper_folder, folder);
424 Index<String> fnset;
425 for(int i = 0; i < folder.GetCount(); i++) {
426 String fn = folder[i];
427 if(fnset.Find(fn) < 0) {
428 fnset.Add(fn);
429 CppItemInfo& f = assist_item.Add();
430 f.name = f.natural = fn;
431 f.access = 0;
432 f.kind = KIND_INCLUDEFOLDER;
433 }
434 }
435 IndexSort(upper_file, file);
436 for(int i = 0; i < file.GetCount(); i++) {
437 String fn = file[i];
438 CppItemInfo& f = assist_item.Add();
439 f.name = f.natural = fn;
440 f.access = 0;
441 static Index<String> hdr(Split(".h;.hpp;.hh;.hxx", ';'));
442 String fext = GetFileExt(fn);
443 f.kind = hdr.Find(ToLower(GetFileExt(fn))) >= 0 || fext.GetCount() == 0 ? KIND_INCLUDEFILE
444 : KIND_INCLUDEFILE_ANY;
445 }
446 include_assist = true;
447 if(include_path.GetCount())
448 include_path << "/";
449 PopUpAssist();
450 return true;
451 }
452
Assist()453 void AssistEditor::Assist()
454 {
455 LTIMING("Assist");
456 if(!assist_active)
457 return;
458 CloseAssist();
459 int q = GetCursor32();
460 assist_cursor = q;
461 assist_type.Clear();
462 assist_item.Clear();
463 include_assist = false;
464 if(IncludeAssist())
465 return;
466 ParserContext parser;
467 Context(parser, GetCursor32());
468 Index<String> in_types;
469 while(iscid(Ch(q - 1)) || Ch(q - 1) == '~')
470 q--;
471 SkipSpcBack(q);
472 thisback = false;
473 current_type.Clear();
474 LTIMING("Assist2");
475 if(Ch(q - 1) == '(') {
476 int qq = q - 1;
477 String id = IdBack(qq);
478 int tn = findarg(id, "THISBACK", "THISBACK1", "THISBACK2", "THISBACK3", "THISBACK4");
479 if(tn >= 0) {
480 thisback = true;
481 thisbackn = tn > 0;
482 GatherItems(parser.current_scope, false, in_types, false);
483 RemoveDuplicates();
484 PopUpAssist();
485 return;
486 }
487 }
488 if(Ch(q - 1) == ':' && Ch(q - 2) == ':') {
489 q -= 2;
490 Vector<String> tparam;
491 String scope = ParseTemplatedType(Qualify(parser.current_scope,
492 CompleteIdBack(q, parser.local.GetIndex()),
493 parser.context.namespace_using),
494 tparam);
495 GatherItems(scope, false, in_types, true);
496 current_type = scope;
497 }
498 else {
499 String tp;
500 Vector<String> xp = ReadBack(q, parser.local.GetIndex());
501 bool isok = false;
502 if(xp.GetCount() && xp[0].StartsWith("::")) // ::Foo().
503 xp[0] = xp[0].Mid(2);
504 for(int i = 0; i < xp.GetCount(); i++)
505 if(iscib(*xp[i])) {
506 isok = true;
507 break;
508 }
509 if(xp.GetCount()) {
510 if(isok) { // Do nothing on pressing '.' when there is no identifier before
511 Index<String> typeset = EvaluateExpressionType(parser, xp);
512 for(int i = 0; i < typeset.GetCount(); i++)
513 if(typeset[i].GetCount())
514 GatherItems(typeset[i], xp[0] != "this", in_types, false);
515 }
516 }
517 else {
518 GatherItems(parser.current_scope, false, in_types, true);
519 Vector<String> ns = parser.GetNamespaces();
520 for(int i = 0; i < ns.GetCount(); i++)
521 if(parser.current_scope != ns[i]) // Do not scan namespace already scanned
522 GatherItems(ns[i], false, in_types, true);
523 }
524 }
525 LTIMING("Assist3");
526 RemoveDuplicates();
527 PopUpAssist();
528 }
529
530 Ptr<Ctrl> AssistEditor::assist_ptr;
531
WheelHook(Ctrl *,bool inframe,int event,Point p,int zdelta,dword keyflags)532 bool AssistEditor::WheelHook(Ctrl *, bool inframe, int event, Point p, int zdelta, dword keyflags)
533 {
534 if(!inframe && event == MOUSEWHEEL && assist_ptr && assist_ptr->IsOpen()) {
535 assist_ptr->MouseWheel(p, zdelta, keyflags);
536 return true;
537 }
538 return false;
539 }
540
PopUpAssist(bool auto_insert)541 void AssistEditor::PopUpAssist(bool auto_insert)
542 {
543 LTIMING("PopUpAssist");
544 if(assist_item.GetCount() == 0)
545 return;
546 int lcy = max(16, BrowserFont().Info().GetHeight());
547 type.Clear();
548 type.Add(AttrText("<all>").Ink(SColorHighlight()));
549 if(assist_type.GetCount() == 0)
550 popup.Zoom(1);
551 else {
552 for(int i = 0; i < assist_type.GetCount(); i++) {
553 String s = assist_type[i];
554 if(s[0] == ':' && s[1] == ':')
555 s = s.Mid(2);
556 s = Nvl(s, "<globals>");
557 if(s[0] == '<')
558 type.Add(AttrText(s).Ink(SColorMark()));
559 else
560 type.Add(Nvl(s, "<globals>"));
561 }
562 popup.NoZoom();
563 }
564 type.SetCursor(0);
565 if(!assist.GetCount())
566 return;
567 LTIMING("PopUpAssist2");
568 int cy = VertLayoutZoom(304);
569 cy += HeaderCtrl::GetStdHeight();
570 assist.SetLineCy(lcy);
571 Point p = GetCaretPoint() + GetScreenView().TopLeft();
572 Rect wa = GetWorkArea();
573 int cx = min(wa.Width() - 100, Zx(800));
574 if(p.x + cx > wa.right)
575 p.x = wa.right - cx;
576 popup.SetRect(RectC(p.x, p.y + cy + GetFontSize().cy < wa.bottom ? p.y + GetFontSize().cy : p.y - cy, cx, cy) & wa);
577 popup.BackPaint();
578 if(auto_insert && assist.GetCount() == 1) {
579 assist.GoBegin();
580 AssistInsert();
581 }
582 else {
583 popup.Ctrl::PopUp(this, false, false, true);
584 assist_ptr = &assist;
585 ONCELOCK {
586 InstallMouseHook(AssistEditor::WheelHook);
587 }
588 }
589 }
590
sILess(const String & a,const String & b)591 bool sILess(const String& a, const String& b)
592 {
593 return ToUpper(a) < ToUpper(b);
594 }
595
Complete()596 void AssistEditor::Complete()
597 {
598 CloseAssist();
599
600 int c = GetCursor32();
601 String q = IdBack(c);
602
603 Index<String> ids;
604 int64 len = 0;
605 for(int i = 0; i < GetLineCount() && len < 1000000; i++) {
606 String x = GetUtf8Line(i);
607 len += x.GetLength();
608 CParser p(x);
609 try {
610 while(!p.IsEof())
611 if(p.IsId()) {
612 String h = p.ReadId();
613 if(h != q)
614 ids.FindAdd(h);
615 }
616 else
617 p.SkipTerm();
618 }
619 catch(CParser::Error) {
620 return;
621 }
622 }
623
624 Vector<String> id = ids.PickKeys();
625 Upp::Sort(id, sILess);
626
627 if(q.GetCount()) {
628 String h;
629 for(int i = 0; i < id.GetCount(); i++) {
630 String s = id[i];
631 if(s.StartsWith(q)) {
632 if(IsNull(h))
633 h = s;
634 else {
635 s.Trim(min(s.GetCount(), h.GetCount()));
636 for(int j = 0; j < s.GetCount(); j++)
637 if(s[j] != h[j]) {
638 h.Trim(j);
639 break;
640 }
641 }
642 }
643 }
644 if(h.GetCount() > q.GetCount())
645 Paste(h.Mid(q.GetCount()).ToWString());
646 }
647 for(int i = 0; i < id.GetCount(); i++) {
648 CppItemInfo& f = assist_item.Add();
649 f.name = f.natural = f.qitem = id[i];
650 f.access = 0;
651 f.kind = 100;
652 }
653 assist_type.Clear();
654 PopUpAssist(true);
655 }
656
Abbr()657 void AssistEditor::Abbr()
658 {
659 CloseAssist();
660 int c = GetCursor32();
661 int ch;
662 String s;
663 while(IsAlpha(ch = Ch(c - 1))) {
664 s.Insert(0, ch);
665 --c;
666 }
667 int len = s.GetCount();
668 s = theide->abbr.Get(s, String());
669 if(IsNull(s))
670 return;
671 NextUndo();
672 SetCursor(c);
673 Remove(c, len);
674 int linepos = c;
675 int line = GetLinePos32(linepos);
676 WString h = GetWLine(line).Mid(0, linepos);
677 for(int i = 0; i < s.GetCount(); i++) {
678 ch = s[i];
679 switch(ch) {
680 case '@':
681 c = GetCursor32();
682 break;
683 case '\n':
684 InsertChar('\n');
685 for(int j = 0; j < h.GetCount(); j++)
686 InsertChar(h[j]);
687 break;
688 default:
689 if((byte)s[i] >= ' ' || s[i] == '\t')
690 InsertChar(s[i]);
691 break;
692 }
693 }
694 SetCursor(c);
695 }
696
AssistInsert()697 void AssistEditor::AssistInsert()
698 {
699 if(assist.IsCursor()) {
700 int ii = assist.GetCursor();
701 if(ii < 0 || ii >= assist_item_ndx.GetCount())
702 return;
703 ii = assist_item_ndx[ii];
704 if(ii >= assist_item.GetCount()) {
705 CloseAssist();
706 IgnoreMouseUp();
707 return;
708 }
709 const CppItemInfo& f = assist_item[ii];
710 if(include_assist) {
711 int ln = GetLine(GetCursor32());
712 int pos = GetPos32(ln);
713 Remove(pos, GetLineLength(ln));
714 SetCursor(pos);
715 String h;
716 for(int i = 0; i < include_back; i++)
717 h << "../";
718 Paste(ToUnicode(String().Cat() << "#include "
719 << (include_local ? "\"" : "<")
720 << h << include_path
721 << f.name
722 << (f.kind == KIND_INCLUDEFOLDER ? "/" :
723 include_local ? "\"" : ">")
724 , CHARSET_WIN1250));
725 if(f.kind == KIND_INCLUDEFOLDER) {
726 Assist();
727 IgnoreMouseUp();
728 return;
729 }
730 else {
731 String pkg = include_path.Left(include_path.GetCount() - 1);
732 Vector<String> nests = SplitDirs(GetVar("UPP"));
733 for(int i = 0; i < nests.GetCount(); i++){
734 if(FileExists(nests[i] + "/" + include_path + GetFileName(pkg) + ".upp")) {
735 Ide *ide = dynamic_cast<Ide *>(TheIde());
736 if(ide)
737 ide->AddPackage(pkg);
738 break;
739 }
740 }
741 }
742 }
743 else {
744 String txt = f.name;
745 int l = txt.GetCount();
746 int pl = txt.GetCount();
747 if(!thisback && f.kind >= FUNCTION && f.kind <= INLINEFRIEND)
748 txt << "()";
749 int cl = GetCursor32();
750 int ch = cl;
751 while(iscid(Ch(cl - 1)))
752 cl--;
753 while(iscid(Ch(ch)))
754 ch++;
755 Remove(cl, ch - cl);
756 SetCursor(cl);
757 if(thisback)
758 for(;;) {
759 int c = Ch(cl++);
760 if(!c || Ch(cl) == ',' || Ch(cl) == ')')
761 break;
762 if(c != ' ') {
763 if(thisbackn)
764 txt << ", ";
765 txt << ')';
766 break;
767 }
768 }
769 if(findarg(f.kind, CONSTRUCTOR, DESTRUCTOR) >= 0)
770 txt << "()";
771 int n = Paste(ToUnicode(txt, CHARSET_WIN1250));
772 if(!thisback && f.kind >= FUNCTION && f.kind <= INLINEFRIEND) {
773 SetCursor(GetCursor32() - 1);
774 StartParamInfo(f, cl);
775 if(f.natural.EndsWith("()"))
776 SetCursor(GetCursor32() + 1);
777 }
778 else
779 if(thisback) {
780 if(thisbackn)
781 SetCursor(GetCursor32() - 1);
782 }
783 else
784 if(!inbody)
785 SetCursor(cl + n - thisbackn);
786 else
787 if(pl > l)
788 SetSelection(cl + l, cl + pl);
789 else
790 SetCursor(cl + l);
791 }
792 }
793 CloseAssist();
794 IgnoreMouseUp();
795 }
796
InCode()797 bool AssistEditor::InCode()
798 {
799 int pos = GetCursor32();
800 int line = GetLinePos32(pos);
801 One<EditorSyntax> st = GetSyntax(line);
802 WString l = GetWLine(line);
803 st->ScanSyntax(l, ~l + pos, line, GetTabSize());
804 return st->CanAssist();
805 }
806
isaid(int c)807 bool isaid(int c)
808 {
809 return c == '~' || iscid(c);
810 }
811
Key(dword key,int count)812 bool AssistEditor::Key(dword key, int count)
813 {
814 if(popup.IsOpen()) {
815 int k = key & ~K_CTRL;
816 ArrayCtrl& kt = key & K_CTRL ? type : assist;
817 if(k == K_UP || k == K_PAGEUP || k == K_CTRL_PAGEUP || k == K_CTRL_END) {
818 if(kt.IsCursor())
819 return kt.Key(k, count);
820 else {
821 kt.SetCursor(kt.GetCount() - 1);
822 return true;
823 }
824 }
825 if(k == K_DOWN || k == K_PAGEDOWN || k == K_CTRL_PAGEDOWN || k == K_CTRL_HOME) {
826 if(kt.IsCursor())
827 return kt.Key(k, count);
828 else {
829 kt.SetCursor(0);
830 return true;
831 }
832 }
833 if(key == K_ENTER && assist.IsCursor()) {
834 AssistInsert();
835 return true;
836 }
837 if(key == K_TAB && !assist.IsCursor() && assist.GetCount()) {
838 assist.GoBegin();
839 AssistInsert();
840 return true;
841 }
842 }
843 int c = GetCursor32();
844 int cc = GetChar(c);
845 int bcc = c > 0 ? GetChar(c - 1) : 0;
846 bool b = CodeEditor::Key(key, count);
847 if(b && search.HasFocus())
848 SetFocus();
849 if(IsReadOnly())
850 return b;
851 if(assist.IsOpen()) {
852 bool (*test)(int c) = include_assist ? isincludefnchar : isaid;
853 if(!(*test)(key) &&
854 !((*test)(cc) && (key == K_DELETE || key == K_RIGHT)) &&
855 !((*test)(bcc) && (key == K_LEFT || key == K_BACKSPACE))) {
856 if(b) {
857 CloseAssist();
858 if(include_assist ? (key == '/' || key == '\\') : key == '.')
859 Assist();
860 }
861 }
862 else
863 SyncAssist();
864 }
865 else
866 if(auto_assist) {
867 if(InCode()) {
868 if(key == '.' || key == '>' && Ch(GetCursor32() - 2) == '-' ||
869 key == ':' && Ch(GetCursor32() - 2) == ':')
870 Assist();
871 else
872 if(key == '(') {
873 int q = GetCursor32() - 1;
874 String id = IdBack(q);
875 if(id == "THISBACK" || id == "THISBACK1" || id == "THISBACK2" || id == "THISBACK3" || id == "THISBACK4")
876 Assist();
877 }
878 }
879 if((key == '\"' || key == '<' || key == '/' || key == '\\') && GetUtf8Line(GetCursorLine()).StartsWith("#include"))
880 Assist();
881 }
882 return b;
883 }
884
MouseWheel(Point p,int zdelta,dword keyflags)885 void AssistEditor::MouseWheel(Point p, int zdelta, dword keyflags)
886 {
887 if(keyflags & K_CTRL)
888 WhenFontScroll(sgn(zdelta));
889 else
890 if(assist.IsOpen())
891 assist.MouseWheel(p, zdelta, keyflags);
892 else
893 CodeEditor::MouseWheel(p, zdelta, keyflags);
894 }
895
LeftDown(Point p,dword keyflags)896 void AssistEditor::LeftDown(Point p, dword keyflags)
897 {
898 CloseAssist();
899 CodeEditor::LeftDown(p, keyflags);
900 }
901
LostFocus()902 void AssistEditor::LostFocus()
903 {
904 CloseAssist();
905 }
906
RemoveDefPar(const char * s)907 String AssistEditor::RemoveDefPar(const char *s)
908 {
909 String r;
910 int lvl = 0;
911 bool dp = true;
912 while(*s) {
913 byte c = *s++;
914 if(c == '(')
915 lvl++;
916 if(lvl == 0) {
917 if(c == '=') {
918 dp = false;
919 if(commentdp)
920 r.Cat("/* ");
921 else
922 while(r.GetCount() && *r.Last() == ' ')
923 r.Trim(r.GetCount() - 1);
924 }
925 if(c == ')') {
926 if(!dp && commentdp)
927 r.Cat("*/");
928 r.Cat(')');
929 try {
930 if(CParser(s).Char('='))
931 break;
932 }
933 catch(CParser::Error) {}
934 r.Cat(s);
935 break;
936 }
937 if(c == ',') {
938 if(!dp && commentdp)
939 r.Cat("*/");
940 dp = true;
941 }
942 }
943 else
944 if(c == ')')
945 lvl--;
946 if(dp || commentdp)
947 r.Cat(c);
948 }
949 return r;
950 }
951
MakeDefinition(const String & cls,const String & _n)952 String AssistEditor::MakeDefinition(const String& cls, const String& _n)
953 {
954 String n = TrimLeft(_n);
955 auto RemoveId = [&](const char *s) {
956 int len = strlen(s);
957 int q = n.Find(s);
958 if(q >= 0 && (q == 0 || !iscid(n[q - 1])) && (q + len >= n.GetCount() || !iscid(n[q + len])))
959 n.Remove(q, len);
960 };
961 RemoveId("override");
962 RemoveId("final");
963 CParser p(n);
964 try {
965 bool dest = false;
966 const char *beg = n;
967 while(!p.IsEof()) {
968 const char *b = p.GetPtr();
969 if(p.Id("operator"))
970 return cls.GetCount() ? NormalizeSpaces(String(beg, b) + ' ' + cls + "::" + b)
971 : NormalizeSpaces(String(beg, b) + ' ' + b);
972 if(p.Char('~')) {
973 beg = p.GetPtr();
974 dest = true;
975 }
976 else
977 if(p.IsId()) {
978 String id = p.ReadId();
979 if(p.Char('(')) {
980 String rp = RemoveDefPar(p.GetPtr());
981 auto merge = [](String a, String b) {
982 return IsAlNum(*a.Last()) && IsAlNum(*b) ? a + ' ' + b : a + b;
983 };
984 if(cls.GetCount() == 0)
985 return NormalizeSpaces(merge(String(beg, b), id) + '(' + rp);
986 if(dest)
987 return NormalizeSpaces(String(beg, b) + cls + "::~" + id + '(' + rp);
988 else
989 return NormalizeSpaces(merge(String(beg, b), cls) + "::" + id + '(' + rp);
990 }
991 }
992 else
993 p.SkipTerm();
994 }
995 }
996 catch(CParser::Error) {}
997 return n;
998 }
999
IdeGotoCodeRef(String coderef)1000 void Ide::IdeGotoCodeRef(String coderef)
1001 {
1002 LLOG("IdeGotoLink " << coderef);
1003 CodeBaseLock __;
1004 if(IsNull(coderef)) return;
1005 String scope, item;
1006 SplitCodeRef(coderef, scope, item);
1007 int q = CodeBase().Find(scope);
1008 if(q < 0)
1009 return;
1010 const Array<CppItem>& n = CodeBase()[q];
1011 q = FindItem(n, item);
1012 if(q >= 0)
1013 JumpToDefinition(n, q, scope);
1014 }
1015
Esc()1016 bool AssistEditor::Esc()
1017 {
1018 bool r = false;
1019 if(assist.IsOpen()) {
1020 CloseAssist();
1021 r = true;
1022 }
1023 if(param_info.IsOpen()) {
1024 for(int i = 0; i < PARAMN; i++)
1025 param[i].line = -1;
1026 param_info.Close();
1027 r = true;
1028 }
1029 return r;
1030 }
1031
SyncNavigatorShow()1032 void AssistEditor::SyncNavigatorShow()
1033 {
1034 navigatorframe.Show(navigator && theide && !theide->designer && !theide->IsEditorMode());
1035 }
1036
Navigator(bool nav)1037 void AssistEditor::Navigator(bool nav)
1038 {
1039 navigator = nav;
1040 SyncNavigatorShow();
1041 if(IsNavigator())
1042 SetFocus();
1043 SyncNavigator();
1044 SyncCursor();
1045 }
1046
SyncNavigator()1047 void AssistEditor::SyncNavigator()
1048 {
1049 if(navigating)
1050 return;
1051 if(IsNavigator()) {
1052 Search();
1053 SyncCursor();
1054 }
1055 SyncNavigatorShow();
1056 }
1057
SelectionChanged()1058 void AssistEditor::SelectionChanged()
1059 {
1060 CodeEditor::SelectionChanged();
1061 SyncCursor();
1062 SyncParamInfo();
1063 }
1064
SerializeNavigator(Stream & s)1065 void AssistEditor::SerializeNavigator(Stream& s)
1066 {
1067 int version = 5;
1068 s / version;
1069 s % navigatorframe;
1070 s % navigator;
1071 if(version == 1 || version == 3) {
1072 Splitter dummy;
1073 s % dummy;
1074 }
1075 if(version >= 4)
1076 s % navigator_splitter;
1077 if(version >= 5)
1078 s % navigator_right;
1079 Navigator(navigator);
1080
1081 if(s.IsLoading())
1082 SyncNavigatorPlacement();
1083 }
1084