~sword-devel/jsword/trunk

« back to all changes in this revision

Viewing changes to jsword/java/historic/org/crosswire/util/CodeColorizer.java

  • Committer: joe
  • Date: 2002-10-08 21:36:18 UTC
  • Revision ID: svn-v4:a88caf3b-7e0a-0410-8d0d-cecb45342206:trunk:80
big config and comment update

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
 
2
 
package org.crosswire.util;
3
 
 
4
 
import java.io.*;
5
 
import java.util.*;
6
 
 
7
 
/**
8
 
 * CodeViewer.java
9
 
 *
10
 
 * Bill Lynch & Matt Tucker
11
 
 * CoolServlets.com, July 1999
12
 
 *
13
 
 * Any errors or suggested improvements to this servlet can be reported
14
 
 * as instructed on Coolservlets.com. We hope you enjoy
15
 
 * this program... your comments will encourage further development!
16
 
 *
17
 
 *    Copyright (C) 1999  Bill Lynch & Matt Tucker
18
 
 *
19
 
 *    This program is free software; you can redistribute it and/or modify
20
 
 *    it under the terms of the GNU General Public License as published by
21
 
 *    the Free Software Foundation; either version 2 of the License, or
22
 
 *    (at your option) any later version.
23
 
 *
24
 
 *    This program is distributed in the hope that it will be useful,
25
 
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
26
 
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27
 
 *    GNU General Public License for more details.
28
 
 *
29
 
 *    You should have received a copy of the GNU General Public License
30
 
 *    along with this program; if not, write to the Free Software
31
 
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
32
 
 */
33
 
/**
34
 
 * Syntax highlights java by turning it into html.
35
 
 *
36
 
 * A codeviewer object is created and then keeps state as lines are passed
37
 
 * in. Each line passed in as java test, is returned as syntax highlighted
38
 
 * html text.
39
 
 *
40
 
 * Users of the class can set how the java code will be highlighted with setter
41
 
 * methods.
42
 
 *
43
 
 * Only valid java lines should be passed in since the object maintains state
44
 
 * and may not handle illegal code gracefully.
45
 
 *
46
 
 * The actual system is implemented as a series of filters that deal with
47
 
 * specific portions of the java code. The filters are as follows:
48
 
 *
49
 
 *  htmlFilter
50
 
 *     |__
51
 
 *        multiLineCommentFilter
52
 
 *           |___
53
 
 *                inlineCommentFilter
54
 
 *                   |___
55
 
 *                        stringFilter
56
 
 *                           |__
57
 
 *                               keywordFilter
58
 
 */
59
 
public class CodeColorizer implements Serializable
60
 
