Added enscript.st
[tpope-extra.git] / enscript / enscript / hl / enscript.st
1 /* This file is a slightly modified version of the file of the same name
2  * included with enscript.  The primary change was recognizing a few more
3  * -*- filetype -*- patterns in startrules. */
4
5 /*
6  * States definitions file for GNU Enscript.
7  * Copyright (c) 1997-2003 Markku Rossi.
8  * Author: Markku Rossi <mtr@iki.fi>
9  *
10  * The latest version of this file can be downloaded from URL:
11  *
12  *     http://www.iki.fi/~mtr/genscript/enscript.st
13  */
14
15 /*
16  * This file is part of GNU enscript.
17  *
18  * This program is free software; you can redistribute it and/or modify
19  * it under the terms of the GNU General Public License as published by
20  * the Free Software Foundation; either version 2, or (at your option)
21  * any later version.
22  *
23  * This program is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  * GNU General Public License for more details.
27  *
28  * You should have received a copy of the GNU General Public License
29  * along with this program; see the file COPYING.  If not, write to
30  * the Free Software Foundation, 59 Temple Place - Suite 330,
31  * Boston, MA 02111-1307, USA.
32  */
33
34 /*
35  * $Id$
36  */
37
38 /*
39  * Guildelines for writing new highlighting rules for the GNU Enscript.
40  *
41  * - all highlighting states should have a document comment like this:
42  *
43  *   /**
44  *    * Name: c
45  *    * Description: C programming language.
46  *    * Author: Author Name <author@email.address>
47  *    * ...
48  *
49  *   It is used by enscript's --help-pretty-print option to print
50  *   description about supported highlighting modes.
51  *
52  * - the main entry state (for example, for the C, the state `c') must
53  *   be inherited from state `HighlightEntry':
54  *
55  *   state c extends HighlightEntry
56  *   {
57  *     ...
58  *
59  * - all help-states smust be inherited from state `Highlight':
60  *
61  *   state c_string extends Highlight
62  *   {
63  *     ...
64  *
65  * - all printing should be done with the language_print() procedure
66  *   instead of the print() primitive.
67  *
68  * - using enscript.el to build regular expressions:
69  *
70  *      M-x load-file RET enscript.el RET
71  *
72  *   Move in the buffer to the point where the (build-re '()) ends,
73  *   that is, after the last closing parenthesis ')'.  Then, type:
74  *
75  *      C-x C-e
76  *
77  *   Magic should happen.
78  *
79  * These rules ensures that enscript's --help-pretty-print option and
80  * the different output languages (HTML, RTF, etc.) work.
81  */
82 \f
83 /* This script needs at least this version of the States program. */
84 prereq ("1.6.2");
85
86 /*
87  * Constants, fonts, etc.
88  */
89
90 debug = "0";
91
92 /* Boolean values. */
93 true = 1;
94 false = 0;
95
96 font_spec = "Courier@10";
97
98 /* These components are resolved from <font_spec>. */
99 font = "";
100 ptsize = "";
101
102 /*
103  * Generatel table of contents?  This is not supported by all output
104  * languages.
105  */
106 toc = "0";
107
108 /*
109  * The Highlight style.  The default style is `emacs' to imitate
110  * Emacs' font lock mode.
111  */
112 style = "emacs";
113
114 /*
115  * Create color outputs?
116  */
117 color = "1";
118
119 /*
120  * Use verbose highlighting rules?
121  */
122 verbose_highlighting = false;
123
124 /*
125  * Target language.  Possible values are:
126  * - enscript           generate enscript special escapes
127  * - html               generate HTML
128  * - overstrike         generate overstrike (line printers, less)
129  * - texinfo            generate Texinfo
130  * - rtf                generate Rich Text Format (rtf - MS Word, WordPerfect)
131  *                      This code can be souched into MS Word or PowerPoint
132  *                      for a pretty version of the code
133  */
134 language = "enscript";
135
136 /*
137  * How many input files we have.
138  */
139 num_input_files = "1";
140 current_input_file = 0;
141
142 /*
143  * Document title.
144  */
145 document_title = "Enscript Output";
146
147 /*
148  * Global variables for nested highlighting `nested.st'.
149  */
150 nested_start = "^-+(([ \t]*)([a-zA-Z_0-9]*)([ \t]*))-+$";
151 nested_start_re = 0;
152 nested_end = "^-+$";
153 nested_end_re_cached = 0;
154 nested_end_re = 0;
155 nested_default = "passthrough";
156
157 /*
158  * Color definitions.
159  */
160
161 cindex = 0;
162 rgb_values = list ();
163
164 sub define_color (name, r, g, b)
165 {
166   rgb_values[cindex] = list (name, r, g, b);
167   cindex = cindex + 1;
168 }
169
170 sub color_index (name)
171 {
172   local i;
173
174   for (i = 0; i < length (rgb_values); i = i + 1)
175     if (strcmp (rgb_values[i][0], name) == 0)
176       return i;
177
178   return -1;
179 }
180
181 sub language_color (name)
182 {
183   local idx;
184
185   idx = color_index (name);
186   if (idx < 0)
187     panic ("unknown color `", name, "'");
188
189   /*
190    * The map_color() subroutine is language specific and defined in
191    * *_faces() subroutine.
192    */
193   map_color (rgb_values[idx][1], rgb_values[idx][2], rgb_values[idx][3]);
194 }
195
196 /* RGB definitions for colors.  These are borrowed from X's rgb.txt file. */
197
198 define_color ("black",                  0, 0, 0);
199 define_color ("gray25",                 64, 64, 64);
200 define_color ("gray50",                 127, 127, 127);
201 define_color ("gray75",                 191, 191, 191);
202 define_color ("gray85",                 217, 217, 217);
203 define_color ("gray90",                 229, 229, 229);
204 define_color ("gray95",                 242, 242, 242);
205 define_color ("blue",                   0, 0, 255);
206 define_color ("cadet blue",             95, 158, 160);
207 define_color ("dark goldenrod",         184, 134, 11);
208 define_color ("dark olive green",       85, 107, 47);
209 define_color ("firebrick",              178, 34, 34);
210 define_color ("forest green",           34, 139, 34);
211 define_color ("green",                  0, 255, 0);
212 define_color ("orchid",                 218, 112, 214);
213 define_color ("purple",                 160, 32, 240);
214 define_color ("red",                    255, 0, 0);
215 define_color ("rosy brown",             188, 143, 143);
216
217 define_color ("DarkSeaGreen",           143, 188, 143);
218 define_color ("DarkSeaGreen1",          193, 255, 193);
219 define_color ("DarkSeaGreen2",          180, 238, 180);
220 define_color ("DarkSeaGreen3",          155, 205, 155);
221 define_color ("DarkSeaGreen4",          105, 139, 105);
222 define_color ("Goldenrod",              237, 218, 116);
223 define_color ("Aquamarine",             67, 183, 186);
224 define_color ("SeaGreen2",              100, 233, 134);
225 define_color ("Coral",                  247, 101,  65);
226 define_color ("DarkSlateGray1",         154, 254, 255);
227 define_color ("LightGrey",              211, 211, 211);
228
229
230 /*
231  * General helpers.
232  */
233
234 sub debug (msg)
235 {
236   if (debug_level)
237     print ("DEBUG: ", msg, "\n");
238 }
239
240 sub is_prefix (prefix, string)
241 {
242   return strncmp (prefix, string, length (prefix)) == 0;
243 }
244
245 sub strchr (string, ch)
246 {
247   local len = length (string), i;
248
249   for (i = 0; i < len; i = i + 1)
250     if (string[i] == ch)
251       return i;
252
253   return -1;
254 }
255
256 sub need_version (major, minor, beta)
257 {
258   local r, v, i;
259
260   regmatch (version, (/([0-9]+)\.([0-9]+)\.([0-9]+)/));
261   v = list (int ($1), int ($2), int ($3));
262   r = list (major, minor, beta);
263
264   for (i = 0; i < 3; i = i + 1)
265     if (v[i] > r[i])
266       return 1;
267     else if (v[i] < r[i])
268       return 0;
269
270   /* Exact match. */
271   return 1;
272 }
273
274 /* Highlight types which match expression <re> from string <data>. */
275 sub highlight_types (data, re)
276 {
277   local match_len;
278
279   while (regmatch (data, re))
280     {
281       language_print ($B);
282       type_face (true);
283       language_print ($0);
284       type_face (false);
285
286       match_len = length ($B, $0);
287
288       data = substring (data, match_len, length (data));
289     }
290
291   language_print (data);
292 }
293
294 \f
295 /*
296  * The supported faces.  These functions are used in the highlighting
297  * rules to mark different logical elements of the code.  The
298  * different faces and their properties (face_*) are defined in the
299  * style definition files.  The face_on() and face_off() functions are
300  * defined in the output language definition files.
301  */
302
303 sub bold (on)
304 {
305   if (on)
306     face_on (face_bold);
307   else
308     face_off (face_bold);
309 }
310
311 sub italic (on)
312 {
313   if (on)
314     face_on (face_italic);
315   else
316     face_off (face_italic);
317 }
318
319 sub bold_italic (on)
320 {
321   if (on)
322     face_on (face_bold_italic);
323   else
324     face_off (face_bold_italic);
325 }
326
327 sub comment_face (on)
328 {
329   if (on)
330     face_on (face_comment);
331   else
332     face_off (face_comment);
333 }
334
335 sub function_name_face (on)
336 {
337   if (on)
338     face_on (face_function_name);
339   else
340     face_off (face_function_name);
341 }
342
343 sub variable_name_face (on)
344 {
345   if (on)
346     face_on (face_variable_name);
347   else
348     face_off (face_variable_name);
349 }
350
351 sub keyword_face (on)
352 {
353   if (on)
354     face_on (face_keyword);
355   else
356     face_off (face_keyword);
357 }
358
359 sub reference_face (on)
360 {
361   if (on)
362     face_on (face_reference);
363   else
364     face_off (face_reference);
365 }
366
367 sub string_face (on)
368 {
369   if (on)
370     face_on (face_string);
371   else
372     face_off (face_string);
373 }
374
375 sub builtin_face (on)
376 {
377   if (on)
378     face_on (face_builtin);
379   else
380     face_off (face_builtin);
381 }
382
383 sub type_face (on)
384 {
385   if (on)
386     face_on (face_type);
387   else
388     face_off (face_type);
389 }
390
391 sub highlight_face (on)
392 {
393   if (on)
394     face_on (face_highlight);
395   else
396     face_off (face_highlight);
397 }
398
399 \f
400 /*
401  * Initializations.
402  */
403
404 start
405 {
406   /* Set debug level. */
407   debug_level = int (debug);
408
409   /* Use colors? */
410   color = int (color);
411
412   /* Increment input file count. */
413   current_input_file = current_input_file + 1;
414
415   /* Resolve fonts. */
416   idx = strchr (font_spec, '@');
417   if (idx < 0)
418     panic ("malformed font spec: `", font_spec, "'");
419
420   font = substring (font_spec, 0, idx);
421   ptsize = substring (font_spec, idx + 1, length (font_spec));
422
423   debug (concat ("start: ", font, "@", ptsize));
424
425   /* Construct bold, italic, etc. fonts for our current body font. */
426   if (is_prefix ("AvantGarde", font))
427     {
428       bold_font = "AvantGarde-Demi";
429       italic_font = "AvantGarde-BookOblique";
430       bold_italic_font = "AvantGarde-DemiOblique";
431     }
432   else if (regmatch (font, /^Bookman|Souvenir/))
433     {
434       bold_font = concat ($0, "-Demi");
435       italic_font = concat ($0, "-LightItalic");
436       bold_italic_font = concat ($0, "-DemiItalic");
437     }
438   else if (regmatch (font, /^Lucida(Sans-)?Typewriter/))
439     {
440       bold_font = concat ($0, "Bold");
441       italic_font = concat ($0, "Oblique");
442       bold_italic_font = concat ($0, "BoldOblique");
443     }
444   else if (regmatch (font, /^(.*)-Roman$/))
445     {
446       bold_font = concat ($1, "-Bold");
447       italic_font = concat ($1, "-Italic");
448       bold_italic_font = concat ($1, "-BoldItalic");
449     }
450   else
451     {
452       bold_font = concat (font, "-Bold");
453       italic_font = concat (font, "-Oblique");
454       bold_italic_font = concat (font, "-BoldOblique");
455     }
456
457   /* Create regular expressions for nested highlighting. */
458   nested_start_re = regexp (nested_start);
459   nested_end_re_cached = regexp (nested_end);
460
461   /* Define output faces. */
462   calln (concat ("lang_", language));
463
464   /* Define our highlight style. */
465   calln (concat ("style_", style));
466
467   /* Resolve start state. */
468   if (check_startrules ())
469     debug ("startstate from startrules");
470   if (check_namerules ())
471     debug ("startstate from namerules");
472 }
473
474 namerules
475 {
476   /\.(c|h)$/                                    c;
477   /\.(c++|C|H|cpp|cc|cxx)$/                     cpp;
478   /\.m$/                                        matlab;
479   /\.(mpl|mp|maple)$/                           maple;
480   /\.(scm|scheme)$/                             scheme;
481   /\b\.emacs$|\.el$/                            elisp;
482   /\.ad(s|b|a)$/                                ada;
483   /\.[Ss]$/                                     asm;
484   /\.st$/                                       states;
485   /(M|m)akefile.*/                              makefile;
486   /\.(MOD|DEF|mi|md)$/                          modula_2;
487   /\.tcl$/                                      tcl;
488   /\.(v|vh)$/                                   verilog;
489   /\.html?$/                                    html;
490   /\bChangeLog$/                                changelog;
491   /\.(vhd|vhdl)$/                               vhdl;
492   /\.(scr|.syn|.synth)$/                        synopsys;
493   /\.idl$/                                      idl;
494   /\.(hs|lhs|gs|lgs)$/                          haskell;
495   /\.(pm|pl)$/                                  perl;
496   /\.(eps|EPS|ps|PS)$/                          postscript;
497   /\.py$/                                       python;
498   /\.pyx$/                                      pyrex;
499   /\.js$/                                       javascript;
500   /\.java$/                                     java;
501   /\.([Pp][Aa][Ss]|[Pp][Pp]|[Pp])$/             pascal;
502   /\.[fF]$/                                     fortran;
503   /\.awk$/                                      awk;
504   /\.sh$/                                       sh;
505   /\.vba$/                                      vba;
506   /\.(cshrc|login|logout|history|csh)$/         csh;
507   /\.tcshrc$/                                   tcsh;
508   /\.(zshenv|zprofile|zshrc|zlogin|zlogout)$/   zsh;
509   /\.(bash_profile|bashrc|inputrc)$/            bash;
510   /\.m4$/                                       m4;
511   /\.il$/                                       skill;
512   /\.wrl$/                                      vrml;
513   /\b(rfc.*\.txt|draft-.*\.txt)$/               rfc;
514   /\.inf$/i                                     inf;
515   /\.tex$/                                      tex;
516   /\.wmlscript$/                                wmlscript;
517   /\.wmls$/                                     wmlscript;
518   /^.*$/                                        passthrough;
519 }
520
521 startrules
522 {
523   /.\010.\010.\010./                                    nroff;
524   /-\*- [Cc] -\*-/                                      c;
525   /-\*- [Cc]\+\+ -\*-/                                  cpp;
526   /-\*- [Aa][Dd][Aa] -\*-/                              ada;
527   /-\*- [Aa][Ss][Mm] -\*-/                              asm;
528   /-\*- [Oo][Bb][Jj][Cc] -\*-/                          objc;
529   /-\*- [Ss][Cc][Hh][Ee][Mm][Ee] -\*-/                  scheme;
530   /-\*- [Ee][Mm][Aa][Cc][Ss] [Ll][Ii][Ss][Pp] -\*-/     elisp;
531   /-\*- [Tt][Cc][Ll] -\*-/                              tcl;
532   /-\*- [Vv][Hh][Dd][Ll] -\*-/                          vhdl;
533   /-\*- [Hh][Aa][Ss][Kk][Ee][Ll][Ll] -\*-/              haskell;
534   /-\*- [Ii][Dd][Ll] -\*-/                              idl;
535   /-\*- [Pp][Ee][Rr][Ll] -\*-/                          perl;
536   /^#![ \t]*\/.*\/perl/                                 perl;
537   /^From:/                                              mail;
538   /^#![ \t]*(\/usr)?\/bin\/[ngmt]?awk/                  awk;
539   /-\*- [Ss][Hh] -\*-/                                  sh;
540   /^#![ \t]*(\/usr)?\/bin\/sh/                          sh;
541   /^#![ \t]*(\/usr)?\/bin\/csh/                         csh;
542   /^#![ \t]*(\/usr)?(\/local)?\/bin\/tcsh/              tcsh;
543   /^#![ \t]*(\/usr)?(\/local)?\/bin\/zsh/               zsh;
544   /^#![ \t]*(\/usr)?(\/local)?\/bin\/bash/              bash;
545   /^#![ \t]*(\/usr)?(\/ccs)?\/bin\/m4/                  m4;
546   /^#VRML/                                              vrml;
547   /^\04?%!/                                             postscript;
548 }
549
550 \f
551 /*
552  * The global super states.
553  */
554
555 state Highlight
556 {
557   /* If you want to preserve enscript's escape sequences in the state
558      highlighting, uncomment the following rule.  It passes all
559      enscript's escape sequences to the output.
560
561        /^\0[^{]+{[^}]+}/ {
562         language_print ($0);
563        }
564   */
565
566   /* If we are doing nested highlighting (same document can contain
567      multiple highlighting styles), the variable `nested_end_re'
568      specifies the end of the nesting highlight state. */
569   nested_end_re {
570     language_print($0);
571     return;
572   }
573
574   /* Skip output language's special characters. */
575   LANGUAGE_SPECIALS {
576     language_print ($0);
577   }
578 }
579
580 /* How many nesting HighlightEntry states are currently active.  The
581    header and trailer will be printed at the nesting level 0. */
582 highlight_entry_nesting = 0;
583
584 state HighlightEntry extends Highlight
585 {
586   BEGIN {
587     if (highlight_entry_nesting++ == 0)
588       header();
589   }
590   END {
591     if (--highlight_entry_nesting == 0)
592       trailer();
593   }
594 }
595
596
597 \f
598 /*
599  * Helper subroutines and states.
600  */
601
602 state match_balanced_block extends Highlight
603 {
604   match_balanced_block_start {
605     language_print ($0);
606     match_balanced_block_count = match_balanced_block_count + 1;
607   }
608
609   match_balanced_block_end {
610     match_balanced_block_count = match_balanced_block_count - 1;
611     if (match_balanced_block_count == 0)
612       return $0;
613
614     language_print ($0);
615   }
616 }
617
618 sub match_balanced_block (starter, ender)
619 {
620   match_balanced_block_count = 1;
621   match_balanced_block_start = starter;
622   match_balanced_block_end = ender;
623   return call (match_balanced_block);
624 }
625
626 state eat_one_line
627 {
628   /.*\n/ {
629     language_print ($0);
630     return;
631   }
632 }
633
634 \f
635 /*
636 Local variables:
637 mode: c
638 End:
639 */