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