{
61
 
    /**
62
 
    * Set up a CodeColorizer
63
 
    */
64
 
    public CodeColorizer()
65
 
    {
66
 
        loadHash();
67
 
    }
68
 
 
69
 
    /**
70
 
    * Now different method of seeing if at end of input stream,
71
 
    * closes inputs stream at end.
72
 
    */
73
 
    public String syntaxHighlight(String line)
74
 
    {
75
 
        return htmlFilter(line);
76
 
    }
77
 
 
78
 
    public void setCommentStart(String commentStart)
79
 
    {
80
 
        this.commentStart = commentStart;
81
 
    }
82
 
 
83
 
    public void setCommentEnd(String commentEnd)
84
 
    {
85
 
        this.commentEnd = commentEnd;
86
 
    }
87
 
 
88
 
    public void setStringStart(String stringStart)
89
 
    {
90
 
        this.stringStart = stringStart;
91
 
    }
92
 
 
93
 
    public void setStringEnd(String stringEnd)
94
 
    {
95
 
        this.stringEnd = stringEnd;
96
 
    }
97
 
 
98
 
    public void setReservedWordStart(String reservedWordStart)
99
 
    {
100
 
        this.reservedWordStart = reservedWordStart;
101
 
    }
102
 
 
103
 
    public void setReservedWordEnd(String reservedWordEnd)
104
 
    {
105
 
        this.reservedWordEnd = reservedWordEnd;
106
 
    }
107
 
 
108
 
    public String getCommentStart()
109
 
    {
110
 
        return commentStart;
111
 
    }
112
 
 
113
 
    public String getCommentEnd()
114
 
    {
115
 
        return commentEnd;
116
 
    }
117
 
 
118
 
    public String getStringStart()
119
 
    {
120
 
        return stringStart;
121
 
    }
122
 
 
123
 
    public String getStringEnd()
124
 
    {
125
 
        return stringEnd;
126
 
    }
127
 
 
128
 
    public String getReservedWordStart()
129
 
    {
130
 
        return reservedWordStart;
131
 
    }
132
 
 
133
 
    public String getReservedWordEnd()
134
 
    {
135
 
        return reservedWordEnd;
136
 
    }
137
 
 
138
 
    /**
139
 
    * Filter html tags into more benign text.
140
 
    */
141
 
    private String htmlFilter(String line)
142
 
    {
143
 
        StringBuffer buf = new StringBuffer();
144
 
        if (line == null || line.equals(""))
145
 
            return "";
146
 
 
147
 
        line = replace(line,"&","&");
148
 
        line = replace(line,"<","&lt;");
149
 
        line = replace(line,">","&gt;");
150
 
        line = replace(line, "\\\\", "&#47;&#47;");
151
 
        line = replace(line, "\\\"", "\\&quot;");
152
 
        line = replace(line, "'\"'", "'&quot;'");
153
 
 
154
 
        return multiLineCommentFilter(line);
155
 
    }
156
 
 
157
 
    /**
158
 
    * Filter out multiLine comments. State is kept with a private boolean
159
 
    * variable.
160
 
    */
161
 
    private String multiLineCommentFilter(String line)
162
 
    {
163
 
        if (line == null || line.equals(""))
164
 
            return "";
165
 
 
166
 
        StringBuffer buf = new StringBuffer();
167
 
        int index;
168
 
 
169
 
        // First, check for the end of a multi-line comment.
170
 
        if (inMultiLineComment &&
171
 
            (index = line.indexOf("*/")) > -1 &&
172
 
            !isInsideString(line,index))
173
 
        {
174
 
            inMultiLineComment = false;
175
 
 
176
 
            buf.append(line.substring(0,index));
177
 
            buf.append("*/").append(commentEnd);
178
 
            if (line.length() > index+2)
179
 
                buf.append(inlineCommentFilter(line.substring(index+2)));
180
 
 
181
 
            return buf.toString();
182
 
        }
183
 
        else if (inMultiLineComment)
184
 
        {
185
 
            // If there was no end detected and we're currently in a multi-line
186
 
            // comment, we don't want to do anymore work, so return line.
187
 
 
188
 
            return line;
189
 
        }
190
 
        else if ((index = line.indexOf("/*")) > -1 &&
191
 
                 !isInsideString(line,index))
192
 
        {
193
 
            // We're not currently in a comment, so check to see if the start
194
 
            // of a multi-line comment is in this line.
195
 
            inMultiLineComment = true;
196
 
 
197
 
            // Return result of other filters + everything after the start
198
 
            // of the multiline comment. We need to pass the through the
199
 
            // to the multiLineComment filter again in case the comment ends
200
 
            // on the same line.
201
 
            buf.append(inlineCommentFilter(line.substring(0,index)));
202
 
            buf.append(commentStart).append("/*");
203
 
            buf.append(multiLineCommentFilter(line.substring(index+2)));
204
 
 
205
 
            return buf.toString();
206
 
        }
207
 
        else
208
 
        {
209
 
            // Otherwise, no useful multi-line comment information was found so
210
 
            // pass the line down to the next filter for processesing.
211
 
 
212
 
            return inlineCommentFilter(line);
213
 
        }
214
 
    }
215
 
 
216
 
    /**
217
 
    * Filter inline comments from a line and formats them properly.
218
 
    * One problem we'll have to solve here: comments contained in a string
219
 
    * should be ignored... this is also true of the multiline comments. So,
220
 
    * we could either ignore the problem, or implement a function called
221
 
    * something like isInsideString(line, index) where index points to
222
 
    * some point in the line that we need to check... started doing this
223
 
    * function below.
224
 
    */
225
 
    private String inlineCommentFilter(String line)
226
 
    {
227
 
        if (line == null || line.equals(""))
228
 
            return "";
229
 
 
230
 
        StringBuffer buf = new StringBuffer();
231
 
        int index;
232
 
 
233
 
        if ((index = line.indexOf("//")) > -1 &&
234
 
            !isInsideString(line,index))
235
 
        {
236
 
            buf.append(stringFilter(line.substring(0,index)));
237
 
            buf.append(commentStart);
238
 
            buf.append(line.substring(index));
239
 
            buf.append(commentEnd);
240
 
        }
241
 
        else
242
 
        {
243
 
            buf.append(stringFilter(line));
244
 
        }
245
 
 
246
 
        return buf.toString();
247
 
    }
248
 
 
249
 
    /**
250
 
    * Filters strings from a line of text and formats them properly.
251
 
    */
252
 
    private String stringFilter(String line)
253
 
    {
254
 
        if (line == null || line.equals(""))
255
 
            return "";
256
 
 
257
 
        if (line.indexOf("\"") <= -1)
258
 
            return keywordFilter(line);
259
 
 
260
 
        StringBuffer buf = new StringBuffer();
261
 
        int start = 0;
262
 
        int startStringIndex = -1;
263
 
        int endStringIndex = -1;
264
 
        int tempIndex;
265
 
 
266
 
        // Keep moving through String characters until we want to stop...
267
 
        while ((tempIndex = line.indexOf("\"")) > -1)
268
 
        {
269
 
            // We found the beginning of a string
270
 
            if (startStringIndex == -1)
271
 
            {
272
 
                startStringIndex = 0;
273
 
                buf.append(stringFilter(line.substring(start,tempIndex)));
274
 
                buf.append(stringStart).append("\"");
275
 
                line = line.substring(tempIndex+1);
276
 
            }
277
 
            else
278
 
            {
279
 
                //Must be at the end
280
 
                startStringIndex = -1;
281
 
                endStringIndex = tempIndex;
282
 
                buf.append(line.substring(0,endStringIndex+1));
283
 
                buf.append(stringEnd);
284
 
                line = line.substring(endStringIndex+1);
285
 
            }
286
 
        }
287
 
 
288
 
        buf.append( keywordFilter(line));
289
 
 
290
 
        return buf.toString();
291
 
    }
292
 
 
293
 
    /**
294
 
    * Filters keywords from a line of text and formats them properly.
295
 
    */
296
 
    private String keywordFilter(String line)
297
 
    {
298
 
        if (line == null || line.equals(""))
299
 
            return "";
300
 
 
301
 
        StringBuffer buf = new StringBuffer();
302
 
 
303
 
        //HashMap usedReservedWords = new HashMap();
304
 
        Hashtable usedReservedWords = new Hashtable();
305
 
 
306
 
        int i = 0;
307
 
        int startAt = 0;
308
 
        char ch;
309
 
        StringBuffer temp = new StringBuffer();
310
 
 
311
 
        while (i < line.length())
312
 
        {
313
 
            temp.setLength(0);
314
 
            ch = line.charAt(i);
315
 
            startAt = i;
316
 
 
317
 
            while (i<line.length() &&
318
 
                   ((ch >= 65 && ch <= 90) || (ch >= 97 && ch <= 122)))
319
 
            {
320
 
                temp.append(ch);
321
 
                i++;
322
 
 
323
 
                if (i < line.length())
324
 
                    ch = line.charAt(i);
325
 
            }
326
 
 
327
 
            String tempString = temp.toString();
328
 
            if (reservedWords.containsKey(tempString) && !usedReservedWords.containsKey(tempString))
329
 
            {
330
 
                usedReservedWords.put(tempString,tempString);
331
 
                line = replace (line, tempString, (reservedWordStart+tempString+reservedWordEnd));
332
 
                i += (reservedWordStart.length() + reservedWordEnd.length());
333
 
            }
334
 
            else
335
 
            {
336
 
                i++;
337
 
            }
338
 
        }
339
 
        buf.append(line);
340
 
        return buf.toString();
341
 
    }
342
 
 
343
 
    /**
344
 
    *  Replace...
345
 
    *  I made it use a stringBuffer... hope it still works :)
346
 
    */
347
 
    private String replace(String line, String oldString, String newString)
348
 
    {
349
 
        int i=0;
350
 
 
351
 
        while ((i = line.indexOf(oldString, i)) >= 0)
352
 
        {
353
 
            line = (new StringBuffer().append(line.substring(0,i)).append(newString).append(line.substring(i+oldString.length()))).toString();
354
 
            i += newString.length();
355
 
        }
356
 
 
357
 
        return line;
358
 
    }
359
 
 
360
 
    /**
361
 
    * Checks to see if some position in a line is between String start and
362
 
    * ending characters. Not yet used in code or fully working :)
363
 
    */
364
 
    private boolean isInsideString(String line, int position)
365
 
    {
366
 
        if (line.indexOf("\"") < 0)
367
 
            return false;
368
 
 
369
 
        int index;
370
 
        String left = line.substring(0,position);
371
 
        String right = line.substring(position);
372
 
        int leftCount = 0;
373
 
        int rightCount = 0;
374
 
 
375
 
        while ((index = left.indexOf("\"")) > -1)
376
 
        {
377
 
            leftCount ++;
378
 
            left = left.substring(index+1);
379
 
        }
380
 
 
381
 
        while ((index = right.indexOf("\"")) > -1)
382
 
        {
383
 
            rightCount ++;
384
 
            right = right.substring(index+1);
385
 
        }
386
 
 
387
 
        if (rightCount % 2 != 0 && leftCount % 2 != 0)
388
 
            return true;
389
 
        else
390
 
            return false;
391
 
    }
392
 
 
393
 
    private void loadHash()
394
 
    {
395
 
        reservedWords.put("abstract", "abstract");
396
 
        reservedWords.put("do", "do");
397
 
        reservedWords.put("inner", "inner");
398
 
        reservedWords.put("public", "public");
399
 
        reservedWords.put("var", "var");
400
 
        reservedWords.put("boolean", "boolean");
401
 
        reservedWords.put("continue", "continue");
402
 
        reservedWords.put("int", "int");
403
 
        reservedWords.put("return", "return");
404
 
        reservedWords.put( "void", "void");
405
 
        reservedWords.put("break", "break");
406
 
        reservedWords.put("else", "else");
407
 
        reservedWords.put("interface", "interface");
408
 
        reservedWords.put("short", "short");
409
 
        reservedWords.put("volatile", "volatile");
410
 
        reservedWords.put("byvalue", "byvalue");
411
 
        reservedWords.put("extends", "extends");
412
 
        reservedWords.put("long", "long");
413
 
        reservedWords.put("static", "static");
414
 
        reservedWords.put("while", "while");
415
 
        reservedWords.put("case", "case");
416
 
        reservedWords.put("final", "final");
417
 
        reservedWords.put("naive", "naive");
418
 
        reservedWords.put("super", "super");
419
 
        reservedWords.put("transient", "transient");
420
 
        reservedWords.put("cast", "cast");
421
 
        reservedWords.put("float", "float");
422
 
        reservedWords.put("new", "new");
423
 
        reservedWords.put("rest", "rest");
424
 
        reservedWords.put("catch", "catch");
425
 
        reservedWords.put("for", "for");
426
 
        reservedWords.put("null", "null");
427
 
        reservedWords.put("synchronized", "synchronized");
428
 
        reservedWords.put("char", "char");
429
 
        reservedWords.put("finally", "finally");
430
 
        reservedWords.put("operator", "operator");
431
 
        reservedWords.put("this", "this");
432
 
        reservedWords.put("class", "class");
433
 
        reservedWords.put("generic", "generic");
434
 
        reservedWords.put("outer", "outer");
435
 
        reservedWords.put("switch", "switch");
436
 
        reservedWords.put("const", "const");
437
 
        reservedWords.put("goto", "goto");
438
 
        reservedWords.put("package", "package");
439
 
        reservedWords.put("throw", "throw");
440
 
        reservedWords.put("double", "double");
441
 
        reservedWords.put("if", "if");
442
 
        reservedWords.put("private", "private");
443
 
        reservedWords.put("true", "true");
444
 
        reservedWords.put("default", "default");
445
 
        reservedWords.put("import", "import");
446
 
        reservedWords.put("protected", "protected");
447
 
        reservedWords.put("try", "try");
448
 
    }
449
 
 
450
 
    void writeObject(ObjectOutputStream oos) throws IOException
451
 
    {
452
 
        oos.defaultWriteObject();
453
 
    }
454
 
 
455
 
    void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException
456
 
    {
457
 
        ois.defaultReadObject();
458
 
    }
459
 
 
460
 
    private BufferedReader in;
461
 
    private StringBuffer out;
462
 
    //private HashMap reservedWords = new HashMap();
463
 
    private Hashtable reservedWords = new Hashtable();
464
 
    private boolean inMultiLineComment = false;
465
 
    private String backgroundColor = "#ffffff";
466
 
    private String commentStart = "<font color='#009900'>";
467
 
    private String commentEnd = "</font>";
468
 
    private String stringStart = "<font color='#0000aa'>";
469
 
    private String stringEnd = "</font>";
470
 
    private String reservedWordStart = "<b>";
471
 
    private String reservedWordEnd = "</b>";
472
 
}