Merge branch 'master' of /home/angel/git/mp-5.x/
[mp-5.x.git] / mp_syntax.mpsl
blob9ff6e266e69cdf354d63b2232bd87d77039430a4
1 /*
3     Minimum Profit 5.x
4     A Programmer's Text Editor
6     Syntax highlight definitions.
8     Copyright (C) 1991-2009 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                                 "class", "template", "new", "delete",
124                                 "using", "namespace", "try", "catch", "throw"
125                                 ])
126                 ],
127                 'word2',        [
128                                 mp.syn_token_list( [
129                                 "char", "int", "long", "struct", "union", "const",
130                                 "void", "unsigned", "signed", "auto", "volatile",
131                                 "enum", "typedef", "float", "double", "extern",
132                                 "register", "short", "sizeof", "static", "far",
133                                 "near", "defined", "va_list", "size_t", "wchar_t",
134                                 "iconv_t", "virtual", "friend", "operator",
135                                 "public", "protected", "private", "slots", "signals"
136                                  ]),
137                                 '/[-=<>:\?\+\*\/\!\%&\|]+/'
138                 ],
139                 'quotes',       [
140                         /* from http://ad.hominem.org/log/2005/05/quoted_strings.php */
141                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
142                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
143                         "/\b-?[0-9]+\b/",                       /* numbers */
144                         "/\b0x[0-9a-f]+\b/i",                   /* hex numbers */
145                         "/\b[0-9[:upper:]_]+\b/"                /* all-caps words */
146                 ],
147                 'comments',     [
148                         [ '|/\*|', '|\*/|' ],                   /* C-like */
149                         '|//.*$|m',                             /* C++ */
150                         '/^\s*#[a-z]+/m'                        /* CPP directives */
151                 ],
152                 'documentation',        [
153                         [ "|/\*\*\n|", '|\*/|' ],               /* mp_doccer */
154                         '/^/\*\*.*\*\*/$/m'                     /* section mark */
155                 ]
156         ],
157         'section'       =>      [ '/(^\/\*\*.*\*\*\/$|^#pragma mark|^\w.*\)$)/' ]
160 mp.syntax.rc = {
161         'id'            =>      'rc',
162         'name'          =>      'Resource file',
163         'filenames'     =>      [ '/\.rc$/' ],
164         'defs'          =>      [
165                 'word1',        [ ],
166                 'word2',        [ ],
167                 'quotes',       [
168                         /* from http://ad.hominem.org/log/2005/05/quoted_strings.php */
169                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
170                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
171                         "/\b-?[0-9]+\b/",                       /* numbers */
172                         "/\b0x[0-9a-f]+\b/i",                   /* hex numbers */
173                         "/\b[0-9[:upper:]_]+\b/"                /* all-caps words */
174                 ],
175                 'comments',     [
176                         [ '|/\*|', '|\*/|' ],                   /* C-like */
177                         '|//.*$|m',                             /* C++ */
178                         '/^\s*#[a-z]+/m'                        /* CPP directives */
179                 ]
180         ]
183 mp.syntax.perl = {
184         'id'            =>      'perl',
185         'name'          =>      'Perl',
186         'filenames'     =>      [ '/\.pl$/i', '/\.pm$/' ],
187         'help'          =>      [ 'perldoc -f %s', 'perldoc %s' ],
188         'help_word_regex' =>    '/[A-Z_][A-Z0-9_:]*/i',
189         'defs'  =>      [
190                 'word1',        [
191                                 mp.syn_token_list( [
192                                 "for", "if", "next", "last", "else", "elsif",
193                                 "unless", "while", "shift", "unshift", "push",
194                                 "pop", "delete", "new", "bless", "return",
195                                 "foreach", "keys", "values", "sort", "grep",
196                                 "tr", "length", "system", "exec", "fork", "map",
197                                 "print", "write", "open", "close", "chop",
198                                 "chomp", "exit", "sleep", "split", "join",
199                                 "sub", "printf", "sprintf", "s", "glob",
200                                 "scalar", "my", "local", "undef", "defined",
201                                 "use", "package", "require", "ref", "can", "isa",
202                                 "qw", "qq", "eq", "ne", "or", "exists",
203                                 "and", "not", "import", "our", "caller" ]),
204                                 '/->/'
205                 ],
206                 'word2',        [
207                                 '/[:\?\+\*\/\!\$@\%&\|~\.]+/',
208                                 '/[\$@%]\w+/'
209                 ],
210                 'quotes',       [
211                         /* from http://ad.hominem.org/log/2005/05/quoted_strings.php */
212                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
213                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
214                         "/\b-?[0-9]+\b/",                       /* numbers */
215                         "/\b0x[0-9a-f]+\b/i",                   /* hex numbers */
216                         "/\b[0-9[:upper:]_]+\b/",               /* all-caps words */
217                         [ "/q\(/", "/\)/" ],                    /* quote */
218                         [ "/qw\(/", "/\)/" ],                   /* quote word */
219                         '/\w+\s*=>/',                           /* barewords as hash keys 1 */
220                         '/\{\s*-?\w+\s*\}/',                    /* barewords as hash keys 2 */
221                         [ "/`/", "/`/" ],                       /* backticks */
222                         [ "/<<[\"']?EOF.*$/m", "/^EOF$/m" ]     /* 'document here' */
223                 ],
224                 /* color all => as word2 */
225                 'word2',        [ '/=>/' ],
226                 /* color curly brackets as word */
227                 'word',         [ '/[{}]/' ],
228                 'comments',     [
229                         "/#.*$/m"                               /* Comments */
230                 ],
231                 'documentation',        [
232                         "/__END__\n.*$/",                       /* __END__ */
233                         '/^## .*$/m',                           /* section mark */
234                         [ "/^=(head[1-4]|over|item|back|pod|begin|end|for)/m",
235                                 "/^=cut$/m" ]                   /* POD */
236                 ]       
237         ],
238         'detect'        =>      sub (d) {
239                 /* take the first line */
240                 local f = d.txt.lines[0];
242                 /* is it a 'she-bang' for Perl? */
243                 return regex('/^#!\s*/usr/bin/(env )?perl/', f);
244         },
245         'section'       =>      [ '/(^sub \w+|^package|^## )/' ]
249 mp.syntax.mpsl = {
250         'id'            =>      'mpsl',
251         'name'          =>      'MPSL',
252         'filenames'     =>      [ '/\.mpsl$/' ],
253         'defs'          =>      [
254                 'word1',        [
255                                 mp.syn_token_list( [
256                                         'if', 'else', 'while', 'foreach',
257                                         'sub', 'break', 'return', 'eq', 'ne' ]),
258                                 mp.syn_token_list( keys(MPSL.CORE) ),
259                                 '/[\{\}]/'
260                 ],
261                 'word2',        [
262                                 "/(NULL|local)/",
263                                 '/[-=<>:\?\+\*\/\!\%&\|]+/'
264                 ],
265                 'quotes',       [
266                         /* from http://ad.hominem.org/log/2005/05/quoted_strings.php */
267                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
268                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
269                         "/\b-?[0-9]+\b/",                       /* numbers */
270                         "/\b0x[0-9a-f]+\b/i",                   /* hex numbers */
271                         "/\b[0-9[:upper:]_]+\b/"                /* all-caps words */
272                 ],
273                 'comments',     [
274                         [ '|/\*|', '|\*/|' ]                    /* C-like */
275                 ],
276                 'documentation',        [
277                         [ "|/\*\*\n|", '|\*/|' ],               /* mp_doccer */
278                         '/^/\*\*.*\*\*/$/m'                     /* section mark */
279                 ]
280         ],
281         'section'       =>      [ '/(^sub \w+|^\/\*\*.*\*\*\/$)/' ]
284 mp.syntax.sh = {
285         'id'            =>      'sh',
286         'name'          =>      'Shell script',
287         'filenames'     =>      [ '/\.sh$/', '/makefile/i' ],
288         'defs'          =>      [
289                 'word1',        [
290                                 mp.syn_token_list( [
291                                 "if", "then", "else", "elif",
292                                 "fi", "case", "do", "done", "esac",
293                                 "for", "until", "while", "break",
294                                 "in", "source", "alias", "cd",
295                                 "continue", "echo", "eval", "exec",
296                                 "exit", "export", "kill", "logout",
297                                 "printf", "pwd", "read", "return",
298                                 "shift", "test", "trap", "ulimit",
299                                 "umask", "unset", "wait", "cp", "rm" ]),
300                                 '/[\{\}]/'
302                 ],
303                 'word2',        [
304                                 '/\b(local|let|set)\b/',
305                                 '/[-=<>:\?\+\*\!\%&\|]+/',
306                                 '/\$\w+/',
307                                 '/\$\{\w+\}/',
308                                 "/\b[0-9[:upper:]_]+\b/"        /* all-caps words */
309                 ],
310                 'quotes',       [
311                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
312                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
313                         "/\b-?[0-9]+\b/",                       /* numbers */
314                         "/\b0x[0-9a-f]+\b/i",                   /* hex numbers */
315                         "/\([A-Za-z0-9_]+\)/",                  /* parens */
316                         [ "/`/", "/`/" ],                       /* backticks */
317                         [ "/<<[\"']?EOF[\"']?;$/m", "/^EOF$/m" ]        /* 'document here' */
318                 ],
319                 'comments',     [ "/#.*$/m" ]
320         ],
321         'detect'        =>      sub (d) {
322                 /* take the first line */
323                 local f = d.txt.lines[0];
325                 /* is it a 'she-bang' for usual shells? */
326                 return regex('/^#!\s*/bin/(sh|bash|csh|dash|ksh)/', f) ||
327                        regex('/^#!\s*/usr/bin/make -f/', f);
328         },
329         'section'       =>      [ '/(^\w+\(\))/', '/^[A-Za-z0-9_\.-]+:/' ]
333 mp.syntax.html = {
334         'id'            =>      'html',
335         'name'          =>      'HTML',
336         'filenames'     =>      [ '/\.html$/', '/\.htm$/' ],
337         'defs'          =>      [
338                 'word1',        [
339                                 "/<[\/]?[ \t]*(" ~
340                                 join("|", [
341                                 "a", "abbr", "acronym", "address",
342                                 "area", "b", "base", "bdo", "big",
343                                 "blockquote", "body", "br", "button",
344                                 "caption", "center", "cite", "code", "col",
345                                 "colgroup", "dd", "del", "dfn", "div",
346                                 "dl", "dt", "em", "fieldset", "form",
347                                 "h1", "h2", "h3", "h4", "h5", "h6",
348                                 "head", "hr", "html", "i", "img",
349                                 "input", "ins", "kbd", "label", "legend",
350                                 "li", "link", "map", "meta", "noscript",
351                                 "object", "ol", "optgroup", "option",
352                                 "p", "param", "pre", "q", "samp",
353                                 "script", "select", "small", "span",
354                                 "strong", "style", "sub", "sup", "table",
355                                 "tbody", "td", "textarea", "tfoot", "th",
356                                 "thead", "title", "tr", "tt", "ul",
357                                 "var" ] ) ~
358                                 ")[^<>]*>/i"
359                 ],
360                 'word2',        [
361                                 mp.syn_token_list( [
362                                  "!DOCTYPE", "class", "type",
363                                 "cellspacing", "cellpadding",
364                                 "href", "align", "valign", "name", "lang",
365                                 "value", "action", "width", "height",
366                                 "content", "http-equiv", "src", "alt",
367                                 "bgcolor", "text", "link", "vlink", "alink",
368                                 "media" ])
369                 ],
370                 'quotes',       [
371                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
372                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/"          /* single-quoted strings */
373                 ],
374                 'comments',     [
375                                 [ '/<!--/', '/-->/' ]
376                 ]
377         ],
378         'section'       =>      [ '/<\s*h[0-9]\s*>/' ]
382 mp.syntax.conf = {
383         'id'            =>      'conf',
384         'name'          =>      'Config file',
385         'filenames'     =>      [ '/\.conf$/', '/\.cfg$/', '/^.*\/?\.[0-9a-z_-]+rc$/' ],
386         'defs'          =>      [
387                 'word1',        [ '/^\[.+\]$/m' ],
388                 'word2',        [ "/^[^:=\n]+[:=]/m" ],
389                 'quotes',       [
390                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
391                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
392                         "/\b-?[0-9]+\b/",                       /* numbers */
393                         "/\b0x[0-9a-f]+\b/i"                    /* hex numbers */
394                 ],
395                 'comments',     [ "/#.*$/m" ]
396         ]
400 mp.syntax.php = {
401         'id'            =>      'php',
402         'name'          =>      'PHP',
403         'filenames'     =>      [ '/\.php[345]?$/', '/\.inc$/' ],
404         'defs'          =>      [
405                 'word1',        [
406                                 mp.syn_token_list( [
407                                 "and", "array", "as",
408                                 "bool", "boolean", "break", "case", "class",
409                                 "const", "continue", "declare", "default",
410                                 "die", "do", "double", "echo", "else", "elseif",
411                                 "empty", "enddeclare", "endfor", "endforeach",
412                                 "endif", "endswitch", "endwhile", "eval",
413                                 "exit", "extends", "__FILE__", "float", "for",
414                                 "foreach", "function", "cfunction", "global",
415                                 "if", "include", "include_once", "int",
416                                 "integer", "isset", "__LINE__", "list", "new",
417                                 "object", "old_function", "or", "print", "real",
418                                 "require", "require_once", "return",
419                                 "static", "string", "switch", "unset", "use",
420                                 "var", "while", "xor", 'true', 'false' ]
421                                 )
422                 ],
423                 'word2',        [ '/\$\w+/', '/[-=<>:\?\+\*\!\%&\|]+/' ],
424                 'quotes',       [
425                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
426                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
427                         "/\b-?[0-9]+\b/",                       /* numbers */
428                         "/\b0x[0-9a-f]+\b/i",                   /* hex numbers */
429                         "/\b[0-9[:upper:]_]+\b/",               /* all-caps words */
430                         [ "/`/", "/`/" ]                        /* backticks */
431                 ],
432                 'comments',     [
433                         [ '|/\*|', '|\*/|' ],                   /* C-like */
434                         '|//.*$|m'                              /* C++ */
435                 ]
436         ]
439 mp.syntax.python = {
440         'id'            =>      'python',
441         'name'          =>      'Python',
442         'filenames'     =>      [ '/\.py$/' ],
443         'defs'          =>      [
444                 'word1',        [
445                         mp.syn_token_list( [
446                                 "and", "assert", "break", "class", "continue",
447                                 "def", "del", "elif", "else", "except", "exec",
448                                 "finally", "for", "from", "if", "import", "in",
449                                 "is", "lambda", "not", "or", "pass", "print",
450                                 "raise", "return", "try", "while", "yield"
451                                 ]
452                         )
453                 ],
454                 'word2',        [ '/global/', '/\$\w+/', '/[-=<>:\?\+\*\!\%&\|{}]+/' ],
455                 'quotes',       [
456                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
457                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
458                         "/\b-?[0-9]+\b/",                       /* numbers */
459                         "/\b0x[0-9a-f]+\b/i",                   /* hex numbers */
460                         "/\b[0-9[:upper:]_]+\b/",               /* all-caps words */
461                         [ "/`/", "/`/" ]                        /* backticks */
462                 ],
463                 'comments',             [ "/#.*$/m" ],
464                 'documentation',        [ [ '/""".+[^"]$/m', '/"""$/m' ] ]
465         ],
466         'detect'        =>      sub (d) {
467                 /* take the first line */
468                 local f = d.txt.lines[0];
470                 /* is it a 'she-bang'? */
471                 return regex('/^#!\s*/usr/bin/(env )?python/', f);
472         },
473         'section'       =>      [ '/^[ \t]*def/' ]
476 mp.syntax.ruby = {
477         'id'            =>      'ruby',
478         'name'          =>      'Ruby',
479         'filenames'     =>      [ '/\.rb$/' ],
480         'defs'          =>      [
481                 'word1',        [
482                         mp.syn_token_list( [
483                                 "BEGIN", "END", "alias", "and", "begin",
484                                 "break", "case", "class", "def", "defined",
485                                 "do", "else", "elsif", "end", "ensure", 
486                                 "false", "for", "if", "in", "module", "next",
487                                 "nil", "not", "or", "redo", "rescue", "retry",
488                                 "return", "self", "super", "then", "true",
489                                 "undef", "unless", "until", "when", "while",
490                                 "yield", "require", "include" ]
491                         )
492                 ],
493                 'word2',        [ '/[-=<>:\?\+\*\!\%&\|{}]+/', '/=(begin|end)/' ],
494                 'quotes',       [
495                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
496                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
497                         "/\b-?[0-9]+\b/",                       /* numbers */
498                         "/\b0x[0-9a-f]+\b/i",                   /* hex numbers */
499                         "/\b[0-9[:upper:]_]+\b/",               /* all-caps words */
500                         [ "/`/", "/`/" ]                        /* backticks */
501                 ],
502                 'comments',     [ "/#.*$/m" ]
503         ],
504         'detect'        =>      sub (d) {
505                 /* take the first line */
506                 local f = d.txt.lines[0];
508                 /* is it a 'she-bang'? */
509                 return regex('/^#!\s*/usr/bin/(env )?ruby/', f);
510         }
513 mp.syntax.diff = {
514         'id'            =>      'diff',
515         'name'          =>      'diff',
516         'filenames'     =>      [ '/\.diff$/', '/\.patch$/' ],
517         'defs'          =>      [
518                 'word1',        [ '/^\+.+$/m' ],
519                 'word2',        [ '/^\-.+$/m' ],
520                 'quotes',       [ '/^@@.+@@$/m' ]
521         ],
522         'section'       =>      [ '/^--- ' ]
525 mp.syntax.commit_msg = {
526         'id'            =>      'commit_msg',
527         'name'          =>      'VCS commit message',
528         'filenames'     =>      [ '/sv[kn]-commit.*\./' ],
529         'defs'          =>      [
530                 'word1',        [ '/^AM? .+$/m' ],
531                 'word2',        [ '/^D .+$/m' ],
532                 'quotes',       [ '/^M .+$/m' ],
533                 'comments',     [ '/^=== .+$/m', '/^--.+$/m' ]
534         ]
537 mp.syntax.po = {
538         'id'            =>      'po',
539         'name'          =>      'Gettext file',
540         'filenames'     =>      [ '/\.po$/' ],
541         'defs'          =>      [
542                 'word1',        [ '/^msgid/m' ],
543                 'word2',        [ '/^msgstr/m' ],
544                 'comments',     [ "/#.*$/m" ],
545                 'quotes',       [
546                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/"      /* double-quoted strings */
547                 ]
548         ]
551 mp.syntax.xml = {
552         'id'            =>      'xml',
553         'name'          =>      'XML / XGML',
554         'filenames'     =>      [ '/\.xml$/', '/\.sgml$/' ],
555         'defs'          =>      [
556                 'word1',        [ '/<[^>]+>/' ],
557                 'word2',        [ '/<\?[^\?]+\?>/' ],
558                 'quotes',       [
559                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
560                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/"          /* single-quoted strings */
561                 ],
562                 'comments',     [
563                                 [ '/<!--/', '/-->/' ]
564                 ]
565         ],
566         'detect'        =>      sub (d) {
567                 /* take the first line */
568                 local f = d.txt.lines[0];
570                 return regex('/<\?xml/', f);
571         }
574 mp.syntax.make_output = {
575         'id'            =>      'make_output',
576         'name'          =>      'Make output',
577         'defs'          =>      [
578                 'word1',        [ "/^.*warning:.*$/m" ],
579                 'word2',        [ "/^.*error:.*$/m" ]
580         ]
583 mp.syntax.euphoria = {
584         'id'            =>      'euphoria',
585         'name'          =>      'euphoria',
586         'filenames'     =>      [ '/\.e$/', '/\.eu$/', '/\.ew$/', '/\.ed$/',
587                                 '/\.ex$/', '/\.exw$/', '/\.exu$/' ],
588         'defs'          =>      [
589                 'word1',        [
590                         mp.syn_token_list( [
591                                 "as", "and", "break", "by", "case", "constant", "continue", "do", "end",
592                                 "else", "elsif", "elsifdef",
593                                 "exit", "entry", "enum", "export", "for", "function", "global", "include",
594                                 "if", "ifdef", "label",
595                                 "not", "or", "procedure", "return", "retry", "switch", "then", "type",
596                                 "to", "while", "with", "without", "xor"
597                         ] )
598                 ],
599                 'word2',        [
600                         mp.syn_token_list( [
601                                 "atom", "integer", "sequence", "object"
602                         ] )
603                 ],
604                 'quotes',       [
605                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",    /* double-quoted strings */
606                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",        /* single-quoted strings */
607                         "/\b-?#[0-9A-F]+\b/",                /* hex numbers */
608                         "/\b-?[0-9]+\b/",                /* numbers */
609                         "/\b[0-9[:upper:]_]+\b/"            /* all-caps words */
610                 ],
611                 'comments',             [ "/--.*$/m" ]
612         ],
613         'section'       =>      [ '/^[ \t]*(global|export)*[ \t]*(function|procedure)/' ]
617 mp.syntax.mp_templates = {
618         'id'            => 'mp_templates',
619         'name'          => 'Minimum Profit template file',
620         'filenames'     => [ '/\.mp_templates$/' ],
621         'defs'          => [
622                 'documentation',        [ '/^%%.*$/m' ]
623         ],
624         'section'       => [ '/^%%/' ]
628 /** code **/
630 sub mp.detect_syntax(doc)
631 /* tries to detect the syntax of a document */
633         doc.syntax = NULL;
635         /* loops the syntax highlight definitions */
636         foreach (n, keys(mp.syntax)) {
637                 local s = mp.syntax[n];
639                 /* test the extensions */
640                 foreach (ext, s.filenames) {
641                         if (regex(ext, doc.name)) {
642                                 doc.syntax = s;
643                                 return;
644                         }
645                 }
646         }
648         /* not by extension? try the 'detect' subroutine */
649         foreach (n, keys(mp.syntax)) {
650                 local s = mp.syntax[n];
652                 if (is_exec(s.detect) && s.detect(doc)) {
653                         doc.syntax = s;
654                         return;
655                 }
656         }
660 sub mp.help(doc, word)
662         local h;
664         foreach (c, doc.syntax.help) {
665                 local f;
667                 /* format the command */
668                 c = sprintf(c, word);
670                 /* pipe from it */
671                 if ((f = popen(c, "r")) != NULL) {
672                         local l;
673                         h = [];
675                         while ((l = read(f)) != NULL)
676                                 push(h, mp.chomp(l));
678                         /* fails? */
679                         if (pclose(f) != 0)
680                                 h = NULL;
681                 }
683                 /* is there already help? don't look for more */
684                 if (h != NULL)
685                         break;
686         }
688         return h;
693  * mp.section_list - Returns the list of sections of a document.
694  * @doc: the document
696  * Applies the `section' array of regular expressions of the
697  * document's syntax definition and returns it as an array of
698  * line and line number pairs.
700  * If the document has no syntax highlight definition, or it has
701  * one without a `section' definition, NULL is returned. Otherwise,
702  * an array of line, line number pairs is returned (it can be
703  * an empty list if the document has no recognizable sections).
704  */
705 sub mp.section_list(doc)
707         local r;
709         if (doc.syntax.section) {
710                 local n, l;
712                 r = [];
714                 while ((l = doc.txt.lines[n]) != NULL) {
715                         foreach (ex, doc.syntax.section) {
716                                 if (regex(ex, l)) {
717                                         push(r, [ l, n ]);
718                                         break;
719                                 }
720                         }
722                         n++;
723                 }
724         }
726         return r;