starscope 1.3.3 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +29 -0
- data/CHANGELOG.md +15 -1
- data/Gemfile.lock +6 -6
- data/README.md +4 -1
- data/bin/starscope +43 -45
- data/doc/LANGUAGE_SUPPORT.md +27 -10
- data/lib/starscope.rb +2 -2
- data/lib/starscope/db.rb +71 -50
- data/lib/starscope/exportable.rb +38 -41
- data/lib/starscope/fragment_extractor.rb +22 -0
- data/lib/starscope/langs/erb.rb +45 -0
- data/lib/starscope/langs/go.rb +33 -38
- data/lib/starscope/langs/ruby.rb +10 -10
- data/lib/starscope/output.rb +3 -5
- data/lib/starscope/queryable.rb +5 -6
- data/lib/starscope/version.rb +1 -1
- data/starscope.gemspec +6 -6
- data/test/fixtures/db_missing_language.json +15 -0
- data/test/fixtures/db_old_subextractor.json +17 -0
- data/test/fixtures/sample_erb.erb +14 -0
- data/test/fixtures/sample_ruby.rb +14 -16
- data/test/functional/starscope_test.rb +13 -15
- data/test/test_helper.rb +2 -1
- data/test/unit/db_test.rb +55 -28
- data/test/unit/exportable_test.rb +3 -5
- data/test/unit/fragment_extractor_test.rb +38 -0
- data/test/unit/langs/erb_test.rb +36 -0
- data/test/unit/langs/golang_test.rb +13 -13
- data/test/unit/langs/ruby_test.rb +14 -14
- data/test/unit/output_test.rb +9 -11
- data/test/unit/queryable_test.rb +19 -20
- metadata +18 -6
- data/lib/starscope/langs/coffeescript.rb +0 -13
data/lib/starscope/exportable.rb
CHANGED
@@ -1,25 +1,24 @@
|
|
1
1
|
module Starscope::Exportable
|
2
|
-
|
3
|
-
|
4
|
-
CSCOPE_DEFAULT_PATH='cscope.out'
|
2
|
+
CTAGS_DEFAULT_PATH = 'tags'
|
3
|
+
CSCOPE_DEFAULT_PATH = 'cscope.out'
|
5
4
|
|
6
5
|
class UnknownExportFormatError < StandardError; end
|
7
6
|
|
8
|
-
def export(format, path=nil)
|
7
|
+
def export(format, path = nil)
|
9
8
|
case format
|
10
9
|
when :ctags
|
11
10
|
path ||= CTAGS_DEFAULT_PATH
|
12
11
|
when :cscope
|
13
12
|
path ||= CSCOPE_DEFAULT_PATH
|
14
13
|
else
|
15
|
-
|
14
|
+
fail UnknownExportFormatError
|
16
15
|
end
|
17
16
|
|
18
17
|
@output.normal("Exporting to '#{path}' in format '#{format}'...")
|
19
18
|
File.open(path, 'w') do |file|
|
20
19
|
export_to(format, file)
|
21
20
|
end
|
22
|
-
@output.normal(
|
21
|
+
@output.normal('Export complete.')
|
23
22
|
end
|
24
23
|
|
25
24
|
def export_to(format, io)
|
@@ -29,7 +28,7 @@ module Starscope::Exportable
|
|
29
28
|
when :cscope
|
30
29
|
export_cscope(io)
|
31
30
|
else
|
32
|
-
|
31
|
+
fail UnknownExportFormatError
|
33
32
|
end
|
34
33
|
end
|
35
34
|
|
@@ -44,7 +43,7 @@ module Starscope::Exportable
|
|
44
43
|
!_TAG_PROGRAM_URL https://github.com/eapache/starscope //
|
45
44
|
!_TAG_PROGRAM_VERSION #{Starscope::VERSION} //
|
46
45
|
END
|
47
|
-
defs = (@tables[:defs] || {}).sort_by {|x| x[:name][-1].to_s}
|
46
|
+
defs = (@tables[:defs] || {}).sort_by { |x| x[:name][-1].to_s }
|
48
47
|
defs.each do |record|
|
49
48
|
file.puts ctag_line(record, @meta[:files][record[:file]])
|
50
49
|
end
|
@@ -55,7 +54,7 @@ END
|
|
55
54
|
ret = "#{rec[:name][-1]}\t#{rec[:file]}\t/^#{line}$/"
|
56
55
|
|
57
56
|
ext = ctag_ext_tags(rec, file)
|
58
|
-
|
57
|
+
unless ext.empty?
|
59
58
|
ret << ";\""
|
60
59
|
ext.sort.each do |k, v|
|
61
60
|
ret << "\t#{k}:#{v}"
|
@@ -71,12 +70,12 @@ END
|
|
71
70
|
# these extensions are documented at http://ctags.sourceforge.net/FORMAT
|
72
71
|
case rec[:type]
|
73
72
|
when :func
|
74
|
-
tag[
|
73
|
+
tag['kind'] = 'f'
|
75
74
|
when :module, :class
|
76
|
-
tag[
|
75
|
+
tag['kind'] = 'c'
|
77
76
|
end
|
78
77
|
|
79
|
-
tag[
|
78
|
+
tag['language'] = file[:lang]
|
80
79
|
|
81
80
|
tag
|
82
81
|
end
|
@@ -91,9 +90,9 @@ END
|
|
91
90
|
|
92
91
|
# ftp://ftp.eeng.dcu.ie/pub/ee454/cygwin/usr/share/doc/mlcscope-14.1.8/html/cscope.html
|
93
92
|
def export_cscope(file)
|
94
|
-
buf =
|
93
|
+
buf = ''
|
95
94
|
files = []
|
96
|
-
db_by_line
|
95
|
+
db_by_line.each do |filename, lines|
|
97
96
|
next if lines.empty?
|
98
97
|
|
99
98
|
buf << "\t@#{filename}\n\n"
|
@@ -107,9 +106,8 @@ END
|
|
107
106
|
next if toks.empty?
|
108
107
|
|
109
108
|
prev = 0
|
110
|
-
buf << line_no.to_s <<
|
109
|
+
buf << line_no.to_s << ' '
|
111
110
|
toks.each do |offset, record|
|
112
|
-
|
113
111
|
next if offset < prev # this probably indicates an extractor bug
|
114
112
|
|
115
113
|
# Don't export nested functions, cscope barfs on them since C doesn't
|
@@ -128,7 +126,6 @@ END
|
|
128
126
|
|
129
127
|
buf << cscope_output(line, prev, offset, record)
|
130
128
|
prev = offset + record[:key].length
|
131
|
-
|
132
129
|
end
|
133
130
|
buf << cscope_plaintext(line, prev, line.length) << "\n\n"
|
134
131
|
end
|
@@ -144,19 +141,19 @@ END
|
|
144
141
|
file.print(buf)
|
145
142
|
|
146
143
|
file.print("#{@meta[:paths].length}\n")
|
147
|
-
@meta[:paths].each {|p| file.print("#{p}\n")}
|
144
|
+
@meta[:paths].each { |p| file.print("#{p}\n") }
|
148
145
|
file.print("0\n")
|
149
146
|
file.print("#{files.length}\n")
|
150
|
-
buf =
|
151
|
-
files.each {|f| buf << f + "\n"}
|
147
|
+
buf = ''
|
148
|
+
files.each { |f| buf << f + "\n" }
|
152
149
|
file.print("#{buf.length}\n#{buf}")
|
153
150
|
end
|
154
151
|
|
155
|
-
def db_by_line
|
152
|
+
def db_by_line
|
156
153
|
db = {}
|
157
154
|
@tables.each do |tbl, records|
|
158
155
|
records.each do |record|
|
159
|
-
next
|
156
|
+
next unless record[:line_no]
|
160
157
|
record[:tbl] = tbl
|
161
158
|
db[record[:file]] ||= {}
|
162
159
|
db[record[:file]][record[:line_no]] ||= []
|
@@ -176,7 +173,7 @@ END
|
|
176
173
|
index = record[:col] || line.index(key)
|
177
174
|
|
178
175
|
while index && !valid_index?(line, index, key)
|
179
|
-
index = line.index(key, index+1)
|
176
|
+
index = line.index(key, index + 1)
|
180
177
|
end
|
181
178
|
|
182
179
|
next if index.nil?
|
@@ -197,7 +194,7 @@ END
|
|
197
194
|
end
|
198
195
|
|
199
196
|
def cscope_output(line, prev, offset, record)
|
200
|
-
buf =
|
197
|
+
buf = ''
|
201
198
|
buf << CSCOPE_GLOBAL_HACK_STOP if record[:type] == :func && record[:tbl] == :defs
|
202
199
|
|
203
200
|
record[:name][0...-1].each do |key|
|
@@ -207,11 +204,11 @@ END
|
|
207
204
|
|
208
205
|
index = line.index(key, prev)
|
209
206
|
|
210
|
-
while index && index+key.length < offset && !valid_index?(line, index, key)
|
211
|
-
index = line.index(key, index+1)
|
207
|
+
while index && index + key.length < offset && !valid_index?(line, index, key)
|
208
|
+
index = line.index(key, index + 1)
|
212
209
|
end
|
213
210
|
|
214
|
-
if index && index+key.length < offset
|
211
|
+
if index && index + key.length < offset
|
215
212
|
buf << cscope_plaintext(line, prev, index) << "\n"
|
216
213
|
buf << "#{key}\n"
|
217
214
|
prev = index + key.length
|
@@ -231,12 +228,12 @@ END
|
|
231
228
|
def valid_index?(line, index, key)
|
232
229
|
# index is valid if the key exists at it, and the prev/next chars are not word characters
|
233
230
|
((line[index, key.length] == key) &&
|
234
|
-
(index == 0 || line[index-1] !~ /\w/) &&
|
235
|
-
(index+key.length == line.length || line[index+key.length] !~ /\w/))
|
231
|
+
(index == 0 || line[index - 1] !~ /\w/) &&
|
232
|
+
(index + key.length == line.length || line[index + key.length] !~ /\w/))
|
236
233
|
end
|
237
234
|
|
238
235
|
def cscope_plaintext(line, start, stop)
|
239
|
-
ret = line.slice(start, stop-start)
|
236
|
+
ret = line.slice(start, stop - start)
|
240
237
|
ret.lstrip! if start == 0
|
241
238
|
ret.rstrip! if stop == line.length
|
242
239
|
ret.gsub(/\s+/, ' ')
|
@@ -250,33 +247,33 @@ END
|
|
250
247
|
when :end
|
251
248
|
case rec[:type]
|
252
249
|
when :func
|
253
|
-
ret =
|
250
|
+
ret = '}'
|
254
251
|
else
|
255
|
-
return
|
252
|
+
return ''
|
256
253
|
end
|
257
254
|
when :file
|
258
|
-
ret =
|
255
|
+
ret = '@'
|
259
256
|
when :defs
|
260
257
|
case rec[:type]
|
261
258
|
when :func
|
262
|
-
ret =
|
259
|
+
ret = '$'
|
263
260
|
when :class, :module
|
264
|
-
ret =
|
261
|
+
ret = 'c'
|
265
262
|
when :type
|
266
|
-
ret =
|
263
|
+
ret = 't'
|
267
264
|
else
|
268
|
-
ret =
|
265
|
+
ret = 'g'
|
269
266
|
end
|
270
267
|
when :calls
|
271
|
-
ret =
|
268
|
+
ret = '`'
|
272
269
|
when :requires
|
273
270
|
ret = "~\""
|
274
271
|
when :imports
|
275
|
-
ret =
|
272
|
+
ret = '~<'
|
276
273
|
when :assigns
|
277
|
-
ret =
|
274
|
+
ret = '='
|
278
275
|
else
|
279
|
-
return
|
276
|
+
return ''
|
280
277
|
end
|
281
278
|
|
282
279
|
"\t" + ret
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Starscope::FragmentExtractor
|
2
|
+
def initialize(lang, frags)
|
3
|
+
@child = Starscope::Lang.const_get(lang)
|
4
|
+
@frags = frags
|
5
|
+
end
|
6
|
+
|
7
|
+
def extract(path, text)
|
8
|
+
text = @frags.map { |f| f.delete(:frag).strip }.join("\n")
|
9
|
+
|
10
|
+
extractor_metadata = @child.extract(path, text) do |tbl, name, args|
|
11
|
+
args.merge!(@frags[args[:line_no] - 1]) if args[:line_no]
|
12
|
+
yield tbl, name, args
|
13
|
+
end
|
14
|
+
|
15
|
+
# TODO: translate metadata?
|
16
|
+
extractor_metadata
|
17
|
+
end
|
18
|
+
|
19
|
+
def name
|
20
|
+
@child.name
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Starscope::Lang
|
2
|
+
module ERB
|
3
|
+
VERSION = 1
|
4
|
+
|
5
|
+
ERB_START = /<%(?:-|={1,4})?/
|
6
|
+
ERB_END = /-?%>/
|
7
|
+
|
8
|
+
def self.match_file(name)
|
9
|
+
name.end_with?('.erb')
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.extract(path, contents, &block)
|
13
|
+
multiline = false # true when parsing a multiline <% ... %> block
|
14
|
+
|
15
|
+
contents.lines.each_with_index do |line, line_no|
|
16
|
+
line_no += 1 # zero-index to one-index
|
17
|
+
|
18
|
+
if multiline
|
19
|
+
term = line.index(ERB_END)
|
20
|
+
if term
|
21
|
+
yield FRAGMENT, :Ruby, :frag => line[0...term], :line_no => line_no
|
22
|
+
line = line[term + 1..-1]
|
23
|
+
multiline = false
|
24
|
+
else
|
25
|
+
yield FRAGMENT, :Ruby, :frag => line, :line_no => line_no
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
unless multiline
|
30
|
+
line.scan(/#{ERB_START}(.*?)#{ERB_END}/) do |match|
|
31
|
+
yield FRAGMENT, :Ruby, :frag => match[0], :line_no => line_no
|
32
|
+
end
|
33
|
+
|
34
|
+
line.gsub!(/<%.*?%>/, '')
|
35
|
+
|
36
|
+
match = /#{ERB_START}(.*)$/.match(line)
|
37
|
+
if match
|
38
|
+
yield FRAGMENT, :Ruby, :frag => match[1], :line_no => line_no
|
39
|
+
multiline = true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/starscope/langs/go.rb
CHANGED
@@ -6,42 +6,39 @@ module Starscope::Lang
|
|
6
6
|
END_OF_BLOCK = /^\s*\}\s*$/
|
7
7
|
END_OF_GROUP = /^\s*\)\s*$/
|
8
8
|
STRING_LITERAL = /".+?"/
|
9
|
-
BUILTIN_FUNCS =
|
10
|
-
|
11
|
-
'uint', 'uint8', 'uint16', 'uint32', 'uint64',
|
12
|
-
'string', 'byte']
|
13
|
-
CONTROL_KEYS = ['if', 'for', 'switch', 'case']
|
9
|
+
BUILTIN_FUNCS = %w(new make len close copy delete int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 string byte)
|
10
|
+
CONTROL_KEYS = %w(if for switch case)
|
14
11
|
|
15
12
|
def self.match_file(name)
|
16
|
-
name.end_with?(
|
13
|
+
name.end_with?('.go')
|
17
14
|
end
|
18
15
|
|
19
|
-
def self.extract(
|
16
|
+
def self.extract(path, contents, &block)
|
20
17
|
stack = []
|
21
18
|
scope = []
|
22
|
-
|
19
|
+
contents.lines.each_with_index do |line, line_no|
|
23
20
|
line_no += 1 # zero-index to one-index
|
24
21
|
|
25
22
|
# strip single-line comments like // foo
|
26
|
-
match =
|
23
|
+
match = %r{//}.match(line)
|
27
24
|
line = match.pre_match if match
|
28
25
|
# strip single-line comments like foo /* foo */ foo
|
29
|
-
match =
|
26
|
+
match = %r{/\*.*\*/}.match(line)
|
30
27
|
line = match.pre_match + match.post_match if match
|
31
28
|
# strip end-of-line comment starters like foo /* foo \n
|
32
|
-
match =
|
29
|
+
match = %r{/\*}.match(line)
|
33
30
|
line = match.pre_match if match
|
34
31
|
ends_with_comment = !match.nil?
|
35
32
|
|
36
33
|
# if we're in a block comment, wait for it to end
|
37
34
|
if stack[-1] == :comment
|
38
|
-
match =
|
35
|
+
match = %r{\*/(.*)}.match(line)
|
39
36
|
next unless match
|
40
37
|
line = match[1]
|
41
38
|
stack.pop
|
42
39
|
end
|
43
40
|
|
44
|
-
if stack[-1] != :import && !line.start_with?(
|
41
|
+
if stack[-1] != :import && !line.start_with?('import')
|
45
42
|
# strip string literals like "foo" unless they're part of an import
|
46
43
|
pos = 0
|
47
44
|
while match = STRING_LITERAL.match(line[pos..-1])
|
@@ -58,21 +55,21 @@ module Starscope::Lang
|
|
58
55
|
when END_OF_BLOCK
|
59
56
|
end_block(line_no, scope, stack, &block)
|
60
57
|
when /(.+)\s+\w+/
|
61
|
-
parse_def(
|
58
|
+
parse_def(Regexp.last_match(1), line_no, scope, &block)
|
62
59
|
end
|
63
60
|
when :interface
|
64
61
|
case line
|
65
62
|
when END_OF_BLOCK
|
66
63
|
end_block(line_no, scope, stack, &block)
|
67
64
|
when /(\w+)\(.*\)\s+/
|
68
|
-
yield :defs, scope + [
|
65
|
+
yield :defs, scope + [Regexp.last_match(1)], :line_no => line_no
|
69
66
|
end
|
70
67
|
when :def
|
71
68
|
case line
|
72
69
|
when END_OF_GROUP
|
73
70
|
stack.pop
|
74
71
|
when /(.+)\s*=.*/
|
75
|
-
parse_def(
|
72
|
+
parse_def(Regexp.last_match(1), line_no, scope, &block)
|
76
73
|
parse_call(line, line_no, scope, &block)
|
77
74
|
else
|
78
75
|
parse_def(line, line_no, scope, &block)
|
@@ -82,13 +79,13 @@ module Starscope::Lang
|
|
82
79
|
when END_OF_GROUP
|
83
80
|
stack.pop
|
84
81
|
when /"(.+)"/
|
85
|
-
name =
|
82
|
+
name = Regexp.last_match(1).split('/')
|
86
83
|
yield :imports, name, :line_no => line_no
|
87
84
|
end
|
88
85
|
when :func
|
89
86
|
case line
|
90
87
|
when /^\}/
|
91
|
-
yield :end,
|
88
|
+
yield :end, '}', :line_no => line_no, :type => :func
|
92
89
|
stack.pop
|
93
90
|
else
|
94
91
|
parse_new_line(line, line_no, scope, stack, &block)
|
@@ -99,9 +96,7 @@ module Starscope::Lang
|
|
99
96
|
|
100
97
|
# if the line looks like "foo /* foo" then we enter the comment state
|
101
98
|
# after parsing the usable part of the line
|
102
|
-
if ends_with_comment
|
103
|
-
stack.push(:comment)
|
104
|
-
end
|
99
|
+
stack.push(:comment) if ends_with_comment
|
105
100
|
end
|
106
101
|
end
|
107
102
|
|
@@ -109,44 +104,44 @@ module Starscope::Lang
|
|
109
104
|
def self.parse_new_line(line, line_no, scope, stack, &block)
|
110
105
|
case line
|
111
106
|
when /^func\s+(\w+)\(/
|
112
|
-
yield :defs, scope + [
|
107
|
+
yield :defs, scope + [Regexp.last_match(1)], :line_no => line_no, :type => :func
|
113
108
|
stack.push(:func)
|
114
109
|
when /^func\s+\(\w+\s+\*?(\w+)\)\s*(\w+)\(/
|
115
|
-
yield :defs, scope + [
|
110
|
+
yield :defs, scope + [Regexp.last_match(1), Regexp.last_match(2)], :line_no => line_no, :type => :func
|
116
111
|
stack.push(:func)
|
117
112
|
when /^package\s+(\w+)/
|
118
|
-
scope.push(
|
113
|
+
scope.push(Regexp.last_match(1))
|
119
114
|
yield :defs, scope, :line_no => line_no, :type => :package
|
120
115
|
when /^type\s+(\w+)\s+struct\s*\{/
|
121
|
-
scope.push(
|
116
|
+
scope.push(Regexp.last_match(1))
|
122
117
|
stack.push(:struct)
|
123
118
|
yield :defs, scope, :line_no => line_no, :type => :class
|
124
119
|
when /^type\s+(\w+)\s+interface\s*\{/
|
125
|
-
scope.push(
|
120
|
+
scope.push(Regexp.last_match(1))
|
126
121
|
stack.push(:interface)
|
127
122
|
yield :defs, scope, :line_no => line_no, :type => :class
|
128
123
|
when /^type\s+(\w+)/
|
129
|
-
yield :defs, scope + [
|
124
|
+
yield :defs, scope + [Regexp.last_match(1)], :line_no => line_no, :type => :type
|
130
125
|
when /^import\s+"(.+)"/
|
131
|
-
name =
|
126
|
+
name = Regexp.last_match(1).split('/')
|
132
127
|
yield :imports, name, :line_no => line_no
|
133
128
|
when /^import\s+\(/
|
134
129
|
stack.push(:import)
|
135
130
|
when /^var\s+\(/
|
136
131
|
stack.push(:def)
|
137
132
|
when /^var\s+(\w+)\s/
|
138
|
-
yield :defs, scope + [
|
133
|
+
yield :defs, scope + [Regexp.last_match(1)], :line_no => line_no
|
139
134
|
parse_call(line, line_no, scope, &block)
|
140
135
|
when /^const\s+\(/
|
141
136
|
stack.push(:def)
|
142
137
|
when /^const\s+(\w+)\s/
|
143
|
-
yield :defs, scope + [
|
138
|
+
yield :defs, scope + [Regexp.last_match(1)], :line_no => line_no
|
144
139
|
parse_call(line, line_no, scope, &block)
|
145
140
|
when /^\s+(.*?) :?=[^=]/
|
146
|
-
|
141
|
+
Regexp.last_match(1).split(' ').each do |var|
|
147
142
|
next if CONTROL_KEYS.include?(var)
|
148
143
|
name = var.delete(',').split('.')
|
149
|
-
next if name[0] ==
|
144
|
+
next if name[0] == '_' # assigning to _ is a discard in golang
|
150
145
|
if name.length == 1
|
151
146
|
yield :assigns, scope + [name[0]], :line_no => line_no
|
152
147
|
else
|
@@ -161,7 +156,7 @@ module Starscope::Lang
|
|
161
156
|
|
162
157
|
def self.parse_call(line, line_no, scope)
|
163
158
|
line.scan(FUNC_CALL) do |match|
|
164
|
-
name = match[0].split('.').select {|chunk|
|
159
|
+
name = match[0].split('.').select { |chunk| !chunk.empty? }
|
165
160
|
if name.length == 1
|
166
161
|
next if name[0] == 'func'
|
167
162
|
if BUILTIN_FUNCS.include?(name[0])
|
@@ -178,23 +173,23 @@ module Starscope::Lang
|
|
178
173
|
def self.parse_def(line, line_no, scope)
|
179
174
|
# if it doesn't start with a valid identifier character, it's probably
|
180
175
|
# part of a multi-line literal and we should skip it
|
181
|
-
return
|
176
|
+
return unless line =~ /^\s*[[:alpha:]_]/
|
182
177
|
|
183
178
|
line.split.each do |var|
|
184
179
|
yield :defs, scope + [var.delete(',')], :line_no => line_no
|
185
|
-
break
|
180
|
+
break unless var.end_with?(',')
|
186
181
|
end
|
187
182
|
end
|
188
183
|
|
189
184
|
def self.end_block(line_no, scope, stack)
|
190
|
-
yield :end, scope + [
|
185
|
+
yield :end, scope + ['}'], :line_no => line_no, :type => :class
|
191
186
|
stack.pop
|
192
187
|
scope.pop
|
193
188
|
end
|
194
189
|
|
195
190
|
def self.find_end_of_string(line, start)
|
196
191
|
escape = false
|
197
|
-
(start+1...line.length).each do |i|
|
192
|
+
(start + 1...line.length).each do |i|
|
198
193
|
if escape
|
199
194
|
escape = false
|
200
195
|
elsif line[i].chr == '\\'
|
@@ -204,7 +199,7 @@ module Starscope::Lang
|
|
204
199
|
end
|
205
200
|
end
|
206
201
|
|
207
|
-
|
202
|
+
line.length
|
208
203
|
end
|
209
204
|
end
|
210
205
|
end
|