1 #include "ide.h"
2 
Annotate(const String & filename)3 void AssistEditor::Annotate(const String& filename)
4 {
5 	CodeBaseLock __;
6 	int fi = GetSourceFileIndex(filename);
7 	CppBase& base = CodeBase();
8 	ClearAnnotations();
9 	for(int j = 0; j < base.GetCount(); j++) {
10 		String nest = base.GetKey(j);
11 		if(*nest != '@') { // Annotations of anonymous structures not suported
12 			const Array<CppItem>& n = base[j];
13 			for(int k = 0; k < n.GetCount(); k++) {
14 				const CppItem& m = n[k];
15 				if(m.file == fi) {
16 					String coderef = MakeCodeRef(nest, m.qitem);
17 					SetAnnotation(m.line - 1,
18 					              GetRefLinks(coderef).GetCount() ? IdeImg::tpp_doc()
19 					                                              : IdeImg::tpp_pen(),
20 					              coderef);
21 				}
22 			}
23 		}
24 	}
25 }
26 
IsCodeItem(const RichTxt & txt,int i)27 bool IsCodeItem(const RichTxt& txt, int i)
28 {
29 	static Uuid codeitem = CodeItemUuid();
30 	static Uuid stritem = StructItemUuid();
31 	if(i < txt.GetPartCount() && txt.IsPara(i)) {
32 		Uuid style = txt.GetParaStyle(i);
33 		return style == codeitem || style == stritem;
34 	}
35 	return false;
36 }
37 
IsBeginEnd(RichText & txt,int i)38 bool IsBeginEnd(RichText& txt, int i)
39 {
40 	static Uuid begin = BeginUuid();
41 	static Uuid end = EndUuid();
42 	if(i < txt.GetPartCount() && txt.IsPara(i)) {
43 		Uuid style = txt.GetParaStyle(i);
44 		return style == begin || style == end;
45 	}
46 	return false;
47 }
48 
GetAnnotationRefs(Vector<String> & tl,String & coderef,int q)49 bool AssistEditor::GetAnnotationRefs(Vector<String>& tl, String& coderef, int q)
50 {
51 	if(annotation_popup.IsOpen())
52 		annotation_popup.Close();
53 	if(q < 0)
54 		q = GetActiveAnnotationLine();
55 	if(q < 0)
56 		return false;
57 	coderef = GetAnnotation(q);
58 	if(IsNull(coderef))
59 		return false;
60 	tl = GetRefLinks(coderef);
61 	return true;
62 }
63 
GetAnnotationRef(String & t,String & coderef,int q)64 bool AssistEditor::GetAnnotationRef(String& t, String& coderef, int q)
65 {
66 	Vector<String> tl;
67 	if(!GetAnnotationRefs(tl, coderef, q))
68 		return false;
69 	if(tl.GetCount() == 0)
70 		return true;
71 	String path = theide ? theide->editfile : Null;
72 	int mi = 0;
73 	int m = 0;
74 	for(int i = 0; i < tl.GetCount(); i++) {
75 		int mm = GetMatchLen(tl[i], path);
76 		if(mm > m) {
77 			mi = i;
78 			m = mm;
79 		}
80 	}
81 	t = tl[mi];
82 	return true;
83 }
84 
SyncAnnotationPopup()85 void AssistEditor::SyncAnnotationPopup()
86 {
87 	String coderef;
88 	String tl;
89 	if(!GetAnnotationRef(tl, coderef))
90 		return;
91 	if(tl.GetCount()) {
92 		static String   last_path;
93 		static RichText topic_text;
94 		String path = GetTopicPath(tl);
95 		if(path != last_path)
96 			topic_text = ParseQTF(ReadTopic(LoadFile(path)).text);
97 		RichText result;
98 		String cr = coderef;
99 		for(int pass = 0; pass < 2; pass++) {
100 			for(int i = 0; i < topic_text.GetPartCount(); i++)
101 				if(topic_text.IsTable(i)) {
102 					const RichTable& t = topic_text.GetTable(i);
103 					Size sz = t.GetSize();
104 					for(int y = 0; y < sz.cy; y++)
105 						for(int x = 0; x < sz.cx; x++) {
106 							const RichTxt& txt = t.Get(y, x);
107 							for(int i = 0; i < txt.GetPartCount(); i++) {
108 								if(txt.IsPara(i) && txt.Get(i, topic_text.GetStyles()).format.label == cr) {
109 									RichTable r(t, 1);
110 									result.CatPick(pick(r));
111 									goto done;
112 								}
113 							}
114 						}
115 				}
116 				else
117 				if(IsCodeItem(topic_text, i) && topic_text.Get(i).format.label == cr) {
118 					while(i > 0 && IsCodeItem(topic_text, i)) i--;
119 					if(!IsCodeItem(topic_text, i)) i++;
120 					while(IsCodeItem(topic_text, i))
121 						result.Cat(topic_text.Get(i++));
122 					while(i < topic_text.GetPartCount() && !IsCodeItem(topic_text, i)
123 					      && !IsBeginEnd(topic_text, i)) {
124 						if(topic_text.IsPara(i))
125 							result.Cat(topic_text.Get(i++));
126 						else {
127 							RichTable table(topic_text.GetTable(i++), 1);
128 							result.CatPick(pick(table));
129 						}
130 					}
131 					pass = 2;
132 					break;
133 				}
134 			if(pass == 0 && !LegacyRef(cr))
135 				break;
136 		}
137 	done:
138 		result.SetStyles(topic_text.GetStyles());
139 		annotation_popup.Pick(pick(result), GetRichTextStdScreenZoom());
140 	}
141 	else
142 		if(SyncRefsFinished)
143 			annotation_popup.SetQTF("[A1 [@b* " + DeQtf(coderef) + "]&Not documented yet - click to document");
144 		else
145 			annotation_popup.SetQTF("[A1 [@b* " + DeQtf(coderef) + "]&Documentation not loaded yet");
146 	Rect r = GetLineScreenRect(GetActiveAnnotationLine());
147 	int h = annotation_popup.GetHeight(Zx(580));
148 	h = min(h, Zx(550));
149 	int y = r.top - h - DPI(16);
150 	if(y < GetWorkArea().top)
151 		y = r.bottom;
152 	annotation_popup.SetRect(r.left, y, Zx(600), h + DPI(16));
153 	annotation_popup.Ctrl::PopUp(this, false, false, true);
154 }
155 
OpenTopic(String topic,String create,bool before)156 void AssistEditor::OpenTopic(String topic, String create, bool before)
157 {
158 	if(theide)
159 		theide->OpenTopic(topic, create, before);
160 }
161 
NewTopic(String group,String coderef)162 void AssistEditor::NewTopic(String group, String coderef)
163 {
164 	if(!theide)
165 		return;
166 	String ef = theide->editfile;
167 	String n = GetFileTitle(ef);
168 	theide->EditFile(AppendFileName(PackageDirectory(theide->GetActivePackage()), group + ".tpp"));
169 	if(!theide->designer)
170 		return;
171 	TopicEditor *te = dynamic_cast<TopicEditor *>(&theide->designer->DesignerCtrl());
172 	if(!te)
173 		return;
174 	String scope, item;
175 	SplitCodeRef(coderef, scope, item);
176 	if(!te->NewTopicEx(IsNull(scope) ? n : Join(Split(scope, ':'), "_"), coderef))
177 		theide->EditFile(ef);
178 }
179 
EditAnnotation(bool fastedit)180 void AssistEditor::EditAnnotation(bool fastedit)
181 {
182 	if(!SyncRefsFinished)
183 		return;
184 	String coderef;
185 	Vector<String> tl;
186 	if(!GetAnnotationRefs(tl, coderef))
187 		return;
188 	SetCursor(GetPos64(GetActiveAnnotationLine()));
189 	if(tl.GetCount() > 1) {
190 		MenuBar bar;
191 		for(int i = 0; i < tl.GetCount(); i++)
192 			bar.Add(tl[i], THISBACK3(OpenTopic, tl[i] + '#' + coderef, String(), false));
193 		bar.Execute();
194 		return;
195 	}
196 	if(tl.GetCount()) {
197 		OpenTopic(tl[0] + '#' + coderef, String(), false);
198 		return;
199 	}
200 	String scope, item;
201 	SplitCodeRef(coderef, scope, item);
202 	const CppItem *m = GetCodeRefItem(coderef);
203 	int access = m ? m->access : 0;
204 	VectorMap<String, String> tpp;
205 	int backi = 0;
206 	for(int pass = 0; pass < 2; pass++) {
207 		for(int i = GetCursorLine(); pass ? i < GetLineCount() : i >= 0; pass ? i++ : i--) {
208 			String coderef2;
209 			if(GetAnnotationRefs(tl, coderef2, i) && tl.GetCount()) {
210 				String scope2, item2;
211 				SplitCodeRef(coderef2, scope2, item2);
212 				m = GetCodeRefItem(coderef2);
213 				if(scope2 == scope && m && m->access == access && tl.GetCount() == 1 && fastedit) {
214 					OpenTopic(tl[0] + '#' + coderef2, coderef, false);
215 					return;
216 				}
217 				for(int j = 0; j < tl.GetCount(); j++)
218 					if(tpp.Find(tl[j]) < 0)
219 						tpp.Add(tl[j], coderef2);
220 			}
221 		}
222 		if(pass == 0)
223 			backi = tpp.GetCount();
224 	}
225 	MenuBar bar;
226 	if(tpp.GetCount()) {
227 		for(int i = 0; i < tpp.GetCount(); i++) {
228 			String l = tpp.GetKey(i);
229 			bar.Add(l, THISBACK3(OpenTopic, l + '#' + tpp[i], coderef, i >= backi));
230 		}
231 		bar.Separator();
232 	}
233 	bar.Add("New reference topic..", THISBACK2(NewTopic, "src", coderef));
234 	bar.Add("New implementation topic..", THISBACK2(NewTopic, "srcimp", coderef));
235 	bar.Execute();
236 }
237