放出个 JavaScript 代码语法高亮类, 是根据 Unnamed Blog 上的修改的(原文提供的下载后有不少错误…), 效率比我原来写的高了不少. 当然, 我自己最后估计还是拿 Lex 来做…

主要修改的地方首先是让整个 js 可运行(-_-!)…然后完善了一些功能, 比如对 & 和 < 的处理, 还有把其它语言的支持分离开来.

首先是 cpp 高亮的支持 js 文件

?Download brushCpp.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sh.Brushes.Cpp = function() {}
 
sh.Brushes.Cpp.aliases = 'cpp';
 
sh.Brushes.Cpp.regexList = [
    {regex: new RegExp('//.*$', 'gm'), css: 'comment'},    // one line comments
    {regex: new RegExp('/\\*[\\s\\S]*?\\*/', 'g'), css: 'comment'},    // multi line comments
    {regex: new RegExp("\'(?:[^\\\\']|\\\\.)*\'|" +
                       "\"(?:[^\\\\\"]|\\\\.)*\"", 'g'), css: 'string'},    // string literals
    {regex: new RegExp('^\\s*#.*', 'gm'), css: 'preprocessor'},    // preprocessor directives
    {regex: new RegExp('\\b(?:auto|break|case|char|const|continue|default|do' +
                       'double|else|enum|extern|float|for|goto|if|int|long|register' +
                       'return|short|signed|sizeof|static|struct|switch|typedef|union' +
                       'unsigned|void|volatile|while)\\b', 'gm'), css: 'keyword'}    // keyword
];


然后是关于着色的 css 文件

1
2
3
4
.cpp .comment { color: gray; }
.cpp .string { color: red; }
.cpp .preprocessor { color: green; }
.cpp .keyword { color: blue; }

最后是主程序文件…

?Download highLight.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// create namespaces
var sh = {
    Brushes : {}
}
 
// Match object
sh.Match = function(regex, css)
{
    this.regex = regex;    // regeax to match
    this.css = css;    // color the matches
    this.match = null;    // match result, return of re.exec(str)
    this.index = 0;
}
 
sh.Parser = function(lang)
{
    this.minIndex = -1;
    this.matches = new Array();
    this.style = null;
    this.InitMatches(lang);
}
 
// Init match regex list
sh.Parser.prototype.InitMatches = function(lang)
{
    var brush;
    for(brush in sh.Brushes)
        if(sh.Brushes[brush].aliases == lang)
            break;
 
    // If lang can be found, set matches and style
    if(sh.Brushes[brush].aliases == lang)
    {
        this.matches = sh.Brushes[brush].regexList;
        this.style = sh.Brushes[brush].aliases;
    }
}
 
// Compare this.matches[i].match.index and store min i into this.minIndex, skip null
sh.Parser.prototype.RefreshMin = function()
{
    var i;
    // get the first not null in this.matchers[i].match
    for(i=0; i<this.matches.length; i++)
    {
        if(this.matches[i].match != null)
        {
            this.minIndex = i;
            break;
        }
    }
    // get min and store into this.minIndex
    for(; i<this.matches.length; i++)
    {
        if(this.matches[i].match != null &&
            this.matches[i].match.index < this.matches[this.minIndex].match.index)
        {
            this.minIndex = i;
        }
    }
}
 
// Do first match, refresh this.minIndex
sh.Parser.prototype.PrepareMatch = function(str)
{
    var i;
 
    for(i=0; i<this.matches.length; i++)
        this.matches[i].match = this.matches[i].regex.exec(str);
 
    this.RefreshMin();
}
 
// Find a match, begins at the last matched index, and refresh this.minIndex
// returns found or not(true/false)
sh.Parser.prototype.MatchOnce = function(str)
{
    var index = this.matches[this.minIndex].regex.lastIndex;
 
    var i;
    for(i=0; i<this.matches.length; i++)
    {
        if(this.matches[i].match && this.matches[i].match.index < index)
        {
            if(this.matches[i].regex.lastIndex < index)
            {
                this.matches[i].regex.lastIndex = index;
            }
            this.matches[i].match = this.matches[i].regex.exec(str);
        }
    }
 
    this.RefreshMin();
 
    return (this.matches[this.minIndex].match != null);
}
 
// Main parser
sh.Parser.prototype.HighLight = function(str)
{
    // If no lang matched, return str
    if(this.style == null)
    {
        str  = str.replace(/&/g, '&amp;');    // Replace & whith &amp;
        str  = str.replace(/</g, '&lt;');    // Replace < whith &lt;
        return "<pre>" + str + "< /pre>";
    }
 
    var gIndex = 0;
    var buf = new Array();
 
    this.PrepareMatch(str);
 
    buf.push("<pre class=\"" + this.style + "\">")
 
    if(this.minIndex == -1)
        buf.push(str);
 
    do
    {
        var i = this.minIndex;
        // push not matched
        buf.push(str.substring(gIndex, this.matches[i].match.index));
        // push matched in color
        var matched = "" + this.matches[i].match;
        matched  = matched.replace(/&/g, '&amp;');    // Replace & whith &amp;
        matched  = matched.replace(/</g, '&lt;');    // Replace < whith &lt;
        buf.push("<span class=\"" + this.matches[i].css + "\">" + matched + "</span>");
        gIndex = this.matches[i].regex.lastIndex;
    }
    while(this.MatchOnce(str))
 
    buf.push(str.substr(gIndex));
    buf.push("< /pre>")
 
    return buf.join("");
}

调用也很简单

?Download highLight.js
1
2
3
4
5
6
7
8
<script class="javascript" src="test.js"></script>
<script class="javascript" src="brushCpp.js"></script>
<link type="text/css" rel="stylesheet" href="brushColor.css"></link>
<script class="javascript">
var input_code = "/* int x = 5; // test */";
var parser = new sh.Parser('cpp');
var highlighted_code = parser.HighLight(input_code);
</script>

给这个类添加其它语言的高亮支持也很简单, 只要仿照 brushCpp.js 写一个对应语言的 js 文件, 然后在 brushColor.css 添加相应的颜色配置方案就可以了.

Related posts:

  1. XPCOM: Javascript function call alternative
  2. XPCOM: Javascript function call

Tags: ,



Leave a Comment