1 #include "Browser.h"
2 
3 #define CODEITEM   "37138531426314131252341829483370"
4 #define STRUCTITEM "37138531426314131252341829483380"
5 #define BEGINSTYLE "05600065144404261032431302351956"
6 #define ENDSTYLE   "96390100711032703541132217272105"
7 
8 static const char styles[] =
9 	"[ $$0,0#00000000000000000000000000000000:Default]"
10 	"[i448;a25;kKO9;2 $$1,0#" CODEITEM ":codeitem]"
11 	"[i448;a25;kKO9;3 $$2,0#" STRUCTITEM ":structitem]"
12 	"[l288;2 $$3,0#27521748481378242620020725143825:desc]"
13 	"[H6;0 $$4,0#" BEGINSTYLE ":begin]"
14 	"[l288;a25;kK~~~.1408;@3;2 $$5,0#61217621437177404841962893300719:param]"
15 	"[0 $$7,0#" ENDSTYLE ":end]"
16 ;
17 
JumpToDefinition()18 void TopicEditor::JumpToDefinition()
19 {
20 	PostCallback(callback1(IdeGotoCodeRef, editor.GetFormatInfo().label));
21 }
22 
Label(String & label)23 void TopicEditor::Label(String& label)
24 {
25 	Save();
26 	if(ref.item.IsMultiSelect())
27 		ref.item.ClearSelection();
28 	ref.item.MultiSelect(false);
29 	ref.Title("Reference");
30 	ref.Set(label);
31 	ref.classlist.Hide();
32 	if(ref.Execute() != IDOK)
33 		return;
34 	label = ref.Get();
35 }
36 
CodeItemUuid()37 Uuid CodeItemUuid()
38 {
39 	return ScanUuid(CODEITEM);
40 }
41 
StructItemUuid()42 Uuid StructItemUuid()
43 {
44 	return ScanUuid(STRUCTITEM);
45 }
46 
BeginUuid()47 Uuid BeginUuid()
48 {
49 	return ScanUuid(BEGINSTYLE);
50 }
51 
EndUuid()52 Uuid EndUuid()
53 {
54 	static Uuid u = ScanUuid(ENDSTYLE);
55 	return u;
56 }
57 
FindBrokenRef()58 void TopicEditor::FindBrokenRef()
59 {
60 	Uuid codeitem = CodeItemUuid();
61 	Uuid stritem = StructItemUuid();;
62 	for(;;) {
63 		if(IsNull(topicpath))
64 			return;
65 		const RichText& txt = editor.Get();
66 		int c = editor.GetCursor();
67 		int i = txt.FindPart(c);
68 		while(++i < txt.GetPartCount()) {
69 			if(txt.IsPara(i)) {
70 				Uuid style = txt.GetParaStyle(i);
71 				if(style == codeitem || style == stritem) {
72 					RichPara para = txt.Get(i);
73 					if(para.format.label == "noref")
74 						continue;
75 					if(!IsNull(para.format.label) && GetCodeRefItem(para.format.label))
76 						continue;
77 					editor.Move(txt.GetPartPos(i));
78 					return;
79 				}
80 			}
81 		}
82 		if(!topics_list.IsCursor())
83 			break;
84 		c = topics_list.GetCursor() + 1;
85 		if(c >= topics_list.GetCount()) {
86 			PromptOK("No more invalid references.");
87 			break;
88 		}
89 		topics_list.SetCursor(c);
90 		if(!IsNull(topicpath))
91 			editor.Move(0);
92 	}
93 }
94 
Tools(Bar & bar)95 void TopicEditor::Tools(Bar& bar)
96 {
97 	bar.Add("Insert code item..", IdeCommonImg::InsertItem(), THISBACK(InsertItem))
98 	   .Key(K_CTRL_INSERT);
99 	String l = editor.GetFormatInfo().label;
100 	bool b = l.GetCount() > 2 && l != "noref";
101 	bar.Add(b, "See referenced code", IdeCommonImg::Source(), THISBACK(JumpToDefinition))
102 	   .Key(K_ALT_J).Key(K_ALT_I);
103 	bar.Add("Find broken references..", IdeCommonImg::FindBrokenRef(), THISBACK(FindBrokenRef))
104 	   .Key(K_CTRL_F3);
105 #ifdef REPAIR
106 	bar.Separator();
107 	bar.Add("Repair!", CtrlImg::Toggle(), THISBACK(Repair)).Key(K_ALT_F5);
108 	bar.Separator();
109 #endif
110 }
111 
MainTool(Bar & bar)112 void TopicEditor::MainTool(Bar& bar)
113 {
114 	editor.StyleTool(bar);
115 	bar.Gap();
116 	editor.FontTools(bar);
117 	bar.Gap();
118 	editor.InkTool(bar);
119 	editor.PaperTool(bar);
120 	bar.Gap();
121 	editor.LanguageTool(bar);
122 	editor.SpellCheckTool(bar);
123 	bar.Gap();
124 	editor.IndexEntryTool(bar);
125 	bar.Break();
126 	editor.HyperlinkTool(bar, Zx(300), K_CTRL_H);
127 	bar.Gap();
128 	editor.ParaTools(bar);
129 	bar.Gap();
130 	editor.EditTools(bar);
131 	bar.Gap();
132 	bar.Add("Print", CtrlImg::print(), THISBACK(Print))
133 	   .Key(K_CTRL_P);
134 	bar.GapRight();
135 	bar.Break();
136 	editor.LabelTool(bar, Zx(300), K_CTRL_M, "Code reference");
137 	bar.Gap();
138 	Tools(bar);
139 	bar.Gap();
140 	editor.TableTools(bar);
141 }
142 
NaturalDeQtf(const char * s)143 String NaturalDeQtf(const char *s) {
144 	StringBuffer r;
145 	r.Reserve(256);
146 	bool cm = false;
147 	while(*s) {
148 		if(*s == ' ')
149 			r.Cat(cm ? ' ' : '_');
150 		else {
151 			if((byte)*s > ' ' && !IsDigit(*s) && !IsAlpha(*s) && (byte)*s < 128)
152 				r.Cat('`');
153 			r.Cat(*s);
154 			if(*s == ',')
155 				cm = true;
156 			else
157 				cm = false;
158 		}
159 		s++;
160 	}
161 	return String(r);
162 }
163 
sSplitT(int c)164 static int sSplitT(int c) {
165 	return c == ';' || c == '<' || c == '>' || c == ',';
166 }
167 
IsCodeRefType(const String & type)168 bool IsCodeRefType(const String& type)
169 {
170 	if(type.GetCount() == 0)
171 		return false;
172 	CodeBaseLock __;
173 	return CodeBase().Find(type) >= 0;
174 }
175 
DecoratedItem(const String & name,const CppItem & m,const char * natural,int pari)176 String DecoratedItem(const String& name, const CppItem& m, const char *natural, int pari)
177 {
178 	String qtf = "[%00-00K ";
179 	Vector<ItemTextPart> n = ParseItemNatural(name, m, natural);
180 	if(pari < 0) {
181 		if(m.virt)
182 			qtf << "[@B virtual] ";
183 		if(m.kind == CLASSFUNCTION || m.kind == CLASSFUNCTIONTEMPLATE)
184 			qtf << "[@B static] ";
185 	}
186 	Vector<String> qt = Split(m.qptype, sSplitT, false);
187 	Vector<String> tt = Split(m.qtype, sSplitT, false);
188 	for(int i = 0; i < n.GetCount(); i++) {
189 		ItemTextPart& p = n[i];
190 		qtf << "[";
191 		if(p.pari == pari)
192 			qtf << "$C";
193 		switch(p.type) {
194 		case ITEM_PNAME:
195 			qtf << "*";
196 		case ITEM_NUMBER:
197 			qtf << "@r";
198 			break;
199 		case ITEM_TNAME:
200 			qtf << "*@g";
201 			break;
202 		case ITEM_NAME:
203 			qtf << "*";
204 			break;
205 		case ITEM_UPP:
206 			qtf << "@c";
207 			break;
208 		case ITEM_CPP_TYPE:
209 		case ITEM_CPP:
210 			qtf << "@B";
211 			break;
212 		default:
213 			int q = p.type - ITEM_PTYPE;
214 			if(q >= 0 && q < qt.GetCount() && IsCodeRefType(qt[q]) && pari < 0)
215 				qtf << "_^" << qt[q] << '^';
216 			q = p.type - ITEM_TYPE;
217 			if(q >= 0 && q < tt.GetCount() && IsCodeRefType(tt[q]) && pari < 0)
218 				qtf << "_^" << tt[q] << '^';
219 			break;
220 		}
221 		qtf << ' ';
222 		qtf << NaturalDeQtf(String(~m.natural + p.pos, p.len));
223 		qtf << ']';
224 	}
225 	return qtf + "]";
226 }
227 
CreateQtf(const String & item,const String & name,const CppItem & m,const String & lang,bool onlyhdr=false)228 String CreateQtf(const String& item, const String& name, const CppItem& m, const String& lang, bool onlyhdr = false)
229 {
230 	String qtf;
231 	bool str = m.kind == STRUCT || m.kind == STRUCTTEMPLATE;
232 	if(!str)
233 		qtf << "[s4 &]";
234 	String st = str ? "[s2;" : "[s1;";
235 	String k = st + ':' + DeQtf(item) + ": ";
236 	if(m.IsTemplate() && str) {
237 		int q = 0;
238 		int w = 0;
239 		while(q < m.natural.GetLength()) {
240 			if(m.natural[q] == '<')
241 				w++;
242 			if(m.natural[q] == '>') {
243 				w--;
244 				if(w == 0) {
245 					q++;
246 					break;
247 				}
248 			}
249 			q++;
250 		}
251 		qtf << "[s2:noref: " << DecoratedItem(name, m, m.natural.Mid(0, q)) << "&][s2 " << k;
252 		if(q < m.natural.GetLength()) {
253 			while((byte)m.natural[q] <= 32)
254 				q++;
255 			qtf << DecoratedItem(name, m, m.natural.Mid(q));
256 		}
257 	}
258 	else
259 		qtf << k << DecoratedItem(name, m, m.natural);
260 
261 	qtf << "&]";
262 	if(onlyhdr)
263 		return qtf;
264 	qtf << "[s3%" << lang << " ";
265 	String d;
266 	Vector<String> t = Split(m.tname, ';');
267 	for(int i = 0; i < t.GetCount(); i++) {
268 		if(i)
269 			d << ' ';
270 		d << "[%-*@g " << DeQtf(t[i]) << "]";
271 	}
272 	d.Clear();
273 	d << "[%" << lang << " ";
274 	Vector<String> p = Split(m.pname, ';');
275 	if(!str)
276 		for(int i = 0; i < p.GetCount(); i++)
277 			d << " [%-*@r " << DeQtf(p[i]) << "]";
278 	if(!str && p.GetCount())
279 		qtf << d << " .";
280 	qtf << "&]";
281 	qtf << "[s7 &]";
282 	return qtf;
283 }
284 
GetLang() const285 String TopicEditor::GetLang() const
286 {
287 	int q = topicpath.ReverseFind('@');
288 	if(q >= 0) {
289 		int lang = LNGFromText(~topicpath + q + 1);
290 		if(lang)
291 			return LNGAsText(lang);
292 	}
293 	return "%";
294 }
295 
InsertItem()296 void TopicEditor::InsertItem()
297 {
298 	if(IsNull(topicpath))
299 		return;
300 	Save();
301 	ref.Title("Insert");
302 	if(ref.item.IsCursor())
303 		ref.item.SetFocus();
304 	ref.item.MultiSelect();
305 	ref.classlist.Show();
306 	int c = ref.Execute();
307 	if(c == IDCANCEL)
308 		return;
309 	if(c == IDYES) {
310 		String qtf = "&{{1 ";
311 		bool next = false;
312 		for(int i = 0; i < ref.scope.GetCount(); i++) {
313 			String s = ref.scope.Get(i, 1);
314 			if(*s != '<') {
315 				if(next)
316 					qtf << ":: ";
317 				qtf << DeQtf(s);
318 				next = true;
319 			}
320 		}
321 		qtf << "}}&";
322 		editor.PasteText(ParseQTF(qtf));
323 		return;
324 	}
325 	String qtf;
326 	if(ref.item.IsSelection()) {
327 		for(int i = 0; i < ref.item.GetCount(); i++)
328 			if(ref.item.IsSelected(i)) {
329 				CppItemInfo m = ref.GetItemInfo(i);
330 				qtf << CreateQtf(ref.GetCodeRef(i), m.name, m, GetLang());
331 			}
332 	}
333 	else
334 	if(ref.item.IsCursor()) {
335 		CppItemInfo m = ref.GetItemInfo();
336 		qtf << CreateQtf(ref.GetCodeRef(), m.name, m, GetLang());
337 	}
338 	else
339 		return;
340 	editor.BeginOp();
341 	editor.PasteText(ParseQTF(styles + qtf));
342 	editor.PrevPara();
343 	editor.PrevPara();
344 }
345 
InsertNew(const String & coderef)346 void TopicEditor::InsertNew(const String& coderef)
347 {
348 	const CppItem *m = GetCodeRefItem(coderef);
349 	if(!m)
350 		return;
351 	editor.BeginOp();
352 	editor.PasteText(ParseQTF(styles + CreateQtf(coderef, m->name, *m, GetLang())));
353 	editor.PrevPara();
354 	editor.PrevPara();
355 }
356 
GoTo(const String & _topic,const String & link,const String & create,bool before)357 void TopicEditor::GoTo(const String& _topic, const String& link, const String& create, bool before)
358 {
359 	if(topics_list.FindSetCursor(_topic) && !IsNull(link)) {
360 		editor.Select(editor.GetLength(), 0);
361 		if(!editor.GotoLabel(link)) {
362 			String l = link;
363 			LegacyRef(l);
364 			editor.GotoLabel(l);
365 		}
366 		if(!IsNull(create)) {
367 			if(!before)
368 				for(int pass = 0; pass < 2; pass++)
369 					for(;;) {
370 						int c = editor.GetCursor();
371 						RichText::FormatInfo f = editor.GetFormatInfo();
372 						if(f.styleid == BeginUuid() || (IsNull(f.label) || f.label == "noref") && pass)
373 							break;
374 						editor.NextPara();
375 						if(editor.GetCursor() == c)
376 							break;
377 					}
378 			InsertNew(create);
379 		}
380 	}
381 }
382 
FixTopic()383 void   TopicEditor::FixTopic()
384 {
385 	String nest;
386 	if(!EditText(nest, "Fix topic", "Nest"))
387 		return;
388 	CodeBaseLock __;
389 	CppBase& base = CodeBase();
390 	int q = base.Find(nest);
391 	if(q < 0) {
392 		Exclamation("Nest not found");
393 		return;
394 	}
395 	Array<CppItem>& n = base[q];
396 	Index<String> natural;
397 	Vector<String> link;
398 	for(int i = 0; i < n.GetCount(); i++) {
399 		const CppItem& m = n[i];
400 		String nat;
401 		if(m.virt)
402 			nat << "virtual ";
403 		if(m.kind == CLASSFUNCTION || m.kind == CLASSFUNCTIONTEMPLATE)
404 			nat << "static ";
405 		nat << m.natural;
406 		natural.Add(nat);
407 		link.Add(MakeCodeRef(nest, n[i].qitem));
408 	}
409 	RichText result;
410 	const RichText& txt = editor.Get();
411 	bool started = false;
412 
413 	int l, h;
414 	if(editor.GetSelection(l, h)) {
415 		l = txt.FindPart(l);
416 		h = txt.FindPart(h);
417 	}
418 	else {
419 		l = 0;
420 		h = txt.GetPartCount();
421 	}
422 
423 	for(int i = 0; i < txt.GetPartCount(); i++)
424 		if(txt.IsPara(i)) {
425 			RichPara p = txt.Get(i);
426 			if(i >= l && i < h) {
427 				WString h = p.GetText();
428 				String nat;
429 				const wchar *s = h;
430 				while(*s)
431 					if(*s == 160 || *s == ' ') {
432 						nat.Cat(' ');
433 						while(*s == 160 || *s == ' ') s++;
434 					}
435 					else
436 						nat.Cat(*s++);
437 				int q = nat.GetCount() ? natural.Find(nat) : -1;
438 				if(q >= 0) {
439 					started = true;
440 					const CppItem& m = n[q];
441 					RichText h = ParseQTF(styles + ("[s7; &]" + CreateQtf(link[q], n[q].name, m, GetLang(), true)));
442 					if(h.GetPartCount())
443 						h.RemovePart(h.GetPartCount() - 1);
444 					result.CatPick(pick(h));
445 				}
446 				else
447 				if(!started || p.GetLength())
448 					result.Cat(p);
449 			}
450 			else
451 				result.Cat(p);
452 		}
453 		else {
454 			RichTable b;
455 			b <<= txt.GetTable(i);
456 			result.CatPick(pick(b));
457 		}
458 	RichPara empty;
459 	result.Cat(empty);
460 	editor.BeginOp();
461 	editor.SetSelection(0, txt.GetLength());
462 	editor.PasteText(result);
463 }
464 
GetFileName() const465 String TopicEditor::GetFileName() const
466 {
467 	return grouppath;
468 }
469 
Save()470 void TopicEditor::Save()
471 {
472 	SaveTopic();
473 	SaveInc();
474 }
475 
SetFocus()476 void TopicEditor::SetFocus()
477 {
478 	if(editor.IsEnabled())
479 		editor.SetFocus();
480 	else
481 		Ctrl::SetFocus();
482 }
483