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