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 '&lt;' 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 '&gt;' 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 '&amp;' 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 }+/