REXXTAGS.org :: Samples: REXX highlighter tag
Home Samples

File: rexxtags.rexxhighlight.tag [download (.tag file, 10Kb)]

Author: José María Blasco<jm@jmblasco.com>

Contributed on: 2002-12-04

Description: This REXX tag allows for a simple form of REXX code highlighting. You can insert REXX code into your XML page, and, by surrounding it with this tag, the code will be highlighted (with optional line-numbering). This is the same REXX tag used in the REXXTAGS tutorial.

Example: Here's the XML code,

  1:<rexxtags:rexxhighlight lineno="yes">
  2:  Parse var line 'option='option
  3:  /* This is a comment to show highlighting */
  4:  If Left(option,3) = 'yes' Then Say 'OK'
  5:  Else Say 'Invalid option: 'option
  6:</rexxtags:rexxhighlight>
  7:


and here's the generated output:

  1:  Parse var line 'option='option
  2:  /* This is a comment to show highlighting */
  3:  If Left(option,3) = 'yes' Then Say 'OK'
  4:  Else Say 'Invalid option: 'option
  5:


Program code:



  1:/* <rexxtags:rexxhighlight>: a quick and dirty REXX tag to highlight REXX code*/
  2:/*                                                                            */
  3:/* Parameters: lineno=[YES|1|NO|0]                                            */
  4:/*                                                                            */
  5:/* Version:     1.0                                                           */
  6:/*                                                                            */
  7:/* Author:      (c) Jose Maria Blasco <jm@jmblasco.com>                       */
  8:/*                                                                            */
  9:/* This software is subject to the terms of the Common Public License. You    */
 10:/* must accept the terms of this license to use this software. Refer to       */
 11:/* the license at the following URL for more information:                     */
 12:/* http://oss.software.ibm.com/developerworks/opensource/CPLv1.0.htm          */
 13:/*                                                                            */
 14:/* Description: A quick-and-dirty REXX code highlighter which is used         */
 15:/* in the REXXTAGS tutorial (and elsewhere on the REXXTAGS site,              */
 16:/* http://www.rexxtags.org ). I wrote it in 30 minutes to test code           */
 17:/* highlighting, and invested later some more time so that the code is        */
 18:/* readable and has some documentation                                        */
 19:/*                                                                            */
 20:/* Disclaimer: I wrote this program for my own needs (mainly, for the         */
 21:/* REXXTAGS tutorial). It is NOT a complete REXX highlighter, nor does it     */
 22:/* handle all syntactical cases, stop words or BIFs. Use at your own risk.    */
 23:/*                                                                            */
 24:/* Modifications:                                                             */
 25:/*                                                                            */
 26:/* Date       Author      Description                                         */
 27:/* ---------- ----------- --------------------------------------------------- */
 28:/* 2002/12/04 J.M.Blasco  v1.0 Initial release                                */
 29:
 30:
 31:Parse arg verb, parms, body                  /* Standard 'parse' for tags     */
 32:
 33:If verb == 'QUERY BODY CONTENT' Then
 34:  Return 'TAGDEPENDENT'                      /* Process tag body ourselves    */
 35:If verb == 'START' then Return ''            /* No output at start tag        */
 36:If verb == 'BODY' Then Do                    /* Standard body processing      */
 37:  Interpret body                             /* Get the tag body into..       */
 38:  Signal Body                                /* ..the 'body.' stem            */
 39:  End                                        /*                               */
 40:If verb == 'END' then Return ''              /* Nothing output at end tag     */
 41:
 42:Return 0                                     /* Return 0 for all other calls  */
 43:
 44:/*----------------------------------------------------------------------------*/
 45:/* Body processing routine. Here we do the actual parsing                     */
 46:/*----------------------------------------------------------------------------*/
 47:Body:
 48:
 49:  /* We first fill the 'res.' and 'fun.' stems with reserved words and BIF..  */
 50:  /* ..names.                                                                 */
 51:
 52:  Call SetReserved
 53:  Call SetFunctions
 54:
 55:  /* We now parse the parameter string and check for the presence of a..      */
 56:  /* ..'lineno' parameter. Note that we do little actual verification of..    */
 57:  /* ..correctness of the parameter.                                          */
 58:
 59:  Parse var parms 'lineno="'lineno'"'
 60:  If Translate(lineno) == "YES" Then lineno = 1
 61:  If lineno \= 1 Then lineno = 0
 62:  printlinenos = lineno
 63:
 64:  /* Variable 'r' will hold the constructed return value (i.e. the..          */
 65:  /* ..highlighted, parsed program).                                          */
 66:  r = ''
 67:
 68:  lineno = 1                                 /* For line number counting      */
 69:  diff = 0                                   /* The following code allows..   */
 70:  If body.1 = '' Then Do                     /* ..for the first line to be..  */
 71:    lineno = 2                               /* ..a blank line.               */
 72:    diff = 1                                 /* 'diff' will be subtracted..   */
 73:  End                                        /* ..from 'lineno' below.        */
 74:
 75:  /*--------------------------------------------------------------------------*/
 76:  /* We iterate over all body lines, with a few tricks                        */
 77:  /*--------------------------------------------------------------------------*/
 78:
 79:  Do lineno = lineno To body.0               /* We parse all 'body.' lines.   */
 80:    l = body.lineno                          /* Get the line in 'l'. Don't..  */
 81:    If l = '' & lineno = body.0 Then Leave   /* print the last line if blank  */
 82:
 83:    /*------------------------------------------------------------------------*/
 84:    /* Main loop. Parse one line; parsed results will go into 'lr'            */
 85:    /*------------------------------------------------------------------------*/
 86:
 87:    l = change(l,'&','&amp;')                /* Don't mess with <, > and & .. */
 88:    l = change(l,'<','&lt;')                 /* in HTML code.                 */
 89:    l = change(l,'>','&gt;')
 90:    l = change(l,'  ','&nbsp; ')
 91:    l = change(l,'  ','&nbsp; ')
 92:
 93:    lr = ''                                  /* 'lr' gets the parsed part.    */
 94:    Do while l <> ''                         /* Loop until the line is parsed.*/
 95:
 96:      /* First take care of starting blanks                                   */
 97:      nb = Verify(l,' ')
 98:      If nb > 0 & left(l,1) == ' ' Then Do
 99:        lr = lr||Copies(' ',nb-1)
