Mercurial > projects > ddmd
comparison dmd/ddoc/Util.d @ 153:560eaedcb7a2
added lots of ddoc code, still needs much care
added helpers functions in ddoc.Util
author | trass3r |
---|---|
date | Wed, 15 Sep 2010 04:18:46 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
152:4092a614a9f3 | 153:560eaedcb7a2 |
---|---|
1 module dmd.ddoc.Util; | |
2 | |
3 public import std.string : cmp, icmp; | |
4 | |
5 /***************************************** | |
6 * Return !=0 if comment consists entirely of "ditto". | |
7 */ | |
8 bool isDitto(string comment) | |
9 { | |
10 if (comment) | |
11 { | |
12 string p = skipwhitespace(comment); | |
13 | |
14 if (icmp(p, "ditto") == 0 && skipwhitespace(p[5..$])[0] == 0) | |
15 return true; | |
16 } | |
17 return false; | |
18 } | |
19 | |
20 /********************************************** | |
21 * Skip white space. | |
22 */ | |
23 string skipwhitespace(string p) | |
24 { | |
25 size_t i = 0; | |
26 | |
27 for (; true; i++) | |
28 { switch (p[i]) | |
29 { | |
30 case ' ': | |
31 case '\t': | |
32 case '\n': | |
33 continue; | |
34 default: | |
35 } | |
36 break; | |
37 } | |
38 return p[i .. $]; | |
39 } | |
40 | |
41 /+ | |
42 /************************************************ | |
43 * Scan forward to one of: | |
44 * start of identifier | |
45 * beginning of next line | |
46 * end of buf | |
47 */ | |
48 unsigned skiptoident(OutBuffer buf, size_t i) | |
49 { | |
50 while (i < buf.offset) | |
51 { dchar_t c; | |
52 | |
53 size_t oi = i; | |
54 if (utf_decodeChar((unsigned char *)buf.data, buf.offset, &i, &c)) | |
55 /* Ignore UTF errors, but still consume input | |
56 */ | |
57 break; | |
58 if (c >= 0x80) | |
59 { | |
60 if (!isUniAlpha(c)) | |
61 continue; | |
62 } | |
63 else if (!(isalpha(c) || c == '_' || c == '\n')) | |
64 continue; | |
65 i = oi; | |
66 break; | |
67 } | |
68 return i; | |
69 } | |
70 | |
71 /************************************************ | |
72 * Scan forward past end of identifier. | |
73 */ | |
74 | |
75 unsigned skippastident(OutBuffer buf, size_t i) | |
76 { | |
77 while (i < buf.offset) | |
78 { dchar_t c; | |
79 | |
80 size_t oi = i; | |
81 if (utf_decodeChar((unsigned char *)buf.data, buf.offset, &i, &c)) | |
82 /* Ignore UTF errors, but still consume input | |
83 */ | |
84 break; | |
85 if (c >= 0x80) | |
86 { | |
87 if (isUniAlpha(c)) | |
88 continue; | |
89 } | |
90 else if (isalnum(c) || c == '_') | |
91 continue; | |
92 i = oi; | |
93 break; | |
94 } | |
95 return i; | |
96 } | |
97 | |
98 | |
99 /************************************************ | |
100 * Scan forward past URL starting at i. | |
101 * We don't want to highlight parts of a URL. | |
102 * Returns: | |
103 * i if not a URL | |
104 * index just past it if it is a URL | |
105 */ | |
106 | |
107 unsigned skippastURL(OutBuffer buf, size_t i) | |
108 { unsigned length = buf.offset - i; | |
109 unsigned char *p = &buf.data[i]; | |
110 unsigned j; | |
111 unsigned sawdot = 0; | |
112 | |
113 if (length > 7 && memicmp((char *)p, "http://", 7) == 0) | |
114 { | |
115 j = 7; | |
116 } | |
117 else if (length > 8 && memicmp((char *)p, "https://", 8) == 0) | |
118 { | |
119 j = 8; | |
120 } | |
121 else | |
122 goto Lno; | |
123 | |
124 for (; j < length; j++) | |
125 { unsigned char c = p[j]; | |
126 if (isalnum(c)) | |
127 continue; | |
128 if (c == '-' || c == '_' || c == '?' || | |
129 c == '=' || c == '%' || c == '&' || | |
130 c == '/' || c == '+' || c == '#' || | |
131 c == '~') | |
132 continue; | |
133 if (c == '.') | |
134 { | |
135 sawdot = 1; | |
136 continue; | |
137 } | |
138 break; | |
139 } | |
140 if (sawdot) | |
141 return i + j; | |
142 | |
143 Lno: | |
144 return i; | |
145 } | |
146 | |
147 | |
148 /**************************************************** | |
149 */ | |
150 bool isKeyword(string p) | |
151 { | |
152 static string[] table = [ "true", "false", "null" ]; | |
153 | |
154 for (int i = 0; i < table.length; i++) | |
155 { | |
156 if (table[i][0 .. p.length] == p) | |
157 return true; | |
158 } | |
159 return false; | |
160 } | |
161 | |
162 /**************************************************** | |
163 */ | |
164 Parameter isFunctionParameter(Dsymbol s, string p) | |
165 { | |
166 FuncDeclaration f = s.isFuncDeclaration(); | |
167 | |
168 /* f.type may be NULL for template members. | |
169 */ | |
170 if (f && f.type) | |
171 { | |
172 TypeFunction *tf; | |
173 if (f.originalType) | |
174 { | |
175 tf = (TypeFunction *)f.originalType; | |
176 } | |
177 else | |
178 tf = (TypeFunction *)f.type; | |
179 | |
180 if (tf.parameters) | |
181 { | |
182 for (size_t k = 0; k < tf.parameters.dim; k++) | |
183 { Parameter *arg = (Parameter *)tf.parameters.data[k]; | |
184 | |
185 if (arg.ident && cmp(arg.ident.toChars(), p, len) == 0) | |
186 { | |
187 return arg; | |
188 } | |
189 } | |
190 } | |
191 } | |
192 return NULL; | |
193 } | |
194 +/ | |
195 /+ | |
196 /************************************************** | |
197 * Highlight text section. | |
198 */ | |
199 void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) | |
200 { | |
201 //printf("highlightText()\n"); | |
202 const char *sid = s.ident.toChars(); | |
203 FuncDeclaration *f = s.isFuncDeclaration(); | |
204 unsigned char *p; | |
205 const char *se; | |
206 | |
207 int leadingBlank = 1; | |
208 int inCode = 0; | |
209 int inComment = 0; // in <!-- ... -. comment | |
210 unsigned iCodeStart; // start of code section | |
211 | |
212 unsigned iLineStart = offset; | |
213 | |
214 for (unsigned i = offset; i < buf.offset; i++) | |
215 { unsigned char c = buf.data[i]; | |
216 | |
217 Lcont: | |
218 switch (c) | |
219 { | |
220 case ' ': | |
221 case '\t': | |
222 break; | |
223 | |
224 case '\n': | |
225 if (sc && !inCode && i == iLineStart && i + 1 < buf.offset) // if "\n\n" | |
226 { | |
227 static char blankline[] = "$(DDOC_BLANKLINE)\n"; | |
228 | |
229 i = buf.insert(i, blankline, sizeof(blankline) - 1); | |
230 } | |
231 leadingBlank = 1; | |
232 iLineStart = i + 1; | |
233 break; | |
234 | |
235 case '<': | |
236 leadingBlank = 0; | |
237 if (inCode) | |
238 break; | |
239 p = &buf.data[i]; | |
240 | |
241 // Skip over comments | |
242 if (p[1] == '!' && p[2] == '-' && p[3] == '-') | |
243 { unsigned j = i + 4; | |
244 p += 4; | |
245 while (1) | |
246 { | |
247 if (j == buf.offset) | |
248 goto L1; | |
249 if (p[0] == '-' && p[1] == '-' && p[2] == '>') | |
250 { | |
251 i = j + 2; // place on closing '>' | |
252 break; | |
253 } | |
254 j++; | |
255 p++; | |
256 } | |
257 break; | |
258 } | |
259 | |
260 // Skip over HTML tag | |
261 if (isalpha(p[1]) || (p[1] == '/' && isalpha(p[2]))) | |
262 { unsigned j = i + 2; | |
263 p += 2; | |
264 while (1) | |
265 { | |
266 if (j == buf.offset) | |
267 goto L1; | |
268 if (p[0] == '>') | |
269 { | |
270 i = j; // place on closing '>' | |
271 break; | |
272 } | |
273 j++; | |
274 p++; | |
275 } | |
276 break; | |
277 } | |
278 | |
279 L1: | |
280 // Replace '<' with '<' character entity | |
281 se = Escape::escapeChar('<'); | |
282 if (se) | |
283 { size_t len = strlen(se); | |
284 buf.remove(i, 1); | |
285 i = buf.insert(i, se, len); | |
286 i--; // point to ';' | |
287 } | |
288 break; | |
289 | |
290 case '>': | |
291 leadingBlank = 0; | |
292 if (inCode) | |
293 break; | |
294 // Replace '>' with '>' character entity | |
295 se = Escape::escapeChar('>'); | |
296 if (se) | |
297 { size_t len = strlen(se); | |
298 buf.remove(i, 1); | |
299 i = buf.insert(i, se, len); | |
300 i--; // point to ';' | |
301 } | |
302 break; | |
303 | |
304 case '&': | |
305 leadingBlank = 0; | |
306 if (inCode) | |
307 break; | |
308 p = &buf.data[i]; | |
309 if (p[1] == '#' || isalpha(p[1])) | |
310 break; // already a character entity | |
311 // Replace '&' with '&' character entity | |
312 se = Escape::escapeChar('&'); | |
313 if (se) | |
314 { size_t len = strlen(se); | |
315 buf.remove(i, 1); | |
316 i = buf.insert(i, se, len); | |
317 i--; // point to ';' | |
318 } | |
319 break; | |
320 | |
321 case '-': | |
322 /* A line beginning with --- delimits a code section. | |
323 * inCode tells us if it is start or end of a code section. | |
324 */ | |
325 if (leadingBlank) | |
326 { int istart = i; | |
327 int eollen = 0; | |
328 | |
329 leadingBlank = 0; | |
330 while (1) | |
331 { | |
332 ++i; | |
333 if (i >= buf.offset) | |
334 break; | |
335 c = buf.data[i]; | |
336 if (c == '\n') | |
337 { eollen = 1; | |
338 break; | |
339 } | |
340 if (c == '\r') | |
341 { | |
342 eollen = 1; | |
343 if (i + 1 >= buf.offset) | |
344 break; | |
345 if (buf.data[i + 1] == '\n') | |
346 { eollen = 2; | |
347 break; | |
348 } | |
349 } | |
350 // BUG: handle UTF PS and LS too | |
351 if (c != '-') | |
352 goto Lcont; | |
353 } | |
354 if (i - istart < 3) | |
355 goto Lcont; | |
356 | |
357 // We have the start/end of a code section | |
358 | |
359 // Remove the entire --- line, including blanks and \n | |
360 buf.remove(iLineStart, i - iLineStart + eollen); | |
361 i = iLineStart; | |
362 | |
363 if (inCode && (i <= iCodeStart)) | |
364 { // Empty code section, just remove it completely. | |
365 inCode = 0; | |
366 break; | |
367 } | |
368 | |
369 if (inCode) | |
370 { | |
371 inCode = 0; | |
372 // The code section is from iCodeStart to i | |
373 OutBuffer codebuf; | |
374 | |
375 codebuf.write(buf.data + iCodeStart, i - iCodeStart); | |
376 codebuf.writeByte(0); | |
377 highlightCode2(sc, s, &codebuf, 0); | |
378 buf.remove(iCodeStart, i - iCodeStart); | |
379 i = buf.insert(iCodeStart, codebuf.data, codebuf.offset); | |
380 i = buf.insert(i, ")\n", 2); | |
381 i--; | |
382 } | |
383 else | |
384 { static char pre[] = "$(D_CODE \n"; | |
385 | |
386 inCode = 1; | |
387 i = buf.insert(i, pre, sizeof(pre) - 1); | |
388 iCodeStart = i; | |
389 i--; // place i on > | |
390 leadingBlank = true; | |
391 } | |
392 } | |
393 break; | |
394 | |
395 default: | |
396 leadingBlank = 0; | |
397 if (sc && !inCode && isIdStart(&buf.data[i])) | |
398 { unsigned j; | |
399 | |
400 j = skippastident(buf, i); | |
401 if (j > i) | |
402 { | |
403 unsigned k = skippastURL(buf, i); | |
404 if (k > i) | |
405 { i = k - 1; | |
406 break; | |
407 } | |
408 | |
409 if (buf.data[i] == '_') // leading '_' means no highlight | |
410 { | |
411 buf.remove(i, 1); | |
412 i = j - 1; | |
413 } | |
414 else | |
415 { | |
416 if (cmp(sid, buf.data + i, j - i) == 0) | |
417 { | |
418 i = buf.bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; | |
419 break; | |
420 } | |
421 else if (isKeyword(buf.data + i, j - i)) | |
422 { | |
423 i = buf.bracket(i, "$(DDOC_KEYWORD ", j, ")") - 1; | |
424 break; | |
425 } | |
426 else | |
427 { | |
428 if (f && isFunctionParameter(f, buf.data + i, j - i)) | |
429 { | |
430 //printf("highlighting arg '%s', i = %d, j = %d\n", arg.ident.toChars(), i, j); | |
431 i = buf.bracket(i, "$(DDOC_PARAM ", j, ")") - 1; | |
432 break; | |
433 } | |
434 } | |
435 i = j - 1; | |
436 } | |
437 } | |
438 } | |
439 break; | |
440 } | |
441 } | |
442 Ldone: | |
443 if (inCode) | |
444 s.error("unmatched --- in DDoc comment"); | |
445 ; | |
446 }+/ |