1 #include "ide.h"
2 
3 #define LTIMING(x) // RTIMING(x)
4 
FormatNest(String nest)5 String FormatNest(String nest)
6 {
7 	int q = nest.Find("@");
8 	if(q >= 0) {
9 		nest.Trim(q);
10 		nest << "[anonymous]";
11 	}
12 	return nest;
13 }
14 
CharFilterNavigator(int c)15 int CharFilterNavigator(int c)
16 {
17 	return c == ':' ? '.' : IsAlNum(c) || c == '_' || c == '.' ? c : 0;
18 }
19 
PaintTeXt(Draw & w,int & x,int y,const String & text,Font font,Color ink)20 void PaintTeXt(Draw& w, int& x, int y, const String& text, Font font, Color ink)
21 {
22 	static int maxascent = MaxAscent(StdFont());
23 	Size sz = GetTextSize(text, font);
24 	w.DrawText(x, y + maxascent - font.GetAscent(), text, font, ink);
25 	x += sz.cx;
26 }
27 
DrawFileName0(Draw & w,const Rect & r,const String & h,Color ink,int x)28 int DrawFileName0(Draw& w, const Rect& r, const String& h, Color ink, int x)
29 {
30 	if(h.GetCount() == 0)
31 		return 0;
32 	int q = h.Find("\xff");
33 	String ns;
34 	String fn = h;
35 	if(q >= 0) {
36 		ns = h.Mid(0, q) + ' ';
37 		fn = h.Mid(q + 1);
38 	}
39 	String s = GetFileName(GetFileFolder(h)) + "/";
40 	x += r.left;
41 	if(ns.GetCount()) {
42 		PaintTeXt(w, x, r.top, ns, StdFont().Bold(), ink);
43 		PaintTeXt(w, x, r.top, "(", StdFont(), ink);
44 	}
45 	PaintTeXt(w, x, r.top, s, StdFont(), ink);
46 	s = GetFileName(h);
47 	PaintTeXt(w, x, r.top, s, StdFont().Bold(), ink);
48 	if(ns.GetCount())
49 		PaintTeXt(w, x, r.top, ")", StdFont(), ink);
50 	return x - r.left;
51 }
52 
GetDrawFileNameSize(const String & h)53 Size GetDrawFileNameSize(const String& h)
54 {
55 	NilDraw w;
56 	return Size(DrawFileName0(w, Size(999999, 999999), h, Null, 0), StdFont().Bold().GetCy());
57 }
58 
DrawFileName(Draw & w,const Rect & r,const String & h,Color ink)59 void DrawFileName(Draw& w, const Rect& r, const String& h, Color ink)
60 {
61 	DrawFileName0(w, r, h, ink, min(r.GetWidth() - GetDrawFileNameSize(h).cx, 0));
62 }
63 
PaintFileName(Draw & w,const Rect & r,String h,Color ink)64 int PaintFileName(Draw& w, const Rect& r, String h, Color ink)
65 {
66 	if(*h == '\xff')
67 		h.Remove(0, 1);
68 	return DrawFileName0(w, r, h, ink, 0);
69 }
70 
Navigator()71 Navigator::Navigator()
72 :	navidisplay(litem)
73 {
74 	scope_display.navigator = this;
75 	scope.NoHeader();
76 	scope.AddColumn().SetDisplay(scope_display);
77 	scope.NoWantFocus();
78 	scope.WhenSel = THISBACK(Scope);
79 	scope.WhenLeftDouble = THISBACK(ScopeDblClk);
80 
81 	list.NoHeader();
82 	list.AddRowNumColumn().SetDisplay(navidisplay);
83 	list.SetLineCy(max(16, GetStdFontCy()));
84 	list.NoWantFocus();
85 	list.WhenLeftClick = THISBACK(NavigatorClick);
86 	list.WhenSel = THISBACK(SyncNavLines);
87 	list.WhenLineEnabled = THISBACK(ListLineEnabled);
88 
89 	navlines.NoHeader().NoWantFocus();
90 	navlines.WhenLeftClick = THISBACK(GoToNavLine);
91 	navlines.AddColumn().SetDisplay(Single<LineDisplay>());
92 
93 	search <<= THISBACK(TriggerSearch);
94 	search.SetFilter(CharFilterNavigator);
95 	search.WhenEnter = THISBACK(NavigatorEnter);
96 
97 	sortitems.Image(BrowserImg::Sort());
98 	sortitems <<= THISBACK(NaviSort);
99 	sorting = false;
100 
101 	dlgmode = false;
102 }
103 
SyncCursor()104 void Navigator::SyncCursor()
105 {
106 	String k = "(" + GetKeyDesc(IdeKeys::AK_GOTO().key[0]) + ") ";
107 	search.NullText("Symbol/lineno " + k);
108 	search.Tip(IsNull(search) ? String() : "Clear " + k);
109 
110 	if(!navigating && theide->editfile.GetCount()) {
111 		navlines.KillCursor();
112 		int q = linefo.Find(GetSourceFileIndex(theide->editfile));
113 		if(q < 0)
114 			return;
115 		navigating = true;
116 		SortedVectorMap<int, int>& m = linefo[q];
117 		q = m.FindUpperBound(GetCurrentLine() + 1) - 1;
118 		if(q >= 0 && q < m.GetCount())
119 			list.SetCursor(m[q]);
120 		navigating = false;
121 	}
122 	SyncLines();
123 	if(scope.IsCursor())
124 		scope.RefreshRow(scope.GetCursor());
125 }
126 
SyncLines()127 void Navigator::SyncLines()
128 {
129 	if(IsNull(theide->editfile) || navigating)
130 		return;
131 	int ln = GetCurrentLine() + 1;
132 	int fi = GetSourceFileIndex(theide->editfile);
133 	int q = -1;
134 	for(int i = 0; i < navlines.GetCount(); i++) {
135 		const NavLine& l = navlines.Get(i, 0).To<NavLine>();
136 		if(l.file == fi && l.line <= ln && i < navlines.GetCount())
137 			q = i;
138 	}
139 	if(dlgmode)
140 		navlines.GoBegin();
141 	else
142 	if(q >= 0)
143 		navlines.SetCursor(q);
144 }
145 
SyncNavLines()146 void Navigator::SyncNavLines()
147 {
148 	int sc = navlines.GetScroll();
149 	navlines.Clear();
150 	int ii = list.GetCursor();
151 	if(ii >= 0 && ii < litem.GetCount()) {
152 		Vector<NavLine> l = GetNavLines(*litem[ii]);
153 		for(int i = 0; i < l.GetCount(); i++) {
154 			String p = GetSourceFilePath(l[i].file);
155 			navlines.Add(RawToValue(l[i]));
156 		}
157 		navlines.ScrollTo(sc);
158 		SyncLines();
159 	}
160 }
161 
DoPaint(Draw & w,const Rect & r,const Value & q,Color ink,Color paper,dword style,int x) const162 int Navigator::LineDisplay::DoPaint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style, int x) const
163 {
164 	w.DrawRect(r, paper);
165 	const NavLine& l = q.To<NavLine>();
166 	x += r.left;
167 	String p = GetSourceFilePath(l.file);
168 	int y = r.top + (r.GetHeight() - StdFont().GetCy()) / 2;
169 	PaintTeXt(w, x, y, GetFileName(GetFileFolder(p)) + "/", StdFont(), ink);
170 	PaintTeXt(w, x, y, GetFileName(p), StdFont().Bold(), ink);
171 	PaintTeXt(w, x, y, " (", StdFont(), ink);
172 	PaintTeXt(w, x, y, AsString(l.line), StdFont().Bold(), ink);
173 	PaintTeXt(w, x, y, ")", StdFont(), ink);
174 	return x - r.left;
175 }
176 
Paint(Draw & w,const Rect & r,const Value & q,Color ink,Color paper,dword style) const177 void Navigator::LineDisplay::Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const
178 {
179 	DoPaint(w, r, q, ink, paper, style, min(r.GetWidth() - GetStdSize(q).cx, 0));
180 }
181 
GetStdSize(const Value & q) const182 Size Navigator::LineDisplay::GetStdSize(const Value& q) const
183 {
184 	NilDraw w;
185 	return Size(DoPaint(w, Size(999999, 999999), q, White(), White(), 0, 0), StdFont().Bold().GetCy());
186 }
187 
GoToNavLine()188 void Navigator::GoToNavLine()
189 {
190 	if(dlgmode)
191 		return;
192 	int ii = navlines.GetClickPos().y;
193 	if(ii >= 0 && ii < navlines.GetCount() && theide) {
194 		const NavLine& l = navlines.Get(ii, 0).To<NavLine>();
195 		theide->GotoPos(GetSourceFilePath(l.file), l.line);
196 	}
197 }
198 
operator <(const NavLine & b) const199 bool Navigator::NavLine::operator<(const NavLine& b) const
200 {
201 	String p1 = GetSourceFilePath(file);
202 	String p2 = GetSourceFilePath(b.file);
203 	return CombineCompare/*(!impl, !b.impl)*/
204 	                     (GetFileExt(p2), GetFileExt(p1)) // .h > .c
205 	                     (GetFileName(p1), GetFileName(p2))
206 	                     (p1, p2)
207 	                     (line, b.line) < 0;
208 }
209 
GetNavLines(const NavItem & m)210 Vector<Navigator::NavLine> Navigator::GetNavLines(const NavItem& m)
211 {
212 	CodeBaseLock __;
213 	Vector<NavLine> l;
214 	int q = CodeBase().Find(m.nest);
215 	if(q < 0 || IsNull(m.qitem))
216 		return l;
217 	const Array<CppItem>& a = CodeBase()[q];
218 	for(int i = 0; i < a.GetCount(); i++) {
219 		const CppItem& mm = a[i];
220 		if(mm.qitem == m.qitem) {
221 			NavLine& nl = l.Add();
222 			nl.impl = mm.impl;
223 			nl.file = mm.file;
224 			nl.line = mm.line;
225 		}
226 	}
227 	Sort(l);
228 	return l;
229 }
230 
Navigate()231 void Navigator::Navigate()
232 {
233 	if(navigating)
234 		return;
235 	navigating = true;
236 	int ii = list.GetCursor();
237 	if(theide && ii >= 0 && ii < litem.GetCount()) {
238 		int ln = GetCurrentLine() + 1;
239 		const NavItem& m = *litem[ii];
240 		if(m.kind == KIND_LINE || IsNull(search)) {
241 			theide->GotoPos(Null, m.line);
242 			if(m.kind == KIND_LINE) { // Go to line - restore file view
243 				search.Clear();
244 				Search();
245 				navigating = false;
246 			}
247 			SyncCursor();
248 		}
249 		else
250 		if(m.kind == KIND_SRCFILE) {
251 			theide->AddHistory();
252 			theide->EditFile(m.ptype);
253 			theide->AddHistory();
254 		}
255 		else {
256 			Vector<NavLine> l = GetNavLines(m);
257 			int q = l.GetCount() - 1;
258 			for(int i = 0; i < l.GetCount(); i++)
259 				if(GetSourceFilePath(l[i].file) == NormalizeSourcePath(theide->editfile) && l[i].line == ln) {
260 					q = (i + l.GetCount() + 1) % l.GetCount();
261 					break;
262 				}
263 			if(q >= 0 && q < l.GetCount()) {
264 				String path = GetSourceFilePath(l[q].file);
265 				if(!theide->GotoDesignerFile(path, m.nest, m.name, l[q].line))
266 					theide->GotoPos(path, l[q].line);
267 			}
268 		}
269 	}
270 	navigating = false;
271 }
272 
ScopeDblClk()273 void Navigator::ScopeDblClk()
274 {
275 	if(!scope.IsCursor())
276 		return;
277 	String h = scope.GetKey();
278 	if((byte)*h == 0xff)
279 		theide->GotoPos(h.Mid(1), 1);
280 	else {
281 		list.GoBegin();
282 		Navigate();
283 	}
284 }
285 
NavigatorClick()286 void Navigator::NavigatorClick()
287 {
288 	if(dlgmode)
289 		return;
290 	int q = list.GetClickPos().y;
291 	if(q >= 0 && q < list.GetCount())
292 		Navigate();
293 }
294 
NavigatorEnter()295 void Navigator::NavigatorEnter()
296 {
297 	if(list.GetCount()) {
298 		list.GoBegin();
299 		Navigate();
300 	}
301 }
302 
ToggleNavigator()303 void Ide::ToggleNavigator()
304 {
305 	editor.Navigator(!editor.navigator);
306 }
307 
SearchCode()308 void Ide::SearchCode()
309 {
310 	if(!editor.navigator)
311 		editor.Navigator(true);
312 	if(!IsNull(~editor.search)) {
313 		editor.search.Clear();
314 		editor.Search();
315 		editor.SetFocus();
316 	}
317 	else {
318 		String h = editor.GetWord();
319 		if(h.GetCount()) {
320 			editor.search <<= h;
321 			editor.search.SelectAll();
322 			editor.Search();
323 		}
324 		editor.search.SetFocus();
325 	}
326 }
327 
SwitchHeader()328 void Ide::SwitchHeader() {
329 	int c = filelist.GetCursor();
330 	if(c < 0) return;
331 	String currfile = filelist[c];
332 	const char *ext = GetFileExtPos(currfile);
333 	if(!stricmp(ext, ".h") || !stricmp(ext, ".hpp")
334 	|| !stricmp(ext, ".lay") || !stricmp(ext, ".iml")) {
335 		int f = filelist.Find(ForceExt(currfile, ".cpp"));
336 		if(f < 0) f = filelist.Find(ForceExt(currfile, ".c"));
337 		if(f < 0) f = filelist.Find(ForceExt(currfile, ".cc"));
338 		if(f >= 0) filelist.SetCursor(f);
339 	}
340 }
341 
Set(const CppItem & m)342 void Navigator::NavItem::Set(const CppItem& m)
343 {
344 	qitem = m.qitem;
345 	name = m.name;
346 	uname = m.uname;
347 	natural = m.natural;
348 	type = m.type;
349 	pname = m.pname;
350 	ptype = m.ptype;
351 	tname = m.tname;
352 	ctname = m.ctname;
353 	access = m.access;
354 	kind = m.kind;
355 	at = m.at;
356 	line = m.line;
357 	file = m.file;
358 	impl = m.impl;
359 	pass = false;
360 }
361 
PaintBackground(Draw & w,const Rect & r,const Value & q,Color ink,Color paper,dword style) const362 void Navigator::NavigatorDisplay::PaintBackground(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const
363 {
364 	int ii = q;
365 	if(ii < 0 || ii >= item.GetCount())
366 		return;
367 	const NavItem& m = *item[ii];
368 	bool focuscursor = (style & (FOCUS|CURSOR)) == (FOCUS|CURSOR) || (style & SELECT);
369 	if(findarg(m.kind, KIND_FILE, KIND_NEST) >= 0)
370 		w.DrawRect(r, focuscursor ? paper : m.kind == KIND_NEST ? Blend(SColorMark, SColorPaper, 220)
371 		                                    : SColorFace);
372 	else
373 		w.DrawRect(r, paper);
374 }
375 
376 
DoPaint(Draw & w,const Rect & r,const Value & q,Color ink,Color paper,dword style) const377 int Navigator::NavigatorDisplay::DoPaint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const
378 {
379 	int ii = q;
380 	if(ii < 0 || ii >= item.GetCount())
381 		return 0;
382 	const NavItem& m = *item[ii];
383 	bool focuscursor = (style & (FOCUS|CURSOR)) == (FOCUS|CURSOR) || (style & SELECT);
384 
385 	int x = r.left;
386 	int ry = r.top + r.GetHeight() / 2;
387 	int y = ry - Draw::GetStdFontCy() / 2;
388 
389 	if(findarg(m.kind, KIND_FILE, KIND_NEST) >= 0) {
390 		w.DrawRect(r, focuscursor ? paper : m.kind == KIND_NEST ? Blend(SColorMark, SColorPaper, 220)
391 		                                    : SColorFace);
392 		if(findarg(m.kind, KIND_FILE) >= 0)
393 			return PaintFileName(w, r, m.type, ink);
394 		String h = FormatNest(m.type);
395 		w.DrawText(x, y, h, StdFont().Bold(), ink);
396 		return GetTextSize(h, StdFont().Bold()).cx;
397 	}
398 
399 	w.DrawRect(r, paper);
400 
401 	if(m.kind == KIND_SRCFILE)
402 		return PaintFileName(w, r, m.type, ink);
403 
404 	if(m.kind == KIND_LINE) {
405 		w.DrawText(x, y, m.type, StdFont().Bold(), ink);
406 		return GetTextSize(m.type, StdFont().Bold()).cx;
407 	}
408 
409 	PaintCppItemImage(w, x, ry, m.access, m.kind, focuscursor);
410 
411 	x += Zx(15);
412 	Vector<ItemTextPart> n = ParseItemNatural(m.name, m.natural, m.ptype, m.pname, m.type,
413 	                                          m.tname, m.ctname, ~m.natural + m.at);
414 	int starti = 0;
415 	for(int i = 0; i < n.GetCount(); i++)
416 		if(n[i].type == ITEM_NAME) {
417 			starti = i;
418 			break;
419 		}
420 	PaintText(w, x, y, m.natural, n, starti, n.GetCount(), focuscursor, ink, false);
421 	if(starti) {
422 		const char *h = " : ";
423 		w.DrawText(x, y, h, BrowserFont(), SColorText);
424 		x += GetTextSize(h, BrowserFont()).cx;
425 	}
426 	PaintText(w, x, y, m.natural, n, 0, starti, focuscursor, ink, false);
427 	return x;
428 }
429 
Paint(Draw & w,const Rect & r,const Value & q,Color ink,Color paper,dword style) const430 void Navigator::NavigatorDisplay::Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const
431 {
432 	DoPaint(w, r, q, ink, paper, style);
433 }
434 
GetStdSize(const Value & q) const435 Size Navigator::NavigatorDisplay::GetStdSize(const Value& q) const
436 {
437 	NilDraw w;
438 	return Size(DoPaint(w, Size(999999, 999999), q, White(), White(), 0), Draw::GetStdFontCy());
439 }
440 
TriggerSearch()441 void Navigator::TriggerSearch()
442 {
443 	search_trigger.KillSet(100, THISBACK(Search));
444 }
445 
NavGroup(bool local)446 void Navigator::NavGroup(bool local)
447 {
448 	CodeBaseLock __;
449 	for(int i = 0; i < nitem.GetCount(); i++) {
450 		NavItem& m = nitem[i];
451 		String g = m.nest;
452 		if(m.kind == TYPEDEF)
453 			g.Trim(max(g.ReverseFind("::"), 0));
454 		if(IsNull(g) || CodeBase().namespaces.Find(m.nest) >= 0) {
455 			if(g.GetCount()) // We want to show the namespace
456 				g << '\xff';
457 			else
458 				g.Clear();
459 			g << GetSourceFilePath(m.decl_file);
460 			g = '\xff' + g;
461 		}
462 		if(!local)
463 			g = (char)(m.pass + 10) + g;
464 		if(local)
465 			if(gitem.GetCount() && gitem.TopKey() == g)
466 				gitem.Top().Add(&m);
467 			else
468 				gitem.Add(g).Add(&m);
469 		else
470 			gitem.GetAdd(g).Add(&m);
471 	}
472 }
473 
474 force_inline
SortByLines(const NavItem * a,const NavItem * b)475 bool Navigator::SortByLines(const NavItem *a, const NavItem *b)
476 {
477 	return CombineCompare(a->decl_file, b->decl_file)(a->decl_line, b->decl_line) < 0;
478 }
479 
480 force_inline
SortByNames(const NavItem * a,const NavItem * b)481 bool Navigator::SortByNames(const NavItem *a, const NavItem *b)
482 {
483 	return CombineCompare(a->name, b->name)(a->qitem, b->qitem) < 0;
484 }
485 
Search()486 void Navigator::Search()
487 {
488 	CodeBaseLock __;
489 	sortitems.Check(sorting);
490 	int sc = scope.GetScroll();
491 	String key = scope.GetKey();
492 	String s = TrimBoth(~search);
493 	String search_name, search_nest;
494 	bool wholeclass = false;
495 	bool both = false;
496 	navigator_global = false;
497 	if(s.Find('.') >= 0) {
498 		Vector<String> h = Split((String)~search, '.');
499 		if(*s.Last() == '.')
500 			search_nest = Join(h, "::");
501 		else {
502 			search_name = h.Pop();
503 			if(h.GetCount())
504 				search_nest = Join(h, "::");
505 		}
506 		wholeclass = *s == '.' && search_nest.GetCount();
507 	}
508 	else {
509 		search_name = search_nest = ~search;
510 		both = true;
511 	}
512 	s = Join(Split(s, '.'), "::") + (s.EndsWith(".") ? "::" : "");
513 	int lineno = StrInt(s);
514 	gitem.Clear();
515 	nitem.Clear();
516 	if(IsNull(theide->editfile))
517 		return;
518 	int fileii = GetSourceFileIndex(theide->editfile);
519 	if(!IsNull(lineno)) {
520 		NavItem& m = nitem.Add();
521 		m.type = "Go to line " + AsString(lineno);
522 		m.kind = KIND_LINE;
523 		m.line = lineno;
524 		gitem.Add(Null).Add(&m);
525 	}
526 	else
527 	if(IsNull(s) && !sorting) {
528 		const CppBase& b = CodeBase();
529 		bool sch = GetFileExt(theide->editfile) == ".sch";
530 		for(int i = 0; i < b.GetCount(); i++) {
531 			String nest = b.GetKey(i);
532 			const Array<CppItem>& ci = b[i];
533 			for(int j = 0; j < ci.GetCount(); j++) {
534 				const CppItem& m = ci[j];
535 				if(m.file == fileii && (!sch || !m.IsData() || m.type != "SqlId")) {
536 					NavItem& n = nitem.Add();
537 					n.Set(m);
538 					n.nest = nest;
539 					n.decl_line = m.line;
540 					n.decl_file = m.file;
541 					n.decl = !m.impl;
542 					NavLine& l = n.linefo.Add();
543 					l.impl = m.impl;
544 					l.file = m.file;
545 					l.line = m.line;
546 				}
547 			}
548 		}
549 		Sort(nitem, FieldRelation(&NavItem::line, StdLess<int>()));
550 		NavGroup(true);
551 	}
552 	else {
553 		navigator_global = true;
554 		const CppBase& b = CodeBase();
555 		String usearch_nest = ToUpper(search_nest);
556 		String usearch_name = ToUpper(search_name);
557 		ArrayMap<String, NavItem> imap;
558 		bool local = sorting && IsNull(s);
559 		VectorMap<String, int> nest_pass;
560 		for(int pass = -1; pass < 2; pass++) {
561 			for(int i = 0; i < b.GetCount(); i++) {
562 				String nest = b.GetKey(i);
563 				bool foundnest = (wholeclass ? pass < 0 ? false :
564 				                               pass ? ToUpper(nest) == usearch_nest
565 				                                    : nest == search_nest
566 				                             : pass < 0 ? nest == search_nest :
567 				                               (pass ? ToUpper(nest).Find(usearch_nest) >= 0
568 				                                     : nest.StartsWith(search_nest)))
569 				                 && nest.Find('@') < 0;
570 				if(local || foundnest || both) {
571 					const Array<CppItem>& ci = b[i];
572 					for(int j = 0; j < ci.GetCount(); j++) {
573 						const CppItem& m = ci[j];
574 						if(local ? m.file == fileii
575 						         : m.uname.Find('@') < 0 && (pass < 0 ? m.name == search_name :
576 						                               pass ? m.uname.Find(usearch_name) >= 0
577 						                                    : m.name.StartsWith(search_name))
578 						           || both && foundnest) {
579 							String key = nest + '\1' + m.qitem;
580 							int q = nest_pass.Find(nest);
581 							int p = pass;
582 							if(q < 0) // We do not want classes to be split based on pass
583 								nest_pass.Add(nest, pass);
584 							else
585 								p = nest_pass[q];
586 							q = imap.Find(key);
587 							if(q < 0) {
588 								NavItem& ni = imap.Add(key);
589 								ni.Set(m);
590 								ni.nest = nest;
591 								ni.decl_line = ni.line;
592 								ni.decl_file = ni.file;
593 								ni.decl = !ni.impl;
594 								ni.pass = p;
595 								NavLine& l = ni.linefo.Add();
596 								l.impl = m.impl;
597 								l.file = m.file;
598 								l.line = m.line;
599 							}
600 							else {
601 								NavItem& mm = imap[q];
602 								if(!m.impl &&
603 								  (!mm.decl
604 								    || CombineCompare(mm.decl_file, m.file)(mm.decl_line, m.line) < 0)) {
605 										mm.decl = true;
606 										mm.decl_line = m.line;
607 										mm.decl_file = m.file;
608 										mm.natural = m.natural;
609 								}
610 								NavLine& l = mm.linefo.Add();
611 								l.impl = m.impl;
612 								l.file = m.file;
613 								l.line = m.line;
614 							}
615 						}
616 					}
617 				}
618 			}
619 		}
620 		nitem = imap.PickValues();
621 		NavGroup(false);
622 		SortByKey(gitem);
623 		Vector<String> keys = gitem.PickKeys();
624 		Vector<Vector<NavItem *> > values = gitem.PickValues();
625 		IndexSort(keys, values);
626 		for(int i = 0; i < keys.GetCount(); i++)
627 			keys[i].Remove(0);
628 		VectorMap<String, Vector<NavItem *> > h(pick(keys), pick(values));
629 		gitem = pick(h);
630 		for(int i = 0; i < gitem.GetCount(); i++)
631 			Sort(gitem[i], sorting ? SortByNames : SortByLines);
632 		const Workspace& wspc = GetIdeWorkspace();
633 		String s = ToUpper(TrimBoth(~search));
634 		for(int i = 0; i < wspc.GetCount(); i++) {
635 			const Package& p = wspc.GetPackage(i);
636 			for(int j = 0; j < p.GetCount(); j++) {
637 				if(!p[j].separator && ToUpper(p[j]).Find(s) >= 0) {
638 					NavItem& m = nitem.Add();
639 					m.kind = KIND_SRCFILE;
640 					m.type = wspc[i] + "/" + p[j];
641 					m.ptype = SourcePath(wspc[i], p[j]);
642 					m.line = 0;
643 					gitem.GetAdd("<files>").Add(&m);
644 				}
645 			}
646 		}
647 	}
648 	scope.Clear();
649 	scope.Add(Null);
650 	Index<String> done;
651 	for(int i = 0; i < gitem.GetCount(); i++) {
652 		String s = gitem.GetKey(i);
653 		if(done.Find(s) < 0) {
654 			done.Add(s);
655 			scope.Add(s);
656 		}
657 	}
658 	scope.ScrollTo(sc);
659 	if(!navigator_global || !scope.FindSetCursor(key))
660 		scope.GoBegin();
661 }
662 
DoPaint(Draw & w,const Rect & r,const Value & q,Color ink,Color paper,dword style) const663 int Navigator::ScopeDisplay::DoPaint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const
664 {
665 	w.DrawRect(r, paper);
666 	if(IsNull(q)) {
667 		const char *txt = "* ";
668 		int x = 0;
669 		w.DrawText(r.left, r.top, txt, StdFont().Bold().Italic(),
670 		           style & CURSOR ? ink : HighlightSetup::GetHlStyle(HighlightSetup::INK_KEYWORD).color);
671 		x += GetTextSize(txt, StdFont().Bold().Italic()).cx;
672 		int ii = navigator->list.GetCursor();
673 		if(ii >= 0 && ii < navigator->litem.GetCount()) {
674 			const NavItem& m = *navigator->litem[ii];
675 			String txt = m.nest;
676 			if(IsCppCode(m.kind))
677 				txt << "::" << m.name;
678 			w.DrawText(r.left + x, r.top, txt, StdFont().Bold(), ink);
679 			x += GetTextSize(txt, StdFont().Bold()).cx;
680 		}
681 		return x;
682 	}
683 	String h = q;
684 	if(*h == '\xff')
685 		return PaintFileName(w, r, h, ink);
686 	else
687 		h = FormatNest(h);
688 	w.DrawText(r.left, r.top, h, StdFont(), ink);
689 	return GetTextSize(h, StdFont()).cx;
690 }
691 
Paint(Draw & w,const Rect & r,const Value & q,Color ink,Color paper,dword style) const692 void Navigator::ScopeDisplay::Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const
693 {
694 	DoPaint(w, r, q, ink, paper, style);
695 }
696 
GetStdSize(const Value & q) const697 Size Navigator::ScopeDisplay::GetStdSize(const Value& q) const
698 {
699 	NilDraw w;
700 	return Size(DoPaint(w, Size(999999, 999999), q, White(), White(), 0), StdFont().Bold().GetCy());
701 }
702 
Scope()703 void Navigator::Scope()
704 {
705 	LTIMING("FINALIZE");
706 	litem.Clear();
707 	nest_item.Clear();
708 	linefo.Clear();
709 	bool all = scope.GetCursor() <= 0;
710 	String sc = scope.GetKey();
711 	for(int i = 0; i < gitem.GetCount(); i++) {
712 		String grp = gitem.GetKey(i);
713 		int    kind = KIND_NEST;
714 		if(*grp == '\xff')
715 			kind = KIND_FILE;
716 		if(all) {
717 			NavItem& m = nest_item.Add();
718 			m.kind = kind;
719 			m.type = FormatNest(grp);
720 			litem.Add(&m);
721 		}
722 		else
723 		if(grp != sc)
724 			continue;
725 		const Vector<NavItem *>& ia = gitem[i];
726 		for(int i = 0; i < ia.GetCount(); i++) {
727 			NavItem *m = ia[i];
728 			for(int j = 0; j < m->linefo.GetCount(); j++)
729 				linefo.GetAdd(m->linefo[j].file).Add(m->linefo[j].line, litem.GetCount());
730 			litem.Add(m);
731 		}
732 	}
733 	list.Clear();
734 	list.SetVirtualCount(litem.GetCount());
735 }
736 
ListLineEnabled(int i,bool & b)737 void Navigator::ListLineEnabled(int i, bool& b)
738 {
739 	if(i >= 0 && i < litem.GetCount()) {
740 		int kind = litem[i]->kind;
741 		if(findarg(kind, KIND_FILE, KIND_NEST) >= 0)
742 			b = false;
743 	}
744 }
745 
NaviSort()746 void Navigator::NaviSort()
747 {
748 	sorting = !sorting;
749 	Search();
750 }
751