Added section marks as special documentation color in mpsl.
[mp-5.x.git] / mp_syntax.mpsl
blobe14c313198b9431789f2729a09741acbcdebd639
1 /*
3     Minimum Profit 5.x
4     A Programmer's Text Editor
6     Syntax highlight definitions.
8     Copyright (C) 1991-2007 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 mp.actions['help']      =       sub (d) {
31         local w, h, r;
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)
39                 h = mp.help(d, w);
41         if (h == NULL)
42                 mp.alert(sprintf(L("No help for '%s'."), w));
43         else {
44                 local d;
46                 d = mp.new(sprintf(L("<help on '%s'>"), w), h);
47                 d.read_only = 1;
48         }
51 mp.actions['section_list'] = sub (d) {
52         local l = mp.section_list(d);
54         if (l == NULL)
55                 mp.alert(L("No detection for sections for this mode."));
56         else {
57                 if (size(l) == 0)
58                         mp.alert(L("No sections were found in this document."));
59                 else {
60                         local r = mp.form( [
61                         {
62                                 'label' => L("Section list"),
63                                 'type'  => 'list',
64                                 'list'  => map(sub (e) { e[0]; }, l),
65                                 'value' => 0
66                         }
67                         ]);
69                         if (r != NULL) {
70                                 mp.set_y(d, l[r[0]][1]);
71                                 mp.set_x(d, 0);
72                         }
73                 }
74         }
77 /** default key bindings **/
79 mp.keycodes['f1']       =       "help";
80 mp.keycodes['ctrl-d']   =       "section_list";
82 /** action descriptions **/
84 mp.actdesc['help']              = LL("Help on word over cursor");
85 mp.actdesc['section_list']      = LL("Section list...");
87 /* data */
89 mp.syntax = {};
91 /** syntax definitions **/
93 sub mp.syn_token_list(l) { '/\b(' ~ join("|", l) ~ ')\b/'; }
95 mp.syntax.c = {
96         'id'            =>      'c',
97         'name'          =>      'C / C++',
98         'filenames'     =>      [ '/\.c$/', '/\.h$/', '/\.l$/', '/\.y$/', '/\.d$/',
99                                 '/\.cpp$/', '/\.hpp$/', '/\.c++$/', '/\.xpm$/' ],
100         'help'          =>      [ "man 2 %s", "man 3 %s" ],
101         'defs'          =>      [
102                 'word1',        [
103                                 mp.syn_token_list( [
104                                 "for", "while", "if", "switch", "case", "do",
105                                 "else", "break", "continue", "return",
106                                 "default", "goto", "main", "fopen", "fclose",
107                                 "fgets", "fgetc", "fputs", "fputc", "fprintf",
108                                 "putc", "printf", "sprintf", "strcpy", "strcat",
109                                 "strcmp", "strncmp", "strtok", "stricmp", "strchr",
110                                 "strrchr", "strlen", "memcmp", "memcpy", "malloc",
111                                 "free", "strncpy", "strncat", "snprintf", "strstr",
112                                 "memset", "memcpy", "va_start", "va_end", "vsprintf",
113                                 "vsnprintf", "atoi", "qsort", "bsearch", "getenv",
114                                 "fscanf", "popen", "pclose", "realloc", "fread",
115                                 "fwrite", "fseek", '\{', '\}', "putchar", "fflush",
116                                 "wcscmp", "swprintf", "wmemcpy", "swscanf", "sscanf",
117                                 "wcslen", "wmemset", "wcscpy", "wcsncpy", "wcscoll",
118                                 "mbstowcs", "wcstombs", "wprintf", "wcschr",
119                                 "wcsrchr", "wcsstr", "strdup", "wctomb", "mbtowc",
120                                 "mbrtowc", "wcrtomb", "open", "close", "read",
121                                 "write", "pipe", "fork", "dup", "dup2", "wait",
122                                 "execl", "execlp", "execle", "execv", "execvp"
123                                 ])
124                 ],
125                 'word2',        [
126                                 mp.syn_token_list( [
127                                 "char", "int", "long", "struct", "union", "const",
128                                 "void", "unsigned", "signed", "auto", "volatile",
129                                 "enum", "typedef", "float", "double", "extern",
130                                 "register", "short", "sizeof", "static", "far",
131                                 "near", "defined", "va_list", "size_t", "wchar_t",
132                                 "iconv_t" ]),
133                                 '/[-=<>:\?\+\*\/\!\%&\|]+/'
134                 ],
135                 'quotes',       [
136                         /* from http://ad.hominem.org/log/2005/05/quoted_strings.php */
137                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
138                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
139                         "/\b-?[0-9]+\b/",                       /* numbers */
140                         "/\b0x[0-9a-f]+\b/i",                   /* hex numbers */
141                         "/\b[0-9[:upper:]_]+\b/"                /* all-caps words */
142                 ],
143                 'comments',     [
144                         [ '|/\*|', '|\*/|' ],                   /* C-like */
145                         '|//.*$|m',                             /* C++ */
146                         '/^\s*#[a-z]+/m'                        /* CPP directives */
147                 ],
148                 'documentation',        [
149                         [ "|/\*\*\n|", '|\*/|' ],               /* mp_doccer */
150                         '/^/\*\*.*\*\*/$/m'                     /* section mark */
151                 ]
152         ],
153         'section'       =>      '/(^\/\*\*.*\*\*\/$|^#pragma mark)/'
156 mp.syntax.rc = {
157         'id'            =>      'rc',
158         'name'          =>      'Resource file',
159         'filenames'     =>      [ '/\.rc$/' ],
160         'defs'          =>      [
161                 'word1',        [ ],
162                 'word2',        [ ],
163                 'quotes',       [
164                         /* from http://ad.hominem.org/log/2005/05/quoted_strings.php */
165                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
166                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
167                         "/\b-?[0-9]+\b/",                       /* numbers */
168                         "/\b0x[0-9a-f]+\b/i",                   /* hex numbers */
169                         "/\b[0-9[:upper:]_]+\b/"                /* all-caps words */
170                 ],
171                 'comments',     [
172                         [ '|/\*|', '|\*/|' ],                   /* C-like */
173                         '|//.*$|m',                             /* C++ */
174                         '/^\s*#[a-z]+/m'                        /* CPP directives */
175                 ]
176         ]
179 mp.syntax.perl = {
180         'id'            =>      'perl',
181         'name'          =>      'Perl',
182         'filenames'     =>      [ '/\.pl$/i', '/\.pm$/' ],
183         'help'          =>      [ 'perldoc -f %s', 'perldoc %s' ],
184         'help_word_regex' =>    '/[A-Z_][A-Z0-9_:]*/i',
185         'defs'  =>      [
186                 'word1',        [
187                                 mp.syn_token_list( [
188                                 "for", "if", "next", "last", "else", "elsif",
189                                 "unless", "while", "shift", "unshift", "push",
190                                 "pop", "delete", "new", "bless", "return",
191                                 "foreach", "keys", "values", "sort", "grep",
192                                 "tr", "length", "system", "exec", "fork", "map",
193                                 "print", "write", "open", "close", "chop",
194                                 "chomp", "exit", "sleep", "split", "join",
195                                 "sub", "printf", "sprintf", "s", "glob",
196                                 "scalar", "my", "local", "undef", "defined",
197                                 "use", "package", "require", "ref", "can", "isa",
198                                 "qw", "qq", "eq", "ne", "or", "exists",
199                                 "and", "not", "import", "our", "caller" ]),
200                                 '/->/'
201                 ],
202                 'word2',        [
203                                 '/[:\?\+\*\/\!\$@\%&\|~\.]+/',
204                                 '/[\$@%]\w+/'
205                 ],
206                 'quotes',       [
207                         /* from http://ad.hominem.org/log/2005/05/quoted_strings.php */
208                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
209                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
210                         "/\b-?[0-9]+\b/",                       /* numbers */
211                         "/\b0x[0-9a-f]+\b/i",                   /* hex numbers */
212                         "/\b[0-9[:upper:]_]+\b/",               /* all-caps words */
213                         [ "/q\(/", "/\)/" ],                    /* quote */
214                         [ "/qw\(/", "/\)/" ],                   /* quote word */
215                         '/\w+\s*=>/',                           /* barewords as hash keys 1 */
216                         '/\{\s*-?\w+\s*\}/',                    /* barewords as hash keys 2 */
217                         [ "/`/", "/`/" ],                       /* backticks */
218                         [ "/<<[\"']?EOF.*$/m", "/^EOF$/m" ]     /* 'document here' */
219                 ],
220                 /* color all => as word2 */
221                 'word2',        [ '/=>/' ],
222                 /* color curly brackets as word */
223                 'word',         [ '/[{}]/' ],
224                 'comments',     [
225                         "/#.*$/m"                               /* Comments */
226                 ],
227                 'documentation',        [
228                         "/__END__\n.*$/",                       /* __END__ */
229                         '/^## .*$/m',                           /* section mark */
230                         [ "/^=(head[1-4]|over|item|back|pod|begin|end|for)/m",
231                                 "/^=cut$/m" ]                   /* POD */
232                 ]       
233         ],
234         'detect'        =>      sub (d) {
235                 /* take the first line */
236                 local f = d.txt.lines[0];
238                 /* is it a 'she-bang' for Perl? */
239                 return regex('/^#!\s*/usr/bin/(env )?perl/', f);
240         },
241         'section'       =>      '/(^sub \w+|^package|^## )/'
245 mp.syntax.mpsl = {
246         'id'            =>      'mpsl',
247         'name'          =>      'MPSL',
248         'filenames'     =>      [ '/\.mpsl$/' ],
249         'defs'          =>      [
250                 'word1',        [
251                                 mp.syn_token_list( [
252                                         'if', 'else', 'while', 'foreach',
253                                         'sub', 'break', 'return', 'eq', 'ne' ]),
254                                 mp.syn_token_list( keys(MPSL.CORE) ),
255                                 '/[\{\}]/'
256                 ],
257                 'word2',        [
258                                 "/(NULL|local)/",
259                                 '/[-=<>:\?\+\*\/\!\%&\|]+/'
260                 ],
261                 'quotes',       [
262                         /* from http://ad.hominem.org/log/2005/05/quoted_strings.php */
263                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
264                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
265                         "/\b-?[0-9]+\b/",                       /* numbers */
266                         "/\b0x[0-9a-f]+\b/i",                   /* hex numbers */
267                         "/\b[0-9[:upper:]_]+\b/"                /* all-caps words */
268                 ],
269                 'comments',     [
270                         [ '|/\*|', '|\*/|' ]                    /* C-like */
271                 ],
272                 'documentation',        [
273                         [ "|/\*\*\n|", '|\*/|' ],               /* mp_doccer */
274                         '/^/\*\*.*\*\*/$/m'                     /* section mark */
275                 ]
276         ],
277         'section'       =>      '/(^sub \w+|^\/\*\*.*\*\*\/$)/'
280 mp.syntax.sh = {
281         'id'            =>      'sh',
282         'name'          =>      'Shell script',
283         'filenames'     =>      [ '/\.sh$/', '/makefile/i' ],
284         'defs'          =>      [
285                 'word1',        [
286                                 mp.syn_token_list( [
287                                 "if", "then", "else", "elif",
288                                 "fi", "case", "do", "done", "esac",
289                                 "for", "until", "while", "break",
290                                 "in", "source", "alias", "cd",
291                                 "continue", "echo", "eval", "exec",
292                                 "exit", "export", "kill", "logout",
293                                 "printf", "pwd", "read", "return",
294                                 "shift", "test", "trap", "ulimit",
295                                 "umask", "unset", "wait", "cp", "rm" ]),
296                                 '/[\{\}]/'
298                 ],
299                 'word2',        [
300                                 '/\b(local|let|set)\b/',
301                                 '/[-=<>:\?\+\*\!\%&\|]+/',
302                                 '/\$\w+/',
303                                 '/\$\{\w+\}/',
304                                 "/\b[0-9[:upper:]_]+\b/"        /* all-caps words */
305                 ],
306                 'quotes',       [
307                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
308                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
309                         "/\b-?[0-9]+\b/",                       /* numbers */
310                         "/\b0x[0-9a-f]+\b/i",                   /* hex numbers */
311                         "/\([A-Za-z0-9_]+\)/",                  /* parens */
312                         [ "/`/", "/`/" ],                       /* backticks */
313                         [ "/<<[\"']?EOF[\"']?;$/m", "/^EOF$/m" ]        /* 'document here' */
314                 ],
315                 'comments',     [ "/#.*$/m" ]
316         ],
317         'detect'        =>      sub (d) {
318                 /* take the first line */
319                 local f = d.txt.lines[0];
321                 /* is it a 'she-bang' for usual shells? */
322                 return regex('/^#!\s*/bin/(sh|bash|csh|dash|ksh)/', f) ||
323                        regex('/^#!\s*/usr/bin/make -f/', f);
324         },
325         'section'       =>      '/(^\w+\(\))/'
329 mp.syntax.html = {
330         'id'            =>      'html',
331         'name'          =>      'HTML',
332         'filenames'     =>      [ '/\.html$/', '/\.htm$/' ],
333         'defs'          =>      [
334                 'word1',        [
335                                 "/<[\/]?[ \t]*(" ~
336                                 join("|", [
337                                 "a", "abbr", "acronym", "address",
338                                 "area", "b", "base", "bdo", "big",
339                                 "blockquote", "body", "br", "button",
340                                 "caption", "center", "cite", "code", "col",
341                                 "colgroup", "dd", "del", "dfn", "div",
342                                 "dl", "dt", "em", "fieldset", "form",
343                                 "h1", "h2", "h3", "h4", "h5", "h6",
344                                 "head", "hr", "html", "i", "img",
345                                 "input", "ins", "kbd", "label", "legend",
346                                 "li", "link", "map", "meta", "noscript",
347                                 "object", "ol", "optgroup", "option",
348                                 "p", "param", "pre", "q", "samp",
349                                 "script", "select", "small", "span",
350                                 "strong", "style", "sub", "sup", "table",
351                                 "tbody", "td", "textarea", "tfoot", "th",
352                                 "thead", "title", "tr", "tt", "ul",
353                                 "var" ] ) ~
354                                 ")[^<>]*>/i"
355                 ],
356                 'word2',        [
357                                 mp.syn_token_list( [
358                                  "!DOCTYPE", "class", "type",
359                                 "cellspacing", "cellpadding",
360                                 "href", "align", "valign", "name", "lang",
361                                 "value", "action", "width", "height",
362                                 "content", "http-equiv", "src", "alt",
363                                 "bgcolor", "text", "link", "vlink", "alink",
364                                 "media" ])
365                 ],
366                 'quotes',       [
367                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
368                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/"          /* single-quoted strings */
369                 ],
370                 'comments',     [
371                                 [ '/<!--/', '/-->/' ]
372                 ]
373         ]
377 mp.syntax.conf = {
378         'id'            =>      'conf',
379         'name'          =>      'Config file',
380         'filenames'     =>      [ '/\.conf$/', '/\.cfg$/', '/^.*\/?\.[0-9a-z_-]+rc$/' ],
381         'defs'          =>      [
382                 'word1',        [ '/^\[.+\]$/m' ],
383                 'word2',        [ "/^[^:=\n]+[:=]/m" ],
384                 'quotes',       [
385                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
386                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
387                         "/\b-?[0-9]+\b/",                       /* numbers */
388                         "/\b0x[0-9a-f]+\b/i"                    /* hex numbers */
389                 ],
390                 'comments',     [ "/#.*$/m" ]
391         ]
395 mp.syntax.php = {
396         'id'            =>      'php',
397         'name'          =>      'PHP',
398         'filenames'     =>      [ '/\.php[345]?$/', '/\.inc$/' ],
399         'defs'          =>      [
400                 'word1',        [
401                                 mp.syn_token_list( [
402                                 "and", "array", "as",
403                                 "bool", "boolean", "break", "case", "class",
404                                 "const", "continue", "declare", "default",
405                                 "die", "do", "double", "echo", "else", "elseif",
406                                 "empty", "enddeclare", "endfor", "endforeach",
407                                 "endif", "endswitch", "endwhile", "eval",
408                                 "exit", "extends", "__FILE__", "float", "for",
409                                 "foreach", "function", "cfunction", "global",
410                                 "if", "include", "include_once", "int",
411                                 "integer", "isset", "__LINE__", "list", "new",
412                                 "object", "old_function", "or", "print", "real",
413                                 "require", "require_once", "return",
414                                 "static", "string", "switch", "unset", "use",
415                                 "var", "while", "xor", 'true', 'false' ]
416                                 )
417                 ],
418                 'word2',        [ '/\$\w+/', '/[-=<>:\?\+\*\!\%&\|]+/' ],
419                 'quotes',       [
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 */
424                         "/\b[0-9[:upper:]_]+\b/",               /* all-caps words */
425                         [ "/`/", "/`/" ]                        /* backticks */
426                 ],
427                 'comments',     [
428                         [ '|/\*|', '|\*/|' ],                   /* C-like */
429                         '|//.*$|m'                              /* C++ */
430                 ]
431         ]
434 mp.syntax.python = {
435         'id'            =>      'python',
436         'name'          =>      'Python',
437         'filenames'     =>      [ '/\.py$/' ],
438         'defs'          =>      [
439                 'word1',        [
440                         mp.syn_token_list( [
441                                 "and", "assert", "break", "class", "continue",
442                                 "def", "del", "elif", "else", "except", "exec",
443                                 "finally", "for", "from", "if", "import", "in",
444                                 "is", "lambda", "not", "or", "pass", "print",
445                                 "raise", "return", "try", "while", "yield"
446                                 ]
447                         )
448                 ],
449                 'word2',        [ '/global/', '/\$\w+/', '/[-=<>:\?\+\*\!\%&\|{}]+/' ],
450                 'quotes',       [
451                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
452                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
453                         "/\b-?[0-9]+\b/",                       /* numbers */
454                         "/\b0x[0-9a-f]+\b/i",                   /* hex numbers */
455                         "/\b[0-9[:upper:]_]+\b/",               /* all-caps words */
456                         [ "/`/", "/`/" ]                        /* backticks */
457                 ],
458                 'comments',             [ "/#.*$/m" ],
459                 'documentation',        [ [ '/""".+[^"]$/m', '/"""$/m' ] ]
460         ],
461         'detect'        =>      sub (d) {
462                 /* take the first line */
463                 local f = d.txt.lines[0];
465                 /* is it a 'she-bang'? */
466                 return regex('/^#!\s*/usr/bin/(env )?python/', f);
467         },
468         'section'       =>      '/^[ \t]*def/'
471 mp.syntax.ruby = {
472         'id'            =>      'ruby',
473         'name'          =>      'Ruby',
474         'filenames'     =>      [ '/\.rb$/' ],
475         'defs'          =>      [
476                 'word1',        [
477                         mp.syn_token_list( [
478                                 "BEGIN", "END", "alias", "and", "begin",
479                                 "break", "case", "class", "def", "defined",
480                                 "do", "else", "elsif", "end", "ensure", 
481                                 "false", "for", "if", "in", "module", "next",
482                                 "nil", "not", "or", "redo", "rescue", "retry",
483                                 "return", "self", "super", "then", "true",
484                                 "undef", "unless", "until", "when", "while",
485                                 "yield", "require", "include" ]
486                         )
487                 ],
488                 'word2',        [ '/[-=<>:\?\+\*\!\%&\|{}]+/', '/=(begin|end)/' ],
489                 'quotes',       [
490                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
491                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
492                         "/\b-?[0-9]+\b/",                       /* numbers */
493                         "/\b0x[0-9a-f]+\b/i",                   /* hex numbers */
494                         "/\b[0-9[:upper:]_]+\b/",               /* all-caps words */
495                         [ "/`/", "/`/" ]                        /* backticks */
496                 ],
497                 'comments',     [ "/#.*$/m" ]
498         ],
499         'detect'        =>      sub (d) {
500                 /* take the first line */
501                 local f = d.txt.lines[0];
503                 /* is it a 'she-bang'? */
504                 return regex('/^#!\s*/usr/bin/(env )?ruby/', f);
505         }
508 mp.syntax.diff = {
509         'id'            =>      'diff',
510         'name'          =>      'diff',
511         'filenames'     =>      [ '/\.diff$/', '/\.patch$/' ],
512         'defs'          =>      [
513                 'word1',        [ '/^\+.+$/m' ],
514                 'word2',        [ '/^\-.+$/m' ],
515                 'quotes',       [ '/^@@.+@@$/m' ]
516         ],
517         'section'       =>      '/^--- '
520 mp.syntax.commit_msg = {
521         'id'            =>      'commit_msg',
522         'name'          =>      'VCS commit message',
523         'filenames'     =>      [ '/sv[kn]-commit.*\./' ],
524         'defs'          =>      [
525                 'word1',        [ '/^AM? .+$/m' ],
526                 'word2',        [ '/^D .+$/m' ],
527                 'quotes',       [ '/^M .+$/m' ],
528                 'comments',     [ '/^=== .+$/m', '/^--.+$/m' ]
529         ]
532 mp.syntax.po = {
533         'id'            =>      'po',
534         'name'          =>      'Gettext file',
535         'filenames'     =>      [ '/\.po$/' ],
536         'defs'          =>      [
537                 'word1',        [ '/^msgid/m' ],
538                 'word2',        [ '/^msgstr/m' ],
539                 'comments',     [ "/#.*$/m" ],
540                 'quotes',       [
541                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/"      /* double-quoted strings */
542                 ]
543         ]
546 mp.syntax.xml = {
547         'id'            =>      'xml',
548         'name'          =>      'XML / XGML',
549         'filenames'     =>      [ '/\.xml$/', '/\.sgml$/' ],
550         'defs'          =>      [
551                 'word1',        [ '/<[^>]+>/' ],
552                 'word2',        [ '/<\?[^\?]+\?>/' ],
553                 'quotes',       [
554                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
555                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/"          /* single-quoted strings */
556                 ],
557                 'comments',     [
558                                 [ '/<!--/', '/-->/' ]
559                 ]
560         ],
561         'detect'        =>      sub (d) {
562                 /* take the first line */
563                 local f = d.txt.lines[0];
565                 return regex('/<\?xml/', f);
566         }
569 mp.syntax.make_output = {
570         'id'            =>      'make_output',
571         'name'          =>      'Make output',
572         'defs'          =>      [
573                 'word1',        [ "/^.*warning:.*$/m" ],
574                 'word2',        [ "/^.*error:.*$/m" ]
575         ]
578 mp.syntax.euphoria = {
579         'id'            =>      'euphoria',
580         'name'          =>      'euphoria',
581         'filenames'     =>      [ '/\.e$/', '/\.eu$/', '/\.ew$/', '/\.ed$/',
582                                 '/\.ex$/', '/\.exw$/', '/\.exu$/' ],
583         'defs'          =>      [
584                 'word1',        [
585                         mp.syn_token_list( [
586                                 "as", "and", "break", "by", "case", "constant", "continue", "do", "end",
587                                 "else", "elsif", "elsifdef",
588                                 "exit", "entry", "enum", "export", "for", "function", "global", "include",
589                                 "if", "ifdef", "label",
590                                 "not", "or", "procedure", "return", "retry", "switch", "then", "type",
591                                 "to", "while", "with", "without", "xor"
592                         ] )
593                 ],
594                 'word2',        [
595                         mp.syn_token_list( [
596                                 "atom", "integer", "sequence", "object"
597                         ] )
598                 ],
599                 'quotes',       [
600                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",    /* double-quoted strings */
601                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",        /* single-quoted strings */
602                         "/\b-?#[0-9A-F]+\b/",                /* hex numbers */
603                         "/\b-?[0-9]+\b/",                /* numbers */
604                         "/\b[0-9[:upper:]_]+\b/"            /* all-caps words */
605                 ],
606                 'comments',             [ "/--.*$/m" ]
607         ],
608         'section'       =>      '/^[ \t]*(global|export)*[ \t]*(function|procedure)/'
612 /** code **/
614 sub mp.detect_syntax(doc)
615 /* tries to detect the syntax of a document */
617         doc.syntax = NULL;
619         /* loops the syntax highlight definitions */
620         foreach (n, keys(mp.syntax)) {
621                 local s = mp.syntax[n];
623                 /* test the extensions */
624                 foreach (ext, s.filenames) {
625                         if (regex(ext, doc.name)) {
626                                 doc.syntax = s;
627                                 return;
628                         }
629                 }
630         }
632         /* not by extension? try the 'detect' subroutine */
633         foreach (n, keys(mp.syntax)) {
634                 local s = mp.syntax[n];
636                 if (is_exec(s.detect) && s.detect(doc)) {
637                         doc.syntax = s;
638                         return;
639                 }
640         }
644 sub mp.help(doc, word)
646         local h;
648         foreach (c, doc.syntax.help) {
649                 local f;
651                 /* format the command */
652                 c = sprintf(c, word);
654                 /* pipe from it */
655                 if ((f = popen(c, "r")) != NULL) {
656                         local l;
657                         h = [];
659                         while ((l = read(f)) != NULL)
660                                 push(h, mp.chomp(l));
662                         /* fails? */
663                         if (pclose(f) != 0)
664                                 h = NULL;
665                 }
667                 /* is there already help? don't look for more */
668                 if (h != NULL)
669                         break;
670         }
672         return h;
677  * mp.section_list - Returns the list of sections of a document.
678  * @doc: the document
680  * Applies the `section' regular expression of the document's
681  * syntax definition and returns it as an array of line and
682  * line number pairs.
684  * If the document has no syntax highlight definition, or it has
685  * one without a `section' regex, NULL is returned. Otherwise,
686  * an array of line, line number pairs is returned (it can be
687  * an empty list if the document has no recognizable sections).
688  */
689 sub mp.section_list(doc)
691         local r;
693         if (doc.syntax.section) {
694                 local n, l;
696                 r = [];
698                 while ((l = doc.txt.lines[n]) != NULL) {
699                         if (regex(doc.syntax.section, l))
700                                 push(r, [ l, n ]);
702                         n++;
703                 }
704         }
706         return r;