4 A Programmer's Text Editor
6 Syntax highlight definitions.
8 Copyright (C) 1991-2011 Angel Ortega <angel@triptico.com>
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 http://www.triptico.com
28 /** editor actions **/
30 sub mp.actions.help(d) {
33 /* get the special word regex separator for help (if any) */
34 r = d.syntax.help_word_regex;
36 /* if there is a word at the cursor position,
37 try searching for help */
38 if ((w = mp.get_word(d, r)) != NULL) {
45 mp.alert(sprintf(L("No help for '%s'."), w));
49 hd = mp.open(sprintf(L("<help on '%s'>"), w));
59 sub mp.actions.section_list(d) {
60 local l = mp.section_list(d);
63 mp.alert(L("No detection for sections for this mode."));
66 mp.alert(L("No sections were found in this document."));
70 /* set pos to the section nearest the cursor */
78 if (pos < 0 || pos > size(l))
84 label: L("Section list"),
86 list: map(l, sub (e) { e[0]; }),
93 mp.search_set_y(d, l[r[0]][1]);
100 /** default key bindings **/
102 mp.keycodes['f1'] = "help";
103 mp.keycodes['ctrl-d'] = "section_list";
105 /** action descriptions **/
107 mp.actdesc['help'] = LL("Help on word over cursor");
108 mp.actdesc['section_list'] = LL("Section list...");
114 /** syntax definitions **/
116 sub mp.syn_token_list(l) { '/\b(' ~ join(l, "|") ~ ')\b/'; }
121 'filenames' => [ '/\.c$/i', '/\.h$/i', '/\.l$/i', '/\.y$/i', '/\.d$/i',
122 '/\.cpp$/i', '/\.hpp$/i', '/\.c++$/i', '/\.cxx$/i', '/\.xpm$/i' ],
123 'help' => [ "man 2 %s", "man 3 %s" ],
124 'help_func' => sub (w) { mp.c_gather_help(w); },
128 "auto", "break", "case", "catch", "class", "const", "const_cast",
129 "continue", "default", "delete", "do", "dynamic_cast", "else", "enum",
130 "explicit", "extern", "for", "friend", "goto", "if", "inline", "mutable",
131 "namespace", "new", "operator", "private", "protected", "public",
132 "register", "reinterpret_cast", "restrict", "return", "sizeof", "static",
133 "static_cast", "struct", "switch", "template", "this", "throw", "try",
134 "typedef", "typeid", "typename", "union", "using", "virtual", "volatile",
135 "while", "not", "not_eq", "xor", "xor_eq", "or", "or_eq", "and", "and_eq",
136 "bitor", "bitand", "compl"
141 "bool", "char", "double", "float", "int", "long", "short", "signed",
142 "unsigned", "wchar_t", "size_t", "ssize_t", "off_t", "wchar_t",
143 "ptrdiff_t", "void", "sig_atomic_t", "fpos_t", "clock_t", "time_t",
144 "va_list", "jmp_buf", "FILE", "DIR", "div_t", "ldiv_t", "mbstate_t",
145 "wctrans_t", "wint_t", "wctype_t", "complex", "int8_t", "int16_t",
146 "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t",
147 "int_least8_t", "int_least16_t", "int_least32_t", "int_least64_t",
148 "uint_least8_t", "uint_least16_t", "uint_least32_t", "uint_least64_t",
149 "int_fast8_t", "int_fast16_t", "int_fast32_t", "int_fast64_t",
150 "uint_fast8_t", "uint_fast16_t", "uint_fast32_t", "uint_fast64_t",
151 "intptr_t", "uintptr_t", "intmax_t", "uintmax_t"
153 '/[-=<>:\?\+\*\/\!\%&\|~\^\.]+/'
156 /* from http://ad.hominem.org/log/2005/05/quoted_strings.php */
157 "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/", /* double-quoted strings */
158 "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/", /* single-quoted strings */
159 "/\b-?[0-9]+\b/", /* numbers */
160 "/\b[0-9]+e[0-9]+\b/", /* numbers in exp format */
161 "/\b0[0-7]+\b/", /* octal numbers */
162 "/\b0x[0-9a-f]+\b/i", /* hex numbers */
163 "/\b__(DATE|FILE|LINE|STDC|TIME|STDC_HOSTED|STDC_VERSION|func)__\b/", /* ISO macros */
164 "/\b(true|false|NULL)\b/" /* symbolic constant names */
167 [ '|/\*|', '|\*/|' ], /* C-like */
168 [ '|#if 0|', '#endif' ], /* CPP "comments" */
169 '|//.*$|m', /* C++ */
170 '/^\s*#\s*[a-z]+/m' /* CPP directives */
173 [ "|/\*\*\n|", '|\*/|' ], /* mp_doccer */
174 '/^/\*\*.*\*\*/$/m' /* section mark */
177 'section' => [ '/(^\/\*\*.*\*\*\/$|^#pragma mark|^[A-Za-z_])/' ]
182 'name' => 'Resource file',
183 'filenames' => [ '/\.rc$/i' ],
188 /* from http://ad.hominem.org/log/2005/05/quoted_strings.php */
189 "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/", /* double-quoted strings */
190 "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/", /* single-quoted strings */
191 "/\b-?[0-9]+\b/", /* numbers */
192 "/\b0x[0-9a-f]+\b/i", /* hex numbers */
193 "/\b[0-9[:upper:]_]+\b/" /* all-caps words */
196 [ '|/\*|', '|\*/|' ], /* C-like */
197 '|//.*$|m', /* C++ */
198 '/^\s*#[a-z]+/m' /* CPP directives */
206 'filenames' => [ '/\.pl$/i', '/\.pm$/i' ],
207 'help' => [ 'perldoc -f %s', 'perldoc %s' ],
208 'help_word_regex' => '/[A-Z_][A-Z0-9_:]*/i',
212 "for", "if", "next", "last", "else", "elsif",
213 "unless", "while", "shift", "unshift", "push",
214 "pop", "delete", "new", "bless", "return",
215 "foreach", "keys", "values", "sort", "grep",
216 "tr", "length", "system", "exec", "fork", "map",
217 "print", "write", "open", "close", "chop",
218 "chomp", "exit", "sleep", "split", "join",
219 "sub", "printf", "sprintf", "s", "glob",
220 "scalar", "my", "local", "undef", "defined",
221 "use", "package", "require", "ref", "can", "isa",
222 "qw", "qq", "eq", "ne", "or", "exists",
223 "and", "not", "import", "our", "caller" ]),
227 '/[:\?\+\*\/\!\$@\%&\|~\.]+/',
231 /* from http://ad.hominem.org/log/2005/05/quoted_strings.php */
232 "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/", /* double-quoted strings */
233 "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/", /* single-quoted strings */
234 "/\b-?[0-9]+\b/", /* numbers */
235 "/\b0x[0-9a-f]+\b/i", /* hex numbers */
236 "/\b[0-9[:upper:]_]+\b/", /* all-caps words */
237 [ "/q\(/", "/\)/" ], /* quote */
238 [ "/qw\(/", "/\)/" ], /* quote word */
239 '/\w+\s*=>/', /* barewords as hash keys 1 */
240 '/\{\s*-?\w+\s*\}/', /* barewords as hash keys 2 */
241 [ "/`/", "/`/" ], /* backticks */
242 [ "/<<[\"']?EOF.*$/m", "/^EOF$/m" ] /* 'document here' */
244 /* color all => as word2 */
246 /* color curly brackets as word */
247 'word', [ '/[{}]/' ],
249 "/#.*$/m" /* Comments */
252 "/__END__\n.*$/", /* __END__ */
253 '/^## .*$/m', /* section mark */
254 [ "/^=(head[1-4]|over|item|back|pod|begin|end|for)/m",
255 "/^=cut$/m" ] /* POD */
258 'detect' => sub (d) {
259 /* take the first line */
260 local f = d.txt.lines[0];
262 /* is it a 'she-bang' for Perl? */
263 return regex(f, '/^#!\s*/usr/bin/(env )?perl/');
265 'section' => [ '/(^sub \w+|^package|^## )/' ]
272 'filenames' => [ '/\.mpsl?$/i' ],
276 'if', 'else', 'while', 'foreach',
277 'sub', 'break', 'return', 'eq', 'ne' ]),
278 mp.syn_token_list( keys(MPSL.CORE) ),
283 '/[-=<>\?\+\*\/\!\%&\|]+/'
286 /* from http://ad.hominem.org/log/2005/05/quoted_strings.php */
287 "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/", /* double-quoted strings */
288 "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/", /* single-quoted strings */
289 "/\b-?[0-9]+\b/", /* numbers */
290 "/\b0x[0-9a-f]+\b/i", /* hex numbers */
291 '/\w+\s*:/', /* JS-type hashes */
292 "/\b[0-9[:upper:]_]+\b/" /* all-caps words */
298 [ '|/\*|', '|\*/|' ] /* C-like */
301 [ "|/\*\*\n|", '|\*/|' ], /* mp_doccer */
302 '/^/\*\*.*\*\*/$/m' /* section mark */
305 'detect' => sub (d) {
306 /* take the first line */
307 local f = d.txt.lines[0];
309 return regex(f, '|^#!\s*/usr/bin/(env )?mpsl|');
311 'section' => [ '/(^[A-Za-z_]|^\/\*\*.*\*\*\/$)/' ]
316 'name' => 'Shell script',
317 'filenames' => [ '/\.sh$/i', '/makefile/i' ],
321 "if", "then", "else", "elif",
322 "fi", "case", "do", "done", "esac",
323 "for", "until", "while", "break",
324 "in", "source", "alias", "cd",
325 "continue", "echo", "eval", "exec",
326 "exit", "export", "kill", "logout",
327 "printf", "pwd", "read", "return",
328 "shift", "test", "trap", "ulimit",
329 "umask", "unset", "wait", "cp", "rm" ]),
334 '/\b(local|let|set)\b/',
335 '/[-=<>:\?\+\*\!\%&\|]+/',
338 "/\b[0-9[:upper:]_]+\b/" /* all-caps words */
341 "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/", /* double-quoted strings */
342 "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/", /* single-quoted strings */
343 "/\b-?[0-9]+\b/", /* numbers */
344 "/\b0x[0-9a-f]+\b/i", /* hex numbers */
345 "/\([A-Za-z0-9_]+\)/", /* parens */
346 [ "/`/", "/`/" ], /* backticks */
347 [ "/<<[\"']?EOF[\"']?;$/m", "/^EOF$/m" ] /* 'document here' */
349 'comments', [ "/#.*$/m" ]
351 'detect' => sub (d) {
352 /* take the first line */
353 local f = d.txt.lines[0];
355 /* is it a 'she-bang' for usual shells? */
356 return regex(f, '/^#!\s*/bin/(sh|bash|csh|dash|ksh)/') ||
357 regex(f, '/^#!\s*/usr/bin/make -f/');
359 'section' => [ '/(^\w+\(\))/', '/^[A-Za-z0-9_\.-]+:/' ]
366 'filenames' => [ '/\.html$/i', '/\.htm$/i' ],
371 "a", "abbr", "acronym", "address",
372 "area", "b", "base", "bdo", "big",
373 "blockquote", "body", "br", "button",
374 "caption", "center", "cite", "code", "col",
375 "colgroup", "dd", "del", "dfn", "div",
376 "dl", "dt", "em", "fieldset", "form",
377 "h1", "h2", "h3", "h4", "h5", "h6",
378 "head", "hr", "html", "i", "img",
379 "input", "ins", "kbd", "label", "legend",
380 "li", "link", "map", "meta", "noscript",
381 "object", "ol", "optgroup", "option",
382 "p", "param", "pre", "q", "samp",
383 "script", "select", "small", "span",
384 "strong", "style", "sub", "sup", "table",
385 "tbody", "td", "textarea", "tfoot", "th",
386 "thead", "title", "tr", "tt", "ul",
392 "!DOCTYPE", "class", "type",
393 "cellspacing", "cellpadding",
394 "href", "align", "valign", "name", "lang",
395 "value", "action", "width", "height",
396 "content", "http-equiv", "src", "alt",
397 "bgcolor", "text", "link", "vlink", "alink",
401 "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/", /* double-quoted strings */
402 "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/" /* single-quoted strings */
405 [ '/<!--/', '/-->/' ]
408 'section' => [ '/<\s*h[0-9]\s*>/' ]
414 'name' => 'Config file',
415 'filenames' => [ '/\.conf$/i', '/\.cfg$/i', '/^.*\/?\.[0-9a-z_-]+rc$/i' ],
417 'word1', [ '/^\[.+\]$/m' ],
418 'word2', [ "/^[^:=\n]+[:=]/m" ],
420 "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/", /* double-quoted strings */
421 "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/", /* single-quoted strings */
422 "/\b-?[0-9]+\b/", /* numbers */
423 "/\b0x[0-9a-f]+\b/i" /* hex numbers */
425 'comments', [ "/#.*$/m" ]
433 'filenames' => [ '/\.php[345]?$/i', '/\.inc$/i' ],
437 "and", "array", "as",
438 "bool", "boolean", "break", "case", "class",
439 "const", "continue", "declare", "default",
440 "die", "do", "double", "echo", "else", "elseif",
441 "empty", "enddeclare", "endfor", "endforeach",
442 "endif", "endswitch", "endwhile", "eval",
443 "exit", "extends", "__FILE__", "float", "for",
444 "foreach", "function", "cfunction", "global",
445 "if", "include", "include_once", "int",
446 "integer", "isset", "__LINE__", "list", "new",
447 "object", "old_function", "or", "print", "real",
448 "require", "require_once", "return",
449 "static", "string", "switch", "unset", "use",
450 "var", "while", "xor", 'true', 'false' ]
453 'word2', [ '/\$\w+/', '/[-=<>:\?\+\*\!\%&\|]+/' ],
455 "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/", /* double-quoted strings */
456 "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/", /* single-quoted strings */
457 "/\b-?[0-9]+\b/", /* numbers */
458 "/\b0x[0-9a-f]+\b/i", /* hex numbers */
459 "/\b[0-9[:upper:]_]+\b/", /* all-caps words */
460 [ "/`/", "/`/" ] /* backticks */
463 [ '|/\*|', '|\*/|' ], /* C-like */
472 'filenames' => [ '/\.py$/i' ],
476 "and", "assert", "break", "class", "continue",
477 "def", "del", "elif", "else", "except", "exec",
478 "finally", "for", "from", "if", "import", "in",
479 "is", "lambda", "not", "or", "pass", "print",
480 "raise", "return", "try", "while", "yield"
484 'word2', [ '/global/', '/\$\w+/', '/[-=<>:\?\+\*\!\%&\|{}]+/' ],
486 "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/", /* double-quoted strings */
487 "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/", /* single-quoted strings */
488 "/\b-?[0-9]+\b/", /* numbers */
489 "/\b0x[0-9a-f]+\b/i", /* hex numbers */
490 "/\b[0-9[:upper:]_]+\b/", /* all-caps words */
491 [ "/`/", "/`/" ] /* backticks */
493 'comments', [ "/#.*$/m" ],
494 'documentation', [ [ '/""".+[^"]$/m', '/"""$/m' ] ]
496 'detect' => sub (d) {
497 /* take the first line */
498 local f = d.txt.lines[0];
500 /* is it a 'she-bang'? */
501 return regex(f, '/^#!\s*/usr/bin/(env )?python/');
503 'section' => [ '/^[ \t]*def/' ]
509 'filenames' => [ '/\.rb$/i' ],
513 "BEGIN", "END", "alias", "and", "begin",
514 "break", "case", "class", "def", "defined",
515 "do", "else", "elsif", "end", "ensure",
516 "false", "for", "if", "in", "module", "next",
517 "nil", "not", "or", "redo", "rescue", "retry",
518 "return", "self", "super", "then", "true",
519 "undef", "unless", "until", "when", "while",
520 "yield", "require", "include" ]
523 'word2', [ '/[-=<>:\?\+\*\!\%&\|{}]+/', '/=(begin|end)/' ],
525 "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/", /* double-quoted strings */
526 "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/", /* single-quoted strings */
527 "/\b-?[0-9]+\b/", /* numbers */
528 "/\b0x[0-9a-f]+\b/i", /* hex numbers */
529 "/\b[0-9[:upper:]_]+\b/", /* all-caps words */
530 [ "/`/", "/`/" ] /* backticks */
532 'comments', [ "/#.*$/m" ]
534 'detect' => sub (d) {
535 /* take the first line */
536 local f = d.txt.lines[0];
538 /* is it a 'she-bang'? */
539 return regex(f, '/^#!\s*/usr/bin/(env )?ruby/');
551 'word1', [ '/^\+.+$/m' ],
552 'word2', [ '/^\-.+$/m' ],
553 'quotes', [ '/^@@.+@@.*$/m' ]
555 section: [ '/^--- ', '/^@@/' ],
561 if (regex(d.txt.lines[n++], '/^--- /'))
565 if (regex(d.txt.lines[n++], '/^\+\+\+ /') &&
566 regex(d.txt.lines[n++], '/^@@ /'))
573 mp.syntax.commit_msg = {
574 'id' => 'commit_msg',
575 'name' => 'VCS commit message',
576 'filenames' => [ '/sv[kn]-commit.*\./' ],
578 'word1', [ '/^AM? .+$/m' ],
579 'word2', [ '/^D .+$/m' ],
580 'quotes', [ '/^M .+$/m' ],
581 'comments', [ '/^=== .+$/m', '/^--.+$/m' ]
587 'name' => 'Gettext file',
588 'filenames' => [ '/\.po$/i' ],
590 'word1', [ '/^msgid/m' ],
591 'word2', [ '/^msgstr/m' ],
592 'comments', [ "/#.*$/m" ],
594 "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/" /* double-quoted strings */
601 'name' => 'XML / XGML',
602 'filenames' => [ '/\.xml$/i', '/\.sgml$/i' ],
604 'word1', [ '/<[^>]+>/' ],
605 'word2', [ '/<\?[^\?]+\?>/' ],
607 "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/", /* double-quoted strings */
608 "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/" /* single-quoted strings */
611 [ '/<!--/', '/-->/' ]
614 'detect' => sub (d) {
615 /* take the first line */
616 local f = d.txt.lines[0];
618 return regex(f, '/<\?xml/');
622 mp.syntax.make_output = {
623 'id' => 'make_output',
624 'name' => 'Make output',
626 'word1', [ "/^.*warning:.*$/m" ],
627 'word2', [ "/^.*error:.*$/m" ]
631 mp.syntax.euphoria = {
633 'name' => 'euphoria',
634 'filenames' => [ '/\.e$/', '/\.eu$/', '/\.ew$/', '/\.ed$/',
635 '/\.ex$/', '/\.exw$/', '/\.exu$/' ],
639 "as", "and", "break", "by", "case", "constant", "continue", "do", "end",
640 "else", "elsif", "elsifdef",
641 "exit", "entry", "enum", "export", "for", "function", "global", "include",
642 "if", "ifdef", "label",
643 "not", "or", "procedure", "return", "retry", "switch", "then", "type",
644 "to", "while", "with", "without", "xor"
649 "atom", "integer", "sequence", "object"
653 "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/", /* double-quoted strings */
654 "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/", /* single-quoted strings */
655 "/\b-?#[0-9A-F]+\b/", /* hex numbers */
656 "/\b-?[0-9]+\b/", /* numbers */
657 "/\b[0-9[:upper:]_]+\b/" /* all-caps words */
659 'comments', [ "/--.*$/m" ]
661 'section' => [ '/^[ \t]*(global|export)*[ \t]*(function|procedure)/' ]
665 mp.syntax.mp_templates = {
666 'id' => 'mp_templates',
667 'name' => 'Minimum Profit template file',
668 'filenames' => [ '/\.mp_templates$/' ],
670 'documentation', [ '/^%%.*$/m' ]
672 'section' => [ '/^%%/' ]
676 mp.syntax.hex_view = {
678 'name' => 'Hexadecimal view',
680 'word1', [ "/^\| [0-9A-F]+ \|/m" ],
686 mp.syntax.grutatxt = {
688 'name' => 'Grutatxt',
690 'word1', [ "/[^\n]+\n[-=~]+\n/", "/ \* [^.\n:]+:/" ],
691 'comments', [ "/\b_[^ \t\n][^_\n]*[^ \t\n]_\b/" ],
692 'word2', [ "/\*[^ \t\n][^\*\n]*[^ \t\n]\*/" ],
693 'quotes', [ "/`[^ \t\n][^'\n]*[^ \t\n]'/" ]
695 'section' => [ "/^[-=~]+$/" ],
696 'detect' => sub (d) {
699 /* search the first lines for a heading */
701 local l = d.txt.lines[n++];
706 if (regex(l, "/^[-=~]+$/"))
717 sub mp.detect_syntax(doc)
718 /* tries to detect the syntax of a document */
722 /* loops the syntax highlight definitions */
723 foreach (n, keys(mp.syntax)) {
724 local s = mp.syntax[n];
726 /* test the extensions */
727 foreach (ext, s.filenames) {
728 if (regex(doc.name, ext)) {
735 /* not by extension? try the 'detect' subroutine */
736 foreach (n, keys(mp.syntax)) {
737 local s = mp.syntax[n];
739 if (is_exec(s.detect) && s.detect(doc)) {
747 sub mp.help(doc, word)
751 foreach (c, doc.syntax.help) {
754 /* format the command */
755 c = sprintf(c, word);
758 if ((f = popen(c, "r")) != NULL) {
762 while ((l = read(f)) != NULL) {
763 l = sregex(l, "/\b./g");
764 push(h, mp.chomp(l));
772 /* is there already help? don't look for more */
777 if (h == NULL && doc.syntax.help_func)
778 h = doc.syntax.help_func(word);
785 * mp.section_list - Returns the list of sections of a document.
788 * Applies the `section' array of regular expressions of the
789 * document's syntax definition and returns it as an array of
790 * line and line number pairs.
792 * If the document has no syntax highlight definition, or it has
793 * one without a `section' definition, NULL is returned. Otherwise,
794 * an array of line, line number pairs is returned (it can be
795 * an empty list if the document has no recognizable sections).
797 sub mp.section_list(doc)
801 if (doc.syntax.section) {
806 while ((l = doc.txt.lines[n]) != NULL) {
807 foreach (ex, doc.syntax.section) {
823 * mp.c_gather_help - Gathers help in C-style files
824 * @word: the help term
826 * Searches in all applicable files for code snippets that may
827 * conform help for @word (mp_doccer style help, struct or
828 * function definitions, etc).
830 * Returns an array of text with the gathered information.
832 sub mp.c_gather_help(word)
836 foreach (fn, glob()) {
840 /* test if this file is relevant to C */
841 foreach (ext, mp.syntax.c.filenames) {
842 if (regex(fn, ext)) {
848 if (ok && (f = open(fn, "r")) != NULL) {
852 while ((l = read(f)) != NULL) {
854 local where = fn ~ ':' ~ n ~ ':';
858 if (regex(l, "/^[ \t]*#define[ \t]+" ~ word ~ "/")) {
859 /* it's a CPP define */
863 if (regex(l, "/^[A-Za-z_]+.*[ \t]+" ~ word ~ "[ \t]*\(.*/")) {
864 /* it's a function definition or prototype */
868 if (regex(l, "/^(typedef[ \]*|static[ \]*)?struct[ \t]+.*" ~ word ~ ".*\{/")) {
869 /* it's a structure definition */
872 /* add up to the end of the struct */
873 while ((l = read(f)) != NULL) {
877 if (regex(l, "/^\};/"))
882 if (regex(l, "/^\/\*\*$/")) {
883 /* mp_doccer help: is it for this word? */
887 if (regex(l, "/ \* " ~ word ~ " - /")) {
888 /* it is; dump up to a ; */
889 push(h, where, '/' ~ '**', l);
891 while ((l = read(f)) != NULL) {
893 if (regex(l, "/^\{/"))
907 ins(h, sprintf(L("Gathered information on %s:"), word), 0);