100:        l = Strip(l,'L')
101:      End
102:
103:      /* Get a token (word) from the (rest of the) line                       */
104:      Parse var l w' 'l
105:
106:      /* Built-in Functions                                                   */
107:      If pos('(',w) > 1 Then Do
108:        Parse var w fn'('rest
109:        ufn = Translate(fn)
110:        If fun.ufn Then Do
111:          lr = lr'<b><font color="#990099">'fn'</font></b>('
112:          l = rest' 'l
113:          Iterate
114:        End
115:      End
116:
117:      /* 'Reserved' words                                                     */
118:      uw = Translate(w)
119:      If res.uw Then Do
120:        lr = lr'<b>'w'</b> '
121:        Iterate
122:      End
123:
124:      /* Comments                                                             */
125:      If left(w,2) == '/*' Then Do
126:        If Pos('*/',SubStr(w,3)' 'l) > 0 Then Do
127:          Parse Value SubStr(w,3)' 'l With b'*/'l
128:          lr = lr'<i><font color="#006600">/*'||b'*/</font></i>'
129:          Iterate
130:        End
131:      End
132:
133:      /* This code is to separate expressions from abuttal strings            */
134:      p1 = Pos('"',w)
135:      p2 = Pos("'",w)
136:      If p1 > 1 | p2 > 1 Then Do
137:        If p1 = 0 | (p2 > 0 & p2 < p1) Then Do
138:          lr = lr||Left(w,p2-1)
139:          w = Substr(w,p2)
140:          End
141:        Else Do
142:          lr = lr||Left(w,p1-1)
143:          w = Substr(w,p1)
144:        End
145:      End
146:
147:      /* Handle strings                                                       */
148:      c = left(w,1)
149:      If c = '"' | c = "'" Then Do
150:        start = 2
151:        w = w' 'l
152:        l = ''
153:        Do Forever
154:          p = Pos(c,w,start)
155:          If p = 0 Then p = Length(w)                       /* Unended string */
156:          If SubStr(w,p+1,1) = c Then start = p+2
157:          Else Leave
158:        End
159:        l = Substr(w,p+1)
160:        lr = lr'<font color="#0000ff">'left(w,p)'</font>'
161:        Iterate
162:      End
163:      lr = lr||w' '
164:    End
165:    If printlinenos Then lr = '<font color="#999999"><font size="1">'Change(Right(lineno-diff,3),' ','&nbsp;')'</font>:</font>'lr
166:    If r = '' then r = '<br />'lr
167:    Else r = r'00'x'<br />'lr
168:
169:  End
170:Return '<font face="Courier New,Courier,Arial">'r'</font>'
171:
172:
173:/* This is the list of 'reserved' words. Extend as needed */
174:SetReserved:
175:  res. = 0
176:  res.if = 1
177:  res.then = 1
178:  res.else = 1
179:  res.do = 1
180:  res.to = 1
181:  res.end = 1
182:  res.leave = 1
183:  res.iterate = 1
184:  res.say = 1
185:  res.parse = 1
186:  res.with = 1
187:  res.select = 1
188:  res.when = 1
189:  res.otherwise = 1
190:  res.call = 1
191:  res.signal = 1
192:  res.arg = 1
193:  res.return = 1
194:  res.procedure = 1
195:  res.expose = 1
196:  res.var = 1
197:  res.value = 1
198:Return
199:
200:/* This is the list of built-in functions. Extend as needed */
201:SetFunctions:
202:  fun. = 0
203:  fun.substr = 1
204:  fun.left = 1
205:  fun.right = 1
206:  fun.arg = 1
207:  fun.reverse = 1
208:  fun.pos = 1
209:  fun.translate = 1
210:  fun.word = 1
211:  fun.length = 1
212:  fun.date = 1
213:Return
214:
215:/* The following internal function is from Mike Cowlishaw  */
216:/* (posted in comp.lang.rexx)                              */
217:/* Internal function:  CHANGE(string,old,new)              */
218:/*                                                         */
219:/* (Like XEDIT  "C/old/new/1 *")                           */
220:/*                                                         */
221:/* Changes all occurrences of "old" in "string" to "new".  */
222:/* If "old"=='', then "new" is prefixed to "string".   MFC */
223:Change: procedure expose changed
224:  parse arg string, old, new
225:  if old=='' then do; changed=1; return new||string; end
226:  out=''; changed=0
227:  do while pos(old,string)\=0
228:    parse var string prefix (old) string
229:    out=out||prefix||new
230:    changed=changed+1
231:    end
232:  return out||string
233:

/samples/rexxtags.rexxhighlight.html
Last update: 29/05/03 at 01:34
 Comments
Valid XHTML 1.0! Valid CSS!