More join() changes.
[mp-5.x.git] / mp_syntax.mpsl
blob7a65feace04534c7db3cce0f89ba214e2a253c6c
1 /*
3     Minimum Profit 5.x
4     A Programmer's Text Editor
6     Syntax highlight definitions.
8     Copyright (C) 1991-2010 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.search_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$/i', '/\.h$/i', '/\.l$/i', '/\.y$/i', '/\.d$/i',
99                                 '/\.cpp$/i', '/\.hpp$/i', '/\.c++$/i', '/\.cxx$/i', '/\.xpm$/i' ],
100         'help'          =>      [ "man 2 %s", "man 3 %s" ],
101         'defs'          =>      [
102                 'word1',        [
103                                 mp.syn_token_list( [
104                                 "auto", "break", "case", "catch", "class", "const", "const_cast",
105                                 "continue", "default", "delete", "do", "dynamic_cast", "else", "enum",
106                                 "explicit", "extern", "for", "friend", "goto", "if", "inline", "mutable",
107                                 "namespace", "new", "operator", "private", "protected", "public",
108                                 "register", "reinterpret_cast", "restrict", "return", "sizeof", "static",
109                                 "static_cast", "struct", "switch", "template", "this", "throw", "try",
110                                 "typedef", "typeid", "typename", "union", "using", "virtual", "volatile",
111                                 "while", "not", "not_eq", "xor", "xor_eq", "or",  "or_eq", "and", "and_eq",
112                                 "bitor", "bitand", "compl"
113                                 ])
114                 ],
115                 'word2',        [
116                                 mp.syn_token_list( [
117                                 "bool", "char", "double", "float", "int", "long", "short", "signed",
118                                 "unsigned", "wchar_t", "size_t", "ssize_t", "off_t", "wchar_t",
119                                 "ptrdiff_t", "void", "sig_atomic_t", "fpos_t", "clock_t", "time_t",
120                                 "va_list", "jmp_buf", "FILE", "DIR", "div_t", "ldiv_t", "mbstate_t",
121                                 "wctrans_t", "wint_t", "wctype_t", "complex", "int8_t", "int16_t",
122                                 "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t",
123                                 "int_least8_t", "int_least16_t", "int_least32_t", "int_least64_t",
124                                 "uint_least8_t", "uint_least16_t", "uint_least32_t", "uint_least64_t",
125                                 "int_fast8_t", "int_fast16_t", "int_fast32_t", "int_fast64_t",
126                                 "uint_fast8_t", "uint_fast16_t", "uint_fast32_t", "uint_fast64_t",
127                                 "intptr_t", "uintptr_t", "intmax_t", "uintmax_t"
128                                  ]),
129                                 '/[-=<>:\?\+\*\/\!\%&\|~\^\.]+/'
130                 ],
131                 'quotes',       [
132                         /* from http://ad.hominem.org/log/2005/05/quoted_strings.php */
133                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
134                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
135                         "/\b-?[0-9]+\b/",                       /* numbers */
136                         "/\b[0-9]+e[0-9]+\b/",                  /* numbers in exp format */
137                         "/\b0[0-7]+\b/",                        /* octal numbers */
138                         "/\b0x[0-9a-f]+\b/i",                   /* hex numbers */
139                         "/\b__(DATE|FILE|LINE|STDC|TIME|STDC_HOSTED|STDC_VERSION|func)__\b/", /* ISO macros */
140                         "/\b(true|false|NULL)\b/"           /* symbolic constant names */
141                 ],
142                 'comments',     [
143                         [ '|/\*|', '|\*/|' ],                   /* C-like */
144                         [ '|#if 0|', '#endif' ],                /* CPP "comments" */
145                         '|//.*$|m',                             /* C++ */
146                         '/^\s*#\s*[a-z]+/m'                     /* CPP directives */
147                 ],
148                 'documentation',        [
149                         [ "|/\*\*\n|", '|\*/|' ],               /* mp_doccer */
150                         '/^/\*\*.*\*\*/$/m'                     /* section mark */
151                 ]
152         ],
153         'section'       =>      [ '/(^\/\*\*.*\*\*\/$|^#pragma mark|^\w.*\)( \{)?$)/' ]
156 mp.syntax.rc = {
157         'id'            =>      'rc',
158         'name'          =>      'Resource file',
159         'filenames'     =>      [ '/\.rc$/i' ],
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$/i' ],
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?$/i' ],
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$/i', '/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+\(\))/', '/^[A-Za-z0-9_\.-]+:/' ]
329 mp.syntax.html = {
330         'id'            =>      'html',
331         'name'          =>      'HTML',
332         'filenames'     =>      [ '/\.html$/i', '/\.htm$/i' ],
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         ],
374         'section'       =>      [ '/<\s*h[0-9]\s*>/' ]
378 mp.syntax.conf = {
379         'id'            =>      'conf',
380         'name'          =>      'Config file',
381         'filenames'     =>      [ '/\.conf$/i', '/\.cfg$/i', '/^.*\/?\.[0-9a-z_-]+rc$/i' ],
382         'defs'          =>      [
383                 'word1',        [ '/^\[.+\]$/m' ],
384                 'word2',        [ "/^[^:=\n]+[:=]/m" ],
385                 'quotes',       [
386                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
387                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
388                         "/\b-?[0-9]+\b/",                       /* numbers */
389                         "/\b0x[0-9a-f]+\b/i"                    /* hex numbers */
390                 ],
391                 'comments',     [ "/#.*$/m" ]
392         ]
396 mp.syntax.php = {
397         'id'            =>      'php',
398         'name'          =>      'PHP',
399         'filenames'     =>      [ '/\.php[345]?$/i', '/\.inc$/i' ],
400         'defs'          =>      [
401                 'word1',        [
402                                 mp.syn_token_list( [
403                                 "and", "array", "as",
404                                 "bool", "boolean", "break", "case", "class",
405                                 "const", "continue", "declare", "default",
406                                 "die", "do", "double", "echo", "else", "elseif",
407                                 "empty", "enddeclare", "endfor", "endforeach",
408                                 "endif", "endswitch", "endwhile", "eval",
409                                 "exit", "extends", "__FILE__", "float", "for",
410                                 "foreach", "function", "cfunction", "global",
411                                 "if", "include", "include_once", "int",
412                                 "integer", "isset", "__LINE__", "list", "new",
413                                 "object", "old_function", "or", "print", "real",
414                                 "require", "require_once", "return",
415                                 "static", "string", "switch", "unset", "use",
416                                 "var", "while", "xor", 'true', 'false' ]
417                                 )
418                 ],
419                 'word2',        [ '/\$\w+/', '/[-=<>:\?\+\*\!\%&\|]+/' ],
420                 'quotes',       [
421                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
422                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
423                         "/\b-?[0-9]+\b/",                       /* numbers */
424                         "/\b0x[0-9a-f]+\b/i",                   /* hex numbers */
425                         "/\b[0-9[:upper:]_]+\b/",               /* all-caps words */
426                         [ "/`/", "/`/" ]                        /* backticks */
427                 ],
428                 'comments',     [
429                         [ '|/\*|', '|\*/|' ],                   /* C-like */
430                         '|//.*$|m'                              /* C++ */
431                 ]
432         ]
435 mp.syntax.python = {
436         'id'            =>      'python',
437         'name'          =>      'Python',
438         'filenames'     =>      [ '/\.py$/i' ],
439         'defs'          =>      [
440                 'word1',        [
441                         mp.syn_token_list( [
442                                 "and", "assert", "break", "class", "continue",
443                                 "def", "del", "elif", "else", "except", "exec",
444                                 "finally", "for", "from", "if", "import", "in",
445                                 "is", "lambda", "not", "or", "pass", "print",
446                                 "raise", "return", "try", "while", "yield"
447                                 ]
448                         )
449                 ],
450                 'word2',        [ '/global/', '/\$\w+/', '/[-=<>:\?\+\*\!\%&\|{}]+/' ],
451                 'quotes',       [
452                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
453                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
454                         "/\b-?[0-9]+\b/",                       /* numbers */
455                         "/\b0x[0-9a-f]+\b/i",                   /* hex numbers */
456                         "/\b[0-9[:upper:]_]+\b/",               /* all-caps words */
457                         [ "/`/", "/`/" ]                        /* backticks */
458                 ],
459                 'comments',             [ "/#.*$/m" ],
460                 'documentation',        [ [ '/""".+[^"]$/m', '/"""$/m' ] ]
461         ],
462         'detect'        =>      sub (d) {
463                 /* take the first line */
464                 local f = d.txt.lines[0];
466                 /* is it a 'she-bang'? */
467                 return regex('/^#!\s*/usr/bin/(env )?python/', f);
468         },
469         'section'       =>      [ '/^[ \t]*def/' ]
472 mp.syntax.ruby = {
473         'id'            =>      'ruby',
474         'name'          =>      'Ruby',
475         'filenames'     =>      [ '/\.rb$/i' ],
476         'defs'          =>      [
477                 'word1',        [
478                         mp.syn_token_list( [
479                                 "BEGIN", "END", "alias", "and", "begin",
480                                 "break", "case", "class", "def", "defined",
481                                 "do", "else", "elsif", "end", "ensure",
482                                 "false", "for", "if", "in", "module", "next",
483                                 "nil", "not", "or", "redo", "rescue", "retry",
484                                 "return", "self", "super", "then", "true",
485                                 "undef", "unless", "until", "when", "while",
486                                 "yield", "require", "include" ]
487                         )
488                 ],
489                 'word2',        [ '/[-=<>:\?\+\*\!\%&\|{}]+/', '/=(begin|end)/' ],
490                 'quotes',       [
491                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
492                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
493                         "/\b-?[0-9]+\b/",                       /* numbers */
494                         "/\b0x[0-9a-f]+\b/i",                   /* hex numbers */
495                         "/\b[0-9[:upper:]_]+\b/",               /* all-caps words */
496                         [ "/`/", "/`/" ]                        /* backticks */
497                 ],
498                 'comments',     [ "/#.*$/m" ]
499         ],
500         'detect'        =>      sub (d) {
501                 /* take the first line */
502                 local f = d.txt.lines[0];
504                 /* is it a 'she-bang'? */
505                 return regex('/^#!\s*/usr/bin/(env )?ruby/', f);
506         }
509 mp.syntax.diff = {
510         'id'            =>      'diff',
511         'name'          =>      'diff',
512         'filenames'     =>      [ '/\.diff$/i', '/\.patch$/i' ],
513         'defs'          =>      [
514                 'word1',        [ '/^\+.+$/m' ],
515                 'word2',        [ '/^\-.+$/m' ],
516                 'quotes',       [ '/^@@.+@@$/m' ]
517         ],
518         'section'       =>      [ '/^--- ' ]
521 mp.syntax.commit_msg = {
522         'id'            =>      'commit_msg',
523         'name'          =>      'VCS commit message',
524         'filenames'     =>      [ '/sv[kn]-commit.*\./' ],
525         'defs'          =>      [
526                 'word1',        [ '/^AM? .+$/m' ],
527                 'word2',        [ '/^D .+$/m' ],
528                 'quotes',       [ '/^M .+$/m' ],
529                 'comments',     [ '/^=== .+$/m', '/^--.+$/m' ]
530         ]
533 mp.syntax.po = {
534         'id'            =>      'po',
535         'name'          =>      'Gettext file',
536         'filenames'     =>      [ '/\.po$/i' ],
537         'defs'          =>      [
538                 'word1',        [ '/^msgid/m' ],
539                 'word2',        [ '/^msgstr/m' ],
540                 'comments',     [ "/#.*$/m" ],
541                 'quotes',       [
542                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/"      /* double-quoted strings */
543                 ]
544         ]
547 mp.syntax.xml = {
548         'id'            =>      'xml',
549         'name'          =>      'XML / XGML',
550         'filenames'     =>      [ '/\.xml$/i', '/\.sgml$/i' ],
551         'defs'          =>      [
552                 'word1',        [ '/<[^>]+>/' ],
553                 'word2',        [ '/<\?[^\?]+\?>/' ],
554                 'quotes',       [
555                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
556                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/"          /* single-quoted strings */
557                 ],
558                 'comments',     [
559                                 [ '/<!--/', '/-->/' ]
560                 ]
561         ],
562         'detect'        =>      sub (d) {
563                 /* take the first line */
564                 local f = d.txt.lines[0];
566                 return regex('/<\?xml/', f);
567         }
570 mp.syntax.make_output = {
571         'id'            =>      'make_output',
572         'name'          =>      'Make output',
573         'defs'          =>      [
574                 'word1',        [ "/^.*warning:.*$/m" ],
575                 'word2',        [ "/^.*error:.*$/m" ]
576         ]
579 mp.syntax.euphoria = {
580         'id'            =>      'euphoria',
581         'name'          =>      'euphoria',
582         'filenames'     =>      [ '/\.e$/', '/\.eu$/', '/\.ew$/', '/\.ed$/',
583                                 '/\.ex$/', '/\.exw$/', '/\.exu$/' ],
584         'defs'          =>      [
585                 'word1',        [
586                         mp.syn_token_list( [
587                                 "as", "and", "break", "by", "case", "constant", "continue", "do", "end",
588                                 "else", "elsif", "elsifdef",
589                                 "exit", "entry", "enum", "export", "for", "function", "global", "include",
590                                 "if", "ifdef", "label",
591                                 "not", "or", "procedure", "return", "retry", "switch", "then", "type",
592                                 "to", "while", "with", "without", "xor"
593                         ] )
594                 ],
595                 'word2',        [
596                         mp.syn_token_list( [
597                                 "atom", "integer", "sequence", "object"
598                         ] )
599                 ],
600                 'quotes',       [
601                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",    /* double-quoted strings */
602                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",        /* single-quoted strings */
603                         "/\b-?#[0-9A-F]+\b/",                /* hex numbers */
604                         "/\b-?[0-9]+\b/",                /* numbers */
605                         "/\b[0-9[:upper:]_]+\b/"            /* all-caps words */
606                 ],
607                 'comments',             [ "/--.*$/m" ]
608         ],
609         'section'       =>      [ '/^[ \t]*(global|export)*[ \t]*(function|procedure)/' ]
613 mp.syntax.mp_templates = {
614         'id'            => 'mp_templates',
615         'name'          => 'Minimum Profit template file',
616         'filenames'     => [ '/\.mp_templates$/' ],
617         'defs'          => [
618                 'documentation',        [ '/^%%.*$/m' ]
619         ],
620         'section'       => [ '/^%%/' ]
624 mp.syntax.hex_view = {
625         'id'            => 'hex_view',
626         'name'          => 'Hexadecimal view',
627         'defs'          => [
628                 'word1',                [ "/^\| [0-9A-F]+ \|/m" ],
629                 'word2',                [ "/\|/" ]
630         ]
634 mp.syntax.grutatxt = {
635         'id'            => 'grutatxt',
636         'name'          => 'Grutatxt',
637         'defs'          => [
638                 'word1',        [ "/[^\n]+\n[-=~]+\n/", "/ \* [^.\n:]+:/" ],
639                 'comments',     [ "/\b_[^ \t\n][^_\n]*[^ \t\n]_\b/" ],
640                 'word2',        [ "/\*[^ \t\n][^\*\n]*[^ \t\n]\*/" ],
641                 'quotes',       [ "/`[^ \t\n][^'\n]*[^ \t\n]'/" ]
642         ],
643         'section'       => [ "/^[-=~]+$/" ],
644         'detect'        =>      sub (d) {
645                 local n = 0;
647                 /* search the first lines for a heading */
648                 while (n < 40) {
649                         local l = d.txt.lines[n++];
651                         if (l == NULL)
652                                 break;
654                         if (regex("/^[-=~]+$/", l))
655                                 return 1;
656                 }
658                 return 0;
659         }
663 /** code **/
665 sub mp.detect_syntax(doc)
666 /* tries to detect the syntax of a document */
668         doc.syntax = NULL;
670         /* loops the syntax highlight definitions */
671         foreach (n, keys(mp.syntax)) {
672                 local s = mp.syntax[n];
674                 /* test the extensions */
675                 foreach (ext, s.filenames) {
676                         if (regex(ext, doc.name)) {
677                                 doc.syntax = s;
678                                 return;
679                         }
680                 }
681         }
683         /* not by extension? try the 'detect' subroutine */
684         foreach (n, keys(mp.syntax)) {
685                 local s = mp.syntax[n];
687                 if (is_exec(s.detect) && s.detect(doc)) {
688                         doc.syntax = s;
689                         return;
690                 }
691         }
695 sub mp.help(doc, word)
697         local h;
699         foreach (c, doc.syntax.help) {
700                 local f;
702                 /* format the command */
703                 c = sprintf(c, word);
705                 /* pipe from it */
706                 if ((f = popen(c, "r")) != NULL) {
707                         local l;
708                         h = [];
710                         while ((l = read(f)) != NULL)
711                                 push(h, mp.chomp(l));
713                         /* fails? */
714                         if (pclose(f) != 0)
715                                 h = NULL;
716                 }
718                 /* is there already help? don't look for more */
719                 if (h != NULL)
720                         break;
721         }
723         return h;
728  * mp.section_list - Returns the list of sections of a document.
729  * @doc: the document
731  * Applies the `section' array of regular expressions of the
732  * document's syntax definition and returns it as an array of
733  * line and line number pairs.
735  * If the document has no syntax highlight definition, or it has
736  * one without a `section' definition, NULL is returned. Otherwise,
737  * an array of line, line number pairs is returned (it can be
738  * an empty list if the document has no recognizable sections).
739  */
740 sub mp.section_list(doc)
742         local r;
744         if (doc.syntax.section) {
745                 local n, l;
747                 r = [];
749                 while ((l = doc.txt.lines[n]) != NULL) {
750                         foreach (ex, doc.syntax.section) {
751                                 if (regex(ex, l)) {
752                                         push(r, [ l, n ]);
753                                         break;
754                                 }
755                         }
757                         n++;
758                 }
759         }
761         return r;