Avoid asterisks in new C sections.
[mp-5.x.git] / mp_syntax.mpsl
blobcdaf048ceff92252b994f985a9c7f6cbf49ec791
1 /*
3     Minimum Profit 5.x
4     A Programmer's Text Editor
6     Syntax highlight definitions.
8     Copyright (C) 1991-2011 Angel Ortega <angel@triptico.com>
10     This program is free software; you can redistribute it and/or
11     modify it under the terms of the GNU General Public License
12     as published by the Free Software Foundation; either version 2
13     of the License, or (at your option) any later version.
15     This program is distributed in the hope that it will be useful,
16     but WITHOUT ANY WARRANTY; without even the implied warranty of
17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18     GNU General Public License for more details.
20     You should have received a copy of the GNU General Public License
21     along with this program; if not, write to the Free Software
22     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24     http://www.triptico.com
28 /** editor actions **/
30 sub mp.actions.help(d) {
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 sub mp.actions.section_list(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 pos = -1;
62             /* set pos to the section nearest the cursor */
63             foreach (e, l) {
64                 if (e[1] > d.txt.y)
65                     break;
67                 pos++;
68             }
70             if (pos < 0 || pos > size(l))
71                 pos = 0;
73             local r = mp.form(
74                 [
75                     {
76                         label:  L("Section list"),
77                         type:   'list',
78                         list:   map(l, sub (e) { e[0]; }),
79                         value:  pos
80                     }
81                 ]
82             );
84             if (r != NULL) {
85                 mp.search_set_y(d, l[r[0]][1]);
86                 mp.set_x(d, 0);
87             }
88         }
89     }
92 /** default key bindings **/
94 mp.keycodes['f1']       = "help";
95 mp.keycodes['ctrl-d']   = "section_list";
97 /** action descriptions **/
99 mp.actdesc['help']          = LL("Help on word over cursor");
100 mp.actdesc['section_list']  = LL("Section list...");
102 /** data **/
104 mp.syntax = {};
106 /** syntax definitions **/
108 sub mp.syn_token_list(l) { '/\b(' ~ join(l, "|") ~ ')\b/'; }
110 mp.syntax.c = {
111         'id'            =>      'c',
112         'name'          =>      'C / C++',
113         'filenames'     =>      [ '/\.c$/i', '/\.h$/i', '/\.l$/i', '/\.y$/i', '/\.d$/i',
114                                 '/\.cpp$/i', '/\.hpp$/i', '/\.c++$/i', '/\.cxx$/i', '/\.xpm$/i' ],
115         'help'          =>      [ "man 2 %s", "man 3 %s" ],
116         'defs'          =>      [
117                 'word1',        [
118                                 mp.syn_token_list( [
119                                 "auto", "break", "case", "catch", "class", "const", "const_cast",
120                                 "continue", "default", "delete", "do", "dynamic_cast", "else", "enum",
121                                 "explicit", "extern", "for", "friend", "goto", "if", "inline", "mutable",
122                                 "namespace", "new", "operator", "private", "protected", "public",
123                                 "register", "reinterpret_cast", "restrict", "return", "sizeof", "static",
124                                 "static_cast", "struct", "switch", "template", "this", "throw", "try",
125                                 "typedef", "typeid", "typename", "union", "using", "virtual", "volatile",
126                                 "while", "not", "not_eq", "xor", "xor_eq", "or",  "or_eq", "and", "and_eq",
127                                 "bitor", "bitand", "compl"
128                                 ])
129                 ],
130                 'word2',        [
131                                 mp.syn_token_list( [
132                                 "bool", "char", "double", "float", "int", "long", "short", "signed",
133                                 "unsigned", "wchar_t", "size_t", "ssize_t", "off_t", "wchar_t",
134                                 "ptrdiff_t", "void", "sig_atomic_t", "fpos_t", "clock_t", "time_t",
135                                 "va_list", "jmp_buf", "FILE", "DIR", "div_t", "ldiv_t", "mbstate_t",
136                                 "wctrans_t", "wint_t", "wctype_t", "complex", "int8_t", "int16_t",
137                                 "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t",
138                                 "int_least8_t", "int_least16_t", "int_least32_t", "int_least64_t",
139                                 "uint_least8_t", "uint_least16_t", "uint_least32_t", "uint_least64_t",
140                                 "int_fast8_t", "int_fast16_t", "int_fast32_t", "int_fast64_t",
141                                 "uint_fast8_t", "uint_fast16_t", "uint_fast32_t", "uint_fast64_t",
142                                 "intptr_t", "uintptr_t", "intmax_t", "uintmax_t"
143                                  ]),
144                                 '/[-=<>:\?\+\*\/\!\%&\|~\^\.]+/'
145                 ],
146                 'quotes',       [
147                         /* from http://ad.hominem.org/log/2005/05/quoted_strings.php */
148                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
149                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
150                         "/\b-?[0-9]+\b/",                       /* numbers */
151                         "/\b[0-9]+e[0-9]+\b/",                  /* numbers in exp format */
152                         "/\b0[0-7]+\b/",                        /* octal numbers */
153                         "/\b0x[0-9a-f]+\b/i",                   /* hex numbers */
154                         "/\b__(DATE|FILE|LINE|STDC|TIME|STDC_HOSTED|STDC_VERSION|func)__\b/", /* ISO macros */
155                         "/\b(true|false|NULL)\b/"           /* symbolic constant names */
156                 ],
157                 'comments',     [
158                         [ '|/\*|', '|\*/|' ],                   /* C-like */
159                         [ '|#if 0|', '#endif' ],                /* CPP "comments" */
160                         '|//.*$|m',                             /* C++ */
161                         '/^\s*#\s*[a-z]+/m'                     /* CPP directives */
162                 ],
163                 'documentation',        [
164                         [ "|/\*\*\n|", '|\*/|' ],               /* mp_doccer */
165                         '/^/\*\*.*\*\*/$/m'                     /* section mark */
166                 ]
167         ],
168         'section'       =>      [ '/(^\/\*\*.*\*\*\/$|^#pragma mark|^[A-Za-z_])/' ]
171 mp.syntax.rc = {
172         'id'            =>      'rc',
173         'name'          =>      'Resource file',
174         'filenames'     =>      [ '/\.rc$/i' ],
175         'defs'          =>      [
176                 'word1',        [ ],
177                 'word2',        [ ],
178                 'quotes',       [
179                         /* from http://ad.hominem.org/log/2005/05/quoted_strings.php */
180                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
181                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
182                         "/\b-?[0-9]+\b/",                       /* numbers */
183                         "/\b0x[0-9a-f]+\b/i",                   /* hex numbers */
184                         "/\b[0-9[:upper:]_]+\b/"                /* all-caps words */
185                 ],
186                 'comments',     [
187                         [ '|/\*|', '|\*/|' ],                   /* C-like */
188                         '|//.*$|m',                             /* C++ */
189                         '/^\s*#[a-z]+/m'                        /* CPP directives */
190                 ]
191         ]
194 mp.syntax.perl = {
195         'id'            =>      'perl',
196         'name'          =>      'Perl',
197         'filenames'     =>      [ '/\.pl$/i', '/\.pm$/i' ],
198         'help'          =>      [ 'perldoc -f %s', 'perldoc %s' ],
199         'help_word_regex' =>    '/[A-Z_][A-Z0-9_:]*/i',
200         'defs'  =>      [
201                 'word1',        [
202                                 mp.syn_token_list( [
203                                 "for", "if", "next", "last", "else", "elsif",
204                                 "unless", "while", "shift", "unshift", "push",
205                                 "pop", "delete", "new", "bless", "return",
206                                 "foreach", "keys", "values", "sort", "grep",
207                                 "tr", "length", "system", "exec", "fork", "map",
208                                 "print", "write", "open", "close", "chop",
209                                 "chomp", "exit", "sleep", "split", "join",
210                                 "sub", "printf", "sprintf", "s", "glob",
211                                 "scalar", "my", "local", "undef", "defined",
212                                 "use", "package", "require", "ref", "can", "isa",
213                                 "qw", "qq", "eq", "ne", "or", "exists",
214                                 "and", "not", "import", "our", "caller" ]),
215                                 '/->/'
216                 ],
217                 'word2',        [
218                                 '/[:\?\+\*\/\!\$@\%&\|~\.]+/',
219                                 '/[\$@%]\w+/'
220                 ],
221                 'quotes',       [
222                         /* from http://ad.hominem.org/log/2005/05/quoted_strings.php */
223                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
224                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
225                         "/\b-?[0-9]+\b/",                       /* numbers */
226                         "/\b0x[0-9a-f]+\b/i",                   /* hex numbers */
227                         "/\b[0-9[:upper:]_]+\b/",               /* all-caps words */
228                         [ "/q\(/", "/\)/" ],                    /* quote */
229                         [ "/qw\(/", "/\)/" ],                   /* quote word */
230                         '/\w+\s*=>/',                           /* barewords as hash keys 1 */
231                         '/\{\s*-?\w+\s*\}/',                    /* barewords as hash keys 2 */
232                         [ "/`/", "/`/" ],                       /* backticks */
233                         [ "/<<[\"']?EOF.*$/m", "/^EOF$/m" ]     /* 'document here' */
234                 ],
235                 /* color all => as word2 */
236                 'word2',        [ '/=>/' ],
237                 /* color curly brackets as word */
238                 'word',         [ '/[{}]/' ],
239                 'comments',     [
240                         "/#.*$/m"                               /* Comments */
241                 ],
242                 'documentation',        [
243                         "/__END__\n.*$/",                       /* __END__ */
244                         '/^## .*$/m',                           /* section mark */
245                         [ "/^=(head[1-4]|over|item|back|pod|begin|end|for)/m",
246                                 "/^=cut$/m" ]                   /* POD */
247                 ]
248         ],
249         'detect'        =>      sub (d) {
250                 /* take the first line */
251                 local f = d.txt.lines[0];
253                 /* is it a 'she-bang' for Perl? */
254                 return regex(f, '/^#!\s*/usr/bin/(env )?perl/');
255         },
256         'section'       =>      [ '/(^sub \w+|^package|^## )/' ]
260 mp.syntax.mpsl = {
261         'id'            =>      'mpsl',
262         'name'          =>      'MPSL',
263         'filenames'     =>      [ '/\.mpsl?$/i' ],
264         'defs'          =>      [
265                 'word1',        [
266                                 mp.syn_token_list( [
267                                         'if', 'else', 'while', 'foreach',
268                                         'sub', 'break', 'return', 'eq', 'ne' ]),
269                                 mp.syn_token_list( keys(MPSL.CORE) ),
270                                 '/[\{\}]/'
271                 ],
272                 'word2',        [
273                                 "/(NULL|local)/",
274                                 '/[-=<>\?\+\*\/\!\%&\|]+/'
275                 ],
276                 'quotes',       [
277             /* from http://ad.hominem.org/log/2005/05/quoted_strings.php */
278             "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/", /* double-quoted strings */
279             "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",     /* single-quoted strings */
280             "/\b-?[0-9]+\b/",                           /* numbers */
281             "/\b0x[0-9a-f]+\b/i",                       /* hex numbers */
282             '/\w+\s*:/',                                /* JS-type hashes */
283             "/\b[0-9[:upper:]_]+\b/"                    /* all-caps words */
284         ],
285         'word2',    [
286             '/:/'
287         ],
288                 'comments',     [
289                         [ '|/\*|', '|\*/|' ]                    /* C-like */
290                 ],
291                 'documentation',        [
292                         [ "|/\*\*\n|", '|\*/|' ],               /* mp_doccer */
293                         '/^/\*\*.*\*\*/$/m'                     /* section mark */
294                 ]
295         ],
296         'section'       =>      [ '/(^[A-Za-z_]|^\/\*\*.*\*\*\/$)/' ]
299 mp.syntax.sh = {
300         'id'            =>      'sh',
301         'name'          =>      'Shell script',
302         'filenames'     =>      [ '/\.sh$/i', '/makefile/i' ],
303         'defs'          =>      [
304                 'word1',        [
305                                 mp.syn_token_list( [
306                                 "if", "then", "else", "elif",
307                                 "fi", "case", "do", "done", "esac",
308                                 "for", "until", "while", "break",
309                                 "in", "source", "alias", "cd",
310                                 "continue", "echo", "eval", "exec",
311                                 "exit", "export", "kill", "logout",
312                                 "printf", "pwd", "read", "return",
313                                 "shift", "test", "trap", "ulimit",
314                                 "umask", "unset", "wait", "cp", "rm" ]),
315                                 '/[\{\}]/'
317                 ],
318                 'word2',        [
319                                 '/\b(local|let|set)\b/',
320                                 '/[-=<>:\?\+\*\!\%&\|]+/',
321                                 '/\$\w+/',
322                                 '/\$\{\w+\}/',
323                                 "/\b[0-9[:upper:]_]+\b/"        /* all-caps words */
324                 ],
325                 'quotes',       [
326                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
327                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
328                         "/\b-?[0-9]+\b/",                       /* numbers */
329                         "/\b0x[0-9a-f]+\b/i",                   /* hex numbers */
330                         "/\([A-Za-z0-9_]+\)/",                  /* parens */
331                         [ "/`/", "/`/" ],                       /* backticks */
332                         [ "/<<[\"']?EOF[\"']?;$/m", "/^EOF$/m" ]        /* 'document here' */
333                 ],
334                 'comments',     [ "/#.*$/m" ]
335         ],
336         'detect'        =>      sub (d) {
337                 /* take the first line */
338                 local f = d.txt.lines[0];
340                 /* is it a 'she-bang' for usual shells? */
341                 return regex(f, '/^#!\s*/bin/(sh|bash|csh|dash|ksh)/') ||
342                        regex(f, '/^#!\s*/usr/bin/make -f/');
343         },
344         'section'       =>      [ '/(^\w+\(\))/', '/^[A-Za-z0-9_\.-]+:/' ]
348 mp.syntax.html = {
349         'id'            =>      'html',
350         'name'          =>      'HTML',
351         'filenames'     =>      [ '/\.html$/i', '/\.htm$/i' ],
352         'defs'          =>      [
353                 'word1',        [
354                                 "/<[\/]?[ \t]*(" ~
355                                 join([
356                                 "a", "abbr", "acronym", "address",
357                                 "area", "b", "base", "bdo", "big",
358                                 "blockquote", "body", "br", "button",
359                                 "caption", "center", "cite", "code", "col",
360                                 "colgroup", "dd", "del", "dfn", "div",
361                                 "dl", "dt", "em", "fieldset", "form",
362                                 "h1", "h2", "h3", "h4", "h5", "h6",
363                                 "head", "hr", "html", "i", "img",
364                                 "input", "ins", "kbd", "label", "legend",
365                                 "li", "link", "map", "meta", "noscript",
366                                 "object", "ol", "optgroup", "option",
367                                 "p", "param", "pre", "q", "samp",
368                                 "script", "select", "small", "span",
369                                 "strong", "style", "sub", "sup", "table",
370                                 "tbody", "td", "textarea", "tfoot", "th",
371                                 "thead", "title", "tr", "tt", "ul",
372                                 "var" ], "|") ~
373                                 ")[^<>]*>/i"
374                 ],
375                 'word2',        [
376                                 mp.syn_token_list( [
377                                  "!DOCTYPE", "class", "type",
378                                 "cellspacing", "cellpadding",
379                                 "href", "align", "valign", "name", "lang",
380                                 "value", "action", "width", "height",
381                                 "content", "http-equiv", "src", "alt",
382                                 "bgcolor", "text", "link", "vlink", "alink",
383                                 "media" ])
384                 ],
385                 'quotes',       [
386                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
387                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/"          /* single-quoted strings */
388                 ],
389                 'comments',     [
390                                 [ '/<!--/', '/-->/' ]
391                 ]
392         ],
393         'section'       =>      [ '/<\s*h[0-9]\s*>/' ]
397 mp.syntax.conf = {
398         'id'            =>      'conf',
399         'name'          =>      'Config file',
400         'filenames'     =>      [ '/\.conf$/i', '/\.cfg$/i', '/^.*\/?\.[0-9a-z_-]+rc$/i' ],
401         'defs'          =>      [
402                 'word1',        [ '/^\[.+\]$/m' ],
403                 'word2',        [ "/^[^:=\n]+[:=]/m" ],
404                 'quotes',       [
405                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
406                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
407                         "/\b-?[0-9]+\b/",                       /* numbers */
408                         "/\b0x[0-9a-f]+\b/i"                    /* hex numbers */
409                 ],
410                 'comments',     [ "/#.*$/m" ]
411         ]
415 mp.syntax.php = {
416         'id'            =>      'php',
417         'name'          =>      'PHP',
418         'filenames'     =>      [ '/\.php[345]?$/i', '/\.inc$/i' ],
419         'defs'          =>      [
420                 'word1',        [
421                                 mp.syn_token_list( [
422                                 "and", "array", "as",
423                                 "bool", "boolean", "break", "case", "class",
424                                 "const", "continue", "declare", "default",
425                                 "die", "do", "double", "echo", "else", "elseif",
426                                 "empty", "enddeclare", "endfor", "endforeach",
427                                 "endif", "endswitch", "endwhile", "eval",
428                                 "exit", "extends", "__FILE__", "float", "for",
429                                 "foreach", "function", "cfunction", "global",
430                                 "if", "include", "include_once", "int",
431                                 "integer", "isset", "__LINE__", "list", "new",
432                                 "object", "old_function", "or", "print", "real",
433                                 "require", "require_once", "return",
434                                 "static", "string", "switch", "unset", "use",
435                                 "var", "while", "xor", 'true', 'false' ]
436                                 )
437                 ],
438                 'word2',        [ '/\$\w+/', '/[-=<>:\?\+\*\!\%&\|]+/' ],
439                 'quotes',       [
440                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
441                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
442                         "/\b-?[0-9]+\b/",                       /* numbers */
443                         "/\b0x[0-9a-f]+\b/i",                   /* hex numbers */
444                         "/\b[0-9[:upper:]_]+\b/",               /* all-caps words */
445                         [ "/`/", "/`/" ]                        /* backticks */
446                 ],
447                 'comments',     [
448                         [ '|/\*|', '|\*/|' ],                   /* C-like */
449                         '|//.*$|m'                              /* C++ */
450                 ]
451         ]
454 mp.syntax.python = {
455         'id'            =>      'python',
456         'name'          =>      'Python',
457         'filenames'     =>      [ '/\.py$/i' ],
458         'defs'          =>      [
459                 'word1',        [
460                         mp.syn_token_list( [
461                                 "and", "assert", "break", "class", "continue",
462                                 "def", "del", "elif", "else", "except", "exec",
463                                 "finally", "for", "from", "if", "import", "in",
464                                 "is", "lambda", "not", "or", "pass", "print",
465                                 "raise", "return", "try", "while", "yield"
466                                 ]
467                         )
468                 ],
469                 'word2',        [ '/global/', '/\$\w+/', '/[-=<>:\?\+\*\!\%&\|{}]+/' ],
470                 'quotes',       [
471                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
472                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
473                         "/\b-?[0-9]+\b/",                       /* numbers */
474                         "/\b0x[0-9a-f]+\b/i",                   /* hex numbers */
475                         "/\b[0-9[:upper:]_]+\b/",               /* all-caps words */
476                         [ "/`/", "/`/" ]                        /* backticks */
477                 ],
478                 'comments',             [ "/#.*$/m" ],
479                 'documentation',        [ [ '/""".+[^"]$/m', '/"""$/m' ] ]
480         ],
481         'detect'        =>      sub (d) {
482                 /* take the first line */
483                 local f = d.txt.lines[0];
485                 /* is it a 'she-bang'? */
486                 return regex(f, '/^#!\s*/usr/bin/(env )?python/');
487         },
488         'section'       =>      [ '/^[ \t]*def/' ]
491 mp.syntax.ruby = {
492         'id'            =>      'ruby',
493         'name'          =>      'Ruby',
494         'filenames'     =>      [ '/\.rb$/i' ],
495         'defs'          =>      [
496                 'word1',        [
497                         mp.syn_token_list( [
498                                 "BEGIN", "END", "alias", "and", "begin",
499                                 "break", "case", "class", "def", "defined",
500                                 "do", "else", "elsif", "end", "ensure",
501                                 "false", "for", "if", "in", "module", "next",
502                                 "nil", "not", "or", "redo", "rescue", "retry",
503                                 "return", "self", "super", "then", "true",
504                                 "undef", "unless", "until", "when", "while",
505                                 "yield", "require", "include" ]
506                         )
507                 ],
508                 'word2',        [ '/[-=<>:\?\+\*\!\%&\|{}]+/', '/=(begin|end)/' ],
509                 'quotes',       [
510                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
511                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",         /* single-quoted strings */
512                         "/\b-?[0-9]+\b/",                       /* numbers */
513                         "/\b0x[0-9a-f]+\b/i",                   /* hex numbers */
514                         "/\b[0-9[:upper:]_]+\b/",               /* all-caps words */
515                         [ "/`/", "/`/" ]                        /* backticks */
516                 ],
517                 'comments',     [ "/#.*$/m" ]
518         ],
519         'detect'        =>      sub (d) {
520                 /* take the first line */
521                 local f = d.txt.lines[0];
523                 /* is it a 'she-bang'? */
524                 return regex(f, '/^#!\s*/usr/bin/(env )?ruby/');
525         }
528 mp.syntax.diff = {
529         'id'            =>      'diff',
530         'name'          =>      'diff',
531         'filenames'     =>      [ '/\.diff$/i', '/\.patch$/i' ],
532         'defs'          =>      [
533                 'word1',        [ '/^\+.+$/m' ],
534                 'word2',        [ '/^\-.+$/m' ],
535                 'quotes',       [ '/^@@.+@@.*$/m' ]
536         ],
537         'section'       =>      [ '/^--- ', '/^@@/' ]
540 mp.syntax.commit_msg = {
541         'id'            =>      'commit_msg',
542         'name'          =>      'VCS commit message',
543         'filenames'     =>      [ '/sv[kn]-commit.*\./' ],
544         'defs'          =>      [
545                 'word1',        [ '/^AM? .+$/m' ],
546                 'word2',        [ '/^D .+$/m' ],
547                 'quotes',       [ '/^M .+$/m' ],
548                 'comments',     [ '/^=== .+$/m', '/^--.+$/m' ]
549         ]
552 mp.syntax.po = {
553         'id'            =>      'po',
554         'name'          =>      'Gettext file',
555         'filenames'     =>      [ '/\.po$/i' ],
556         'defs'          =>      [
557                 'word1',        [ '/^msgid/m' ],
558                 'word2',        [ '/^msgstr/m' ],
559                 'comments',     [ "/#.*$/m" ],
560                 'quotes',       [
561                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/"      /* double-quoted strings */
562                 ]
563         ]
566 mp.syntax.xml = {
567         'id'            =>      'xml',
568         'name'          =>      'XML / XGML',
569         'filenames'     =>      [ '/\.xml$/i', '/\.sgml$/i' ],
570         'defs'          =>      [
571                 'word1',        [ '/<[^>]+>/' ],
572                 'word2',        [ '/<\?[^\?]+\?>/' ],
573                 'quotes',       [
574                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",     /* double-quoted strings */
575                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/"          /* single-quoted strings */
576                 ],
577                 'comments',     [
578                                 [ '/<!--/', '/-->/' ]
579                 ]
580         ],
581         'detect'        =>      sub (d) {
582                 /* take the first line */
583                 local f = d.txt.lines[0];
585                 return regex(f, '/<\?xml/');
586         }
589 mp.syntax.make_output = {
590         'id'            =>      'make_output',
591         'name'          =>      'Make output',
592         'defs'          =>      [
593                 'word1',        [ "/^.*warning:.*$/m" ],
594                 'word2',        [ "/^.*error:.*$/m" ]
595         ]
598 mp.syntax.euphoria = {
599         'id'            =>      'euphoria',
600         'name'          =>      'euphoria',
601         'filenames'     =>      [ '/\.e$/', '/\.eu$/', '/\.ew$/', '/\.ed$/',
602                                 '/\.ex$/', '/\.exw$/', '/\.exu$/' ],
603         'defs'          =>      [
604                 'word1',        [
605                         mp.syn_token_list( [
606                                 "as", "and", "break", "by", "case", "constant", "continue", "do", "end",
607                                 "else", "elsif", "elsifdef",
608                                 "exit", "entry", "enum", "export", "for", "function", "global", "include",
609                                 "if", "ifdef", "label",
610                                 "not", "or", "procedure", "return", "retry", "switch", "then", "type",
611                                 "to", "while", "with", "without", "xor"
612                         ] )
613                 ],
614                 'word2',        [
615                         mp.syn_token_list( [
616                                 "atom", "integer", "sequence", "object"
617                         ] )
618                 ],
619                 'quotes',       [
620                         "/\"([^\"\\\\\n]*(\\\\.[^\"\\\\\n]*)*)\"/",    /* double-quoted strings */
621                         "/'([^'\\\\\n]*(\\\\.[^'\\\\\n]*)*)'/",        /* single-quoted strings */
622                         "/\b-?#[0-9A-F]+\b/",                /* hex numbers */
623                         "/\b-?[0-9]+\b/",                /* numbers */
624                         "/\b[0-9[:upper:]_]+\b/"            /* all-caps words */
625                 ],
626                 'comments',             [ "/--.*$/m" ]
627         ],
628         'section'       =>      [ '/^[ \t]*(global|export)*[ \t]*(function|procedure)/' ]
632 mp.syntax.mp_templates = {
633         'id'            => 'mp_templates',
634         'name'          => 'Minimum Profit template file',
635         'filenames'     => [ '/\.mp_templates$/' ],
636         'defs'          => [
637                 'documentation',        [ '/^%%.*$/m' ]
638         ],
639         'section'       => [ '/^%%/' ]
643 mp.syntax.hex_view = {
644         'id'            => 'hex_view',
645         'name'          => 'Hexadecimal view',
646         'defs'          => [
647                 'word1',                [ "/^\| [0-9A-F]+ \|/m" ],
648                 'word2',                [ "/\|/" ]
649         ]
653 mp.syntax.grutatxt = {
654         'id'            => 'grutatxt',
655         'name'          => 'Grutatxt',
656         'defs'          => [
657                 'word1',        [ "/[^\n]+\n[-=~]+\n/", "/ \* [^.\n:]+:/" ],
658                 'comments',     [ "/\b_[^ \t\n][^_\n]*[^ \t\n]_\b/" ],
659                 'word2',        [ "/\*[^ \t\n][^\*\n]*[^ \t\n]\*/" ],
660                 'quotes',       [ "/`[^ \t\n][^'\n]*[^ \t\n]'/" ]
661         ],
662         'section'       => [ "/^[-=~]+$/" ],
663         'detect'        =>      sub (d) {
664                 local n = 0;
666                 /* search the first lines for a heading */
667                 while (n < 40) {
668                         local l = d.txt.lines[n++];
670                         if (l == NULL)
671                                 break;
673                         if (regex(l, "/^[-=~]+$/"))
674                                 return 1;
675                 }
677                 return 0;
678         }
682 /** code **/
684 sub mp.detect_syntax(doc)
685 /* tries to detect the syntax of a document */
687         doc.syntax = NULL;
689         /* loops the syntax highlight definitions */
690         foreach (n, keys(mp.syntax)) {
691                 local s = mp.syntax[n];
693                 /* test the extensions */
694                 foreach (ext, s.filenames) {
695                         if (regex(doc.name, ext)) {
696                                 doc.syntax = s;
697                                 return;
698                         }
699                 }
700         }
702         /* not by extension? try the 'detect' subroutine */
703         foreach (n, keys(mp.syntax)) {
704                 local s = mp.syntax[n];
706                 if (is_exec(s.detect) && s.detect(doc)) {
707                         doc.syntax = s;
708                         return;
709                 }
710         }
714 sub mp.help(doc, word)
716         local h;
718         foreach (c, doc.syntax.help) {
719                 local f;
721                 /* format the command */
722                 c = sprintf(c, word);
724                 /* pipe from it */
725                 if ((f = popen(c, "r")) != NULL) {
726                         local l;
727                         h = [];
729                         while ((l = read(f)) != NULL)
730                                 push(h, mp.chomp(l));
732                         /* fails? */
733                         if (pclose(f) != 0)
734                                 h = NULL;
735                 }
737                 /* is there already help? don't look for more */
738                 if (h != NULL)
739                         break;
740         }
742         return h;
747  * mp.section_list - Returns the list of sections of a document.
748  * @doc: the document
750  * Applies the `section' array of regular expressions of the
751  * document's syntax definition and returns it as an array of
752  * line and line number pairs.
754  * If the document has no syntax highlight definition, or it has
755  * one without a `section' definition, NULL is returned. Otherwise,
756  * an array of line, line number pairs is returned (it can be
757  * an empty list if the document has no recognizable sections).
758  */
759 sub mp.section_list(doc)
761     local r;
763     if (doc.syntax.section) {
764         local n, l;
766         r = [];
768         while ((l = doc.txt.lines[n]) != NULL) {
769             foreach (ex, doc.syntax.section) {
770                 if (regex(l, ex)) {
771                     push(r, [ l, n ]);
772                     break;
773                 }
774             }
776             n++;
777         }
778     }
780     return r;