##// END OF EJS Templates
Added javascript highlightment support (http://pastie.textmate.org/50774/)...
Jean-Philippe Lang -
r705:27d6da945743
parent child
Show More
@@ -0,0 +1,176
1 # http://pastie.textmate.org/50774/
2 module CodeRay module Scanners
3
4 class JavaScript < Scanner
5
6 register_for :javascript
7
8 RESERVED_WORDS = [
9 'asm', 'break', 'case', 'continue', 'default', 'do', 'else',
10 'for', 'goto', 'if', 'return', 'switch', 'while',
11 # 'struct', 'union', 'enum', 'typedef',
12 # 'static', 'register', 'auto', 'extern',
13 # 'sizeof',
14 'typeof',
15 # 'volatile', 'const', # C89
16 # 'inline', 'restrict', # C99
17 'var', 'function','try','new','in',
18 'instanceof','throw','catch'
19 ]
20
21 PREDEFINED_CONSTANTS = [
22 'void', 'null', 'this',
23 'true', 'false','undefined',
24 ]
25
26 IDENT_KIND = WordList.new(:ident).
27 add(RESERVED_WORDS, :reserved).
28 add(PREDEFINED_CONSTANTS, :pre_constant)
29
30 ESCAPE = / [rbfnrtv\n\\\/'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x
31 UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x
32
33 def scan_tokens tokens, options
34
35 state = :initial
36 string_type = nil
37 regexp_allowed = true
38
39 until eos?
40
41 kind = :error
42 match = nil
43
44 if state == :initial
45
46 if scan(/ \s+ | \\\n /x)
47 kind = :space
48
49 elsif scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx)
50 kind = :comment
51 regexp_allowed = false
52
53 elsif match = scan(/ \# \s* if \s* 0 /x)
54 match << scan_until(/ ^\# (?:elif|else|endif) .*? $ | \z /xm) unless eos?
55 kind = :comment
56 regexp_allowed = false
57
58 elsif regexp_allowed and scan(/\//)
59 tokens << [:open, :regexp]
60 state = :regex
61 kind = :delimiter
62
63 elsif scan(/ [-+*\/=<>?:;,!&^|()\[\]{}~%] | \.(?!\d) /x)
64 kind = :operator
65 regexp_allowed=true
66
67 elsif match = scan(/ [$A-Za-z_][A-Za-z_0-9]* /x)
68 kind = IDENT_KIND[match]
69 # if kind == :ident and check(/:(?!:)/)
70 # match << scan(/:/)
71 # kind = :label
72 # end
73 regexp_allowed=false
74
75 elsif match = scan(/["']/)
76 tokens << [:open, :string]
77 string_type = matched
78 state = :string
79 kind = :delimiter
80
81 # elsif scan(/#\s*(\w*)/)
82 # kind = :preprocessor # FIXME multiline preprocs
83 # state = :include_expected if self[1] == 'include'
84 #
85 # elsif scan(/ L?' (?: [^\'\n\\] | \\ #{ESCAPE} )? '? /ox)
86 # kind = :char
87
88 elsif scan(/0[xX][0-9A-Fa-f]+/)
89 kind = :hex
90 regexp_allowed=false
91
92 elsif scan(/(?:0[0-7]+)(?![89.eEfF])/)
93 kind = :oct
94 regexp_allowed=false
95
96 elsif scan(/(?:\d+)(?![.eEfF])/)
97 kind = :integer
98 regexp_allowed=false
99
100 elsif scan(/\d[fF]?|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]?/)
101 kind = :float
102 regexp_allowed=false
103
104 else
105 getch
106 end
107
108 elsif state == :regex
109 if scan(/[^\\\/]+/)
110 kind = :content
111 elsif scan(/\\\/|\\\\/)
112 kind = :content
113 elsif scan(/\//)
114 tokens << [matched, :delimiter]
115 tokens << [:close, :regexp]
116 state = :initial
117 next
118 else
119 getch
120 kind = :content
121 end
122
123 elsif state == :string
124 if scan(/[^\\"']+/)
125 kind = :content
126 elsif scan(/["']/)
127 if string_type==matched
128 tokens << [matched, :delimiter]
129 tokens << [:close, :string]
130 state = :initial
131 string_type=nil
132 next
133 else
134 kind = :content
135 end
136 elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)
137 kind = :char
138 elsif scan(/ \\ | $ /x)
139 kind = :error
140 state = :initial
141 else
142 raise "else case \" reached; %p not handled." % peek(1), tokens
143 end
144
145 # elsif state == :include_expected
146 # if scan(/<[^>\n]+>?|"[^"\n\\]*(?:\\.[^"\n\\]*)*"?/)
147 # kind = :include
148 # state = :initial
149 #
150 # elsif match = scan(/\s+/)
151 # kind = :space
152 # state = :initial if match.index ?\n
153 #
154 # else
155 # getch
156 #
157 # end
158 #
159 else
160 raise 'else-case reached', tokens
161
162 end
163
164 match ||= matched
165 # raise [match, kind], tokens if kind == :error
166
167 tokens << [match, kind]
168
169 end
170 tokens
171
172 end
173
174 end
175
176 end end No newline at end of file
@@ -1,189 +1,190
1 1 module CodeRay
2 2
3 3 # = FileType
4 4 #
5 5 # A simple filetype recognizer.
6 6 #
7 7 # Copyright (c) 2006 by murphy (Kornelius Kalnbach) <murphy rubychan de>
8 8 #
9 9 # License:: LGPL / ask the author
10 10 # Version:: 0.1 (2005-09-01)
11 11 #
12 12 # == Documentation
13 13 #
14 14 # # determine the type of the given
15 15 # lang = FileType[ARGV.first]
16 16 #
17 17 # # return :plaintext if the file type is unknown
18 18 # lang = FileType.fetch ARGV.first, :plaintext
19 19 #
20 20 # # try the shebang line, too
21 21 # lang = FileType.fetch ARGV.first, :plaintext, true
22 22 module FileType
23 23
24 24 UnknownFileType = Class.new Exception
25 25
26 26 class << self
27 27
28 28 # Try to determine the file type of the file.
29 29 #
30 30 # +filename+ is a relative or absolute path to a file.
31 31 #
32 32 # The file itself is only accessed when +read_shebang+ is set to true.
33 33 # That means you can get filetypes from files that don't exist.
34 34 def [] filename, read_shebang = false
35 35 name = File.basename filename
36 36 ext = File.extname name
37 37 ext.sub!(/^\./, '') # delete the leading dot
38 38
39 39 type =
40 40 TypeFromExt[ext] ||
41 41 TypeFromExt[ext.downcase] ||
42 42 TypeFromName[name] ||
43 43 TypeFromName[name.downcase]
44 44 type ||= shebang(filename) if read_shebang
45 45
46 46 type
47 47 end
48 48
49 49 def shebang filename
50 50 begin
51 51 File.open filename, 'r' do |f|
52 52 first_line = f.gets
53 53 first_line[TypeFromShebang]
54 54 end
55 55 rescue IOError
56 56 nil
57 57 end
58 58 end
59 59
60 60 # This works like Hash#fetch.
61 61 #
62 62 # If the filetype cannot be found, the +default+ value
63 63 # is returned.
64 64 def fetch filename, default = nil, read_shebang = false
65 65 if default and block_given?
66 66 warn 'block supersedes default value argument'
67 67 end
68 68
69 69 unless type = self[filename, read_shebang]
70 70 return yield if block_given?
71 71 return default if default
72 72 raise UnknownFileType, 'Could not determine type of %p.' % filename
73 73 end
74 74 type
75 75 end
76 76
77 77 end
78 78
79 79 TypeFromExt = {
80 80 'rb' => :ruby,
81 81 'rbw' => :ruby,
82 82 'rake' => :ruby,
83 83 'mab' => :ruby,
84 84 'cpp' => :c,
85 85 'c' => :c,
86 86 'h' => :c,
87 'js' => :javascript,
87 88 'xml' => :xml,
88 89 'htm' => :html,
89 90 'html' => :html,
90 91 'xhtml' => :xhtml,
91 92 'raydebug' => :debug,
92 93 'rhtml' => :rhtml,
93 94 'ss' => :scheme,
94 95 'sch' => :scheme,
95 96 'yaml' => :yaml,
96 97 'yml' => :yaml,
97 98 }
98 99
99 100 TypeFromShebang = /\b(?:ruby|perl|python|sh)\b/
100 101
101 102 TypeFromName = {
102 103 'Rakefile' => :ruby,
103 104 'Rantfile' => :ruby,
104 105 }
105 106
106 107 end
107 108
108 109 end
109 110
110 111 if $0 == __FILE__
111 112 $VERBOSE = true
112 113 eval DATA.read, nil, $0, __LINE__+4
113 114 end
114 115
115 116 __END__
116 117
117 118 require 'test/unit'
118 119
119 120 class TC_FileType < Test::Unit::TestCase
120 121
121 122 def test_fetch
122 123 assert_raise FileType::UnknownFileType do
123 124 FileType.fetch ''
124 125 end
125 126
126 127 assert_throws :not_found do
127 128 FileType.fetch '.' do
128 129 throw :not_found
129 130 end
130 131 end
131 132
132 133 assert_equal :default, FileType.fetch('c', :default)
133 134
134 135 stderr, fake_stderr = $stderr, Object.new
135 136 $err = ''
136 137 def fake_stderr.write x
137 138 $err << x
138 139 end
139 140 $stderr = fake_stderr
140 141 FileType.fetch('c', :default) { }
141 142 assert_equal "block supersedes default value argument\n", $err
142 143 $stderr = stderr
143 144 end
144 145
145 146 def test_ruby
146 147 assert_equal :ruby, FileType['test.rb']
147 148 assert_equal :ruby, FileType['C:\\Program Files\\x\\y\\c\\test.rbw']
148 149 assert_equal :ruby, FileType['/usr/bin/something/Rakefile']
149 150 assert_equal :ruby, FileType['~/myapp/gem/Rantfile']
150 151 assert_equal :ruby, FileType['./lib/tasks\repository.rake']
151 152 assert_not_equal :ruby, FileType['test_rb']
152 153 assert_not_equal :ruby, FileType['Makefile']
153 154 assert_not_equal :ruby, FileType['set.rb/set']
154 155 assert_not_equal :ruby, FileType['~/projects/blabla/rb']
155 156 end
156 157
157 158 def test_c
158 159 assert_equal :c, FileType['test.c']
159 160 assert_equal :c, FileType['C:\\Program Files\\x\\y\\c\\test.h']
160 161 assert_not_equal :c, FileType['test_c']
161 162 assert_not_equal :c, FileType['Makefile']
162 163 assert_not_equal :c, FileType['set.h/set']
163 164 assert_not_equal :c, FileType['~/projects/blabla/c']
164 165 end
165 166
166 167 def test_html
167 168 assert_equal :html, FileType['test.htm']
168 169 assert_equal :xhtml, FileType['test.xhtml']
169 170 assert_equal :xhtml, FileType['test.html.xhtml']
170 171 assert_equal :rhtml, FileType['_form.rhtml']
171 172 end
172 173
173 174 def test_yaml
174 175 assert_equal :yaml, FileType['test.yml']
175 176 assert_equal :yaml, FileType['test.yaml']
176 177 assert_equal :yaml, FileType['my.html.yaml']
177 178 assert_not_equal :yaml, FileType['YAML']
178 179 end
179 180
180 181 def test_shebang
181 182 dir = './test'
182 183 if File.directory? dir
183 184 Dir.chdir dir do
184 185 assert_equal :c, FileType['test.c']
185 186 end
186 187 end
187 188 end
188 189
189 190 end
General Comments 0
You need to be logged in to leave comments. Login now