solargraph 0.20.0 → 0.21.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/lib/solargraph.rb +2 -3
- data/lib/solargraph/api_map.rb +6 -6
- data/lib/solargraph/api_map/source_to_yard.rb +1 -1
- data/lib/solargraph/language_server/host.rb +69 -10
- data/lib/solargraph/language_server/message.rb +1 -2
- data/lib/solargraph/language_server/message/initialize.rb +83 -15
- data/lib/solargraph/language_server/message/initialized.rb +7 -0
- data/lib/solargraph/language_server/message/text_document/formatting.rb +4 -1
- data/lib/solargraph/language_server/message/text_document/on_type_formatting.rb +20 -19
- data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +19 -1
- data/lib/solargraph/language_server/request.rb +1 -1
- data/lib/solargraph/language_server/transport.rb +1 -0
- data/lib/solargraph/language_server/transport/data_reader.rb +66 -0
- data/lib/solargraph/language_server/transport/socket.rb +8 -32
- data/lib/solargraph/library.rb +11 -6
- data/lib/solargraph/page.rb +1 -1
- data/lib/solargraph/pin/base.rb +8 -7
- data/lib/solargraph/pin/method_parameter.rb +2 -15
- data/lib/solargraph/pin/yard_object.rb +1 -1
- data/lib/solargraph/plugin/runtime.rb +0 -2
- data/lib/solargraph/shell.rb +0 -24
- data/lib/solargraph/source.rb +5 -169
- data/lib/solargraph/source/mapper.rb +8 -3
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/workspace.rb +3 -3
- data/lib/solargraph/workspace/config.rb +7 -9
- data/lib/solargraph/yard_map.rb +9 -48
- metadata +17 -74
- data/lib/solargraph/server.rb +0 -212
- data/lib/solargraph/suggestion.rb +0 -178
@@ -0,0 +1,66 @@
|
|
1
|
+
module Solargraph
|
2
|
+
module LanguageServer
|
3
|
+
module Transport
|
4
|
+
class DataReader
|
5
|
+
def initialize
|
6
|
+
@in_header = true
|
7
|
+
@content_length = 0
|
8
|
+
@buffer = ''
|
9
|
+
end
|
10
|
+
|
11
|
+
# Declare a block to be executed for each message received from the
|
12
|
+
# client.
|
13
|
+
#
|
14
|
+
# @yieldparam [Hash] The message received from the client
|
15
|
+
def set_message_handler &block
|
16
|
+
@message_handler = block
|
17
|
+
end
|
18
|
+
|
19
|
+
# Process raw data received from the client. The data will be parsed
|
20
|
+
# into messages based on the JSON-RPC protocol. Each message will be
|
21
|
+
# passed to the block declared via set_message_handler. Incomplete data
|
22
|
+
# will be buffered and subsequent data will be appended to the buffer.
|
23
|
+
#
|
24
|
+
# @param data [String]
|
25
|
+
def receive data
|
26
|
+
data.each_char do |char|
|
27
|
+
@buffer.concat char
|
28
|
+
if @in_header
|
29
|
+
prepare_to_parse_message if @buffer.end_with?("\r\n\r\n")
|
30
|
+
else
|
31
|
+
parse_message_from_buffer if @buffer.bytesize == @content_length
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def prepare_to_parse_message
|
39
|
+
@in_header = false
|
40
|
+
@buffer.each_line do |line|
|
41
|
+
parts = line.split(':').map(&:strip)
|
42
|
+
if parts[0] == 'Content-Length'
|
43
|
+
@content_length = parts[1].to_i
|
44
|
+
break
|
45
|
+
end
|
46
|
+
end
|
47
|
+
@buffer.clear
|
48
|
+
end
|
49
|
+
|
50
|
+
def parse_message_from_buffer
|
51
|
+
begin
|
52
|
+
msg = JSON.parse(@buffer)
|
53
|
+
@message_handler.call msg unless @message_handler.nil?
|
54
|
+
rescue JSON::ParserError => e
|
55
|
+
STDERR.puts "Failed to parse request: #{e.message}"
|
56
|
+
STDERR.puts "Buffer: #{@buffer}"
|
57
|
+
ensure
|
58
|
+
@buffer.clear
|
59
|
+
@in_header = true
|
60
|
+
@content_length = 0
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -11,50 +11,26 @@ module Solargraph
|
|
11
11
|
@content_length = 0
|
12
12
|
@buffer = ''
|
13
13
|
@host = Solargraph::LanguageServer::Host.new
|
14
|
+
@data_reader = Solargraph::LanguageServer::Transport::DataReader.new
|
15
|
+
@data_reader.set_message_handler do |message|
|
16
|
+
process message
|
17
|
+
end
|
14
18
|
start_timers
|
15
19
|
end
|
16
20
|
|
17
|
-
def process
|
21
|
+
def process message
|
18
22
|
Thread.new do
|
19
|
-
message = @host.start(
|
23
|
+
message = @host.start(message)
|
20
24
|
message.send
|
21
25
|
tmp = @host.flush
|
22
26
|
send_data tmp unless tmp.empty?
|
23
|
-
GC.start unless
|
27
|
+
GC.start unless message['method'] == 'textDocument/didChange'
|
24
28
|
end
|
25
29
|
end
|
26
30
|
|
27
31
|
# @param data [String]
|
28
32
|
def receive_data data
|
29
|
-
|
30
|
-
@buffer.concat char
|
31
|
-
if @in_header
|
32
|
-
if @buffer.end_with?("\r\n\r\n")
|
33
|
-
@in_header = false
|
34
|
-
@buffer.each_line do |line|
|
35
|
-
parts = line.split(':').map(&:strip)
|
36
|
-
if parts[0] == 'Content-Length'
|
37
|
-
@content_length = parts[1].to_i
|
38
|
-
break
|
39
|
-
end
|
40
|
-
end
|
41
|
-
@buffer.clear
|
42
|
-
end
|
43
|
-
else
|
44
|
-
if @buffer.bytesize == @content_length
|
45
|
-
begin
|
46
|
-
process JSON.parse(@buffer)
|
47
|
-
rescue JSON::ParserError => e
|
48
|
-
STDERR.puts "Failed to parse request: #{e.message}"
|
49
|
-
STDERR.puts "Buffer: #{@buffer}"
|
50
|
-
ensure
|
51
|
-
@buffer.clear
|
52
|
-
@in_header = true
|
53
|
-
@content_length = 0
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
33
|
+
@data_reader.receive data
|
58
34
|
end
|
59
35
|
|
60
36
|
private
|
data/lib/solargraph/library.rb
CHANGED
@@ -162,7 +162,7 @@ module Solargraph
|
|
162
162
|
# will be removed from the ApiMap. Only one file can be checked out
|
163
163
|
# (virtualized) at a time.
|
164
164
|
#
|
165
|
-
# @raise [FileNotFoundError] if the file
|
165
|
+
# @raise [FileNotFoundError] if the file does not exist.
|
166
166
|
#
|
167
167
|
# @param filename [String]
|
168
168
|
# @return [Source]
|
@@ -256,14 +256,19 @@ module Solargraph
|
|
256
256
|
@workspace
|
257
257
|
end
|
258
258
|
|
259
|
-
#
|
259
|
+
# Get the source for an open file or create a new source if the file
|
260
|
+
# exists on disk. Sources created from disk are not added to the open
|
261
|
+
# workspace files, i.e., the version on disk remains the authoritative
|
262
|
+
# version.
|
263
|
+
#
|
264
|
+
# @raise [FileNotFoundError] if the file does not exist
|
260
265
|
# @param filename [String]
|
261
266
|
# @return [Solargraph::Source]
|
262
267
|
def read filename
|
263
|
-
|
264
|
-
|
265
|
-
#
|
266
|
-
|
268
|
+
return source_hash[filename] if open?(filename)
|
269
|
+
return workspace.source(filename) if workspace.has_file?(filename)
|
270
|
+
raise FileNotFoundError, "File not found: #{filename}" unless File.file?(filename)
|
271
|
+
Solargraph::Source.load(filename)
|
267
272
|
end
|
268
273
|
end
|
269
274
|
end
|
data/lib/solargraph/page.rb
CHANGED
data/lib/solargraph/pin/base.rb
CHANGED
@@ -6,20 +6,25 @@ module Solargraph
|
|
6
6
|
include Conversions
|
7
7
|
include Documenting
|
8
8
|
|
9
|
+
# @return [Solargraph::Source::Location]
|
9
10
|
attr_reader :location
|
10
11
|
|
11
12
|
# @return [String]
|
12
13
|
attr_reader :namespace
|
13
14
|
|
15
|
+
# @return [String]
|
14
16
|
attr_reader :name
|
15
17
|
|
18
|
+
# @return [YARD::Docstring]
|
16
19
|
attr_reader :docstring
|
17
20
|
|
18
21
|
# @return [String]
|
19
22
|
attr_reader :return_type
|
20
23
|
|
24
|
+
# @return [Integer]
|
21
25
|
attr_reader :kind
|
22
26
|
|
27
|
+
# @return [String]
|
23
28
|
attr_reader :path
|
24
29
|
|
25
30
|
def initialize location, namespace, name, docstring
|
@@ -29,18 +34,12 @@ module Solargraph
|
|
29
34
|
@docstring = docstring
|
30
35
|
end
|
31
36
|
|
37
|
+
# @return [String]
|
32
38
|
def filename
|
33
39
|
location.filename
|
34
40
|
end
|
35
41
|
|
36
|
-
# @return [String]
|
37
|
-
def path
|
38
|
-
end
|
39
|
-
|
40
42
|
# @return [Integer]
|
41
|
-
def kind
|
42
|
-
end
|
43
|
-
|
44
43
|
def completion_item_kind
|
45
44
|
LanguageServer::CompletionItemKinds::KEYWORD
|
46
45
|
end
|
@@ -49,6 +48,7 @@ module Solargraph
|
|
49
48
|
name.to_s
|
50
49
|
end
|
51
50
|
|
51
|
+
# @return [String]
|
52
52
|
def identifier
|
53
53
|
@identifier ||= "#{path}|#{name}"
|
54
54
|
end
|
@@ -57,6 +57,7 @@ module Solargraph
|
|
57
57
|
false
|
58
58
|
end
|
59
59
|
|
60
|
+
# @return [String]
|
60
61
|
def named_context
|
61
62
|
namespace
|
62
63
|
end
|
@@ -1,20 +1,6 @@
|
|
1
1
|
module Solargraph
|
2
2
|
module Pin
|
3
|
-
class MethodParameter <
|
4
|
-
include Localized
|
5
|
-
|
6
|
-
attr_reader :block
|
7
|
-
|
8
|
-
def initialize location, namespace, name, docstring, block
|
9
|
-
super(location, namespace, name, docstring)
|
10
|
-
@block = block
|
11
|
-
@presence = block.location.range
|
12
|
-
end
|
13
|
-
|
14
|
-
def completion_item_kind
|
15
|
-
Solargraph::LanguageServer::CompletionItemKinds::VARIABLE
|
16
|
-
end
|
17
|
-
|
3
|
+
class MethodParameter < LocalVariable
|
18
4
|
def return_type
|
19
5
|
if @return_type.nil? and !block.docstring.nil?
|
20
6
|
found = nil
|
@@ -25,6 +11,7 @@ module Solargraph
|
|
25
11
|
end
|
26
12
|
@return_type = found.types[0] unless found.nil? or found.types.nil?
|
27
13
|
end
|
14
|
+
super
|
28
15
|
@return_type
|
29
16
|
end
|
30
17
|
end
|
@@ -44,7 +44,6 @@ module Solargraph
|
|
44
44
|
false
|
45
45
|
else
|
46
46
|
if @current_required != api_map.required
|
47
|
-
STDERR.puts "Restarting #{self.class} process"
|
48
47
|
@io.close unless @io.nil? or @io.closed?
|
49
48
|
start_process
|
50
49
|
true
|
@@ -70,7 +69,6 @@ module Solargraph
|
|
70
69
|
unless api_map.nil? or api_map.workspace.nil?
|
71
70
|
dir = api_map.workspace
|
72
71
|
end
|
73
|
-
STDERR.puts "Starting #{self.class} process in #{dir}"
|
74
72
|
Dir.chdir(dir) do
|
75
73
|
@io = IO.popen(executable, 'r+')
|
76
74
|
end
|
data/lib/solargraph/shell.rb
CHANGED
@@ -16,30 +16,6 @@ module Solargraph
|
|
16
16
|
puts Solargraph::VERSION
|
17
17
|
end
|
18
18
|
|
19
|
-
desc 'server', 'Start a Solargraph server'
|
20
|
-
option :port, type: :numeric, aliases: :p, desc: 'The server port', default: 7657
|
21
|
-
option :views, type: :string, aliases: :v, desc: 'The view template directory', default: nil
|
22
|
-
option :files, type: :string, aliases: :f, desc: 'The public files directory', default: nil
|
23
|
-
def server
|
24
|
-
port = options[:port]
|
25
|
-
port = available_port if port.zero?
|
26
|
-
Solargraph::Server.set :port, port
|
27
|
-
Solargraph::Server.set :views, options[:views] unless options[:views].nil?
|
28
|
-
Solargraph::Server.set :public_folder, options[:files] unless options[:files].nil?
|
29
|
-
my_pid = nil
|
30
|
-
Solargraph::Server.run! do
|
31
|
-
# This line should not be necessary with WEBrick
|
32
|
-
#STDERR.puts "Solargraph server pid=#{Process.pid} port=#{port}"
|
33
|
-
my_pid = Process.pid
|
34
|
-
Signal.trap("INT") do
|
35
|
-
Solargraph::Server.stop!
|
36
|
-
end
|
37
|
-
Signal.trap("TERM") do
|
38
|
-
Solargraph::Server.stop!
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
19
|
desc 'socket', 'Run a Solargraph socket server'
|
44
20
|
option :host, type: :string, aliases: :h, desc: 'The server host', default: '127.0.0.1'
|
45
21
|
option :port, type: :numeric, aliases: :p, desc: 'The server port', default: 7658
|
data/lib/solargraph/source.rb
CHANGED
@@ -58,7 +58,7 @@ module Solargraph
|
|
58
58
|
@version = 0
|
59
59
|
begin
|
60
60
|
parse
|
61
|
-
rescue Parser::SyntaxError
|
61
|
+
rescue Parser::SyntaxError, EncodingError
|
62
62
|
hard_fix_node
|
63
63
|
end
|
64
64
|
end
|
@@ -79,7 +79,6 @@ module Solargraph
|
|
79
79
|
|
80
80
|
# @return [Array<String>]
|
81
81
|
def namespaces
|
82
|
-
# @namespaces ||= namespace_pin_map.keys
|
83
82
|
@namespaces ||= pins.select{|pin| pin.kind == Pin::NAMESPACE}.map(&:path)
|
84
83
|
end
|
85
84
|
|
@@ -156,25 +155,6 @@ module Solargraph
|
|
156
155
|
found || pins.first
|
157
156
|
end
|
158
157
|
|
159
|
-
# @return [YARD::Docstring]
|
160
|
-
def docstring_for node
|
161
|
-
return @docstring_hash[node.loc] if node.respond_to?(:loc)
|
162
|
-
nil
|
163
|
-
end
|
164
|
-
|
165
|
-
# @return [String]
|
166
|
-
def code_for node
|
167
|
-
b = node.location.expression.begin.begin_pos
|
168
|
-
e = node.location.expression.end.end_pos
|
169
|
-
frag = code[b..e-1].to_s
|
170
|
-
frag.strip.gsub(/,$/, '')
|
171
|
-
end
|
172
|
-
|
173
|
-
# @param node [Parser::AST::Node]
|
174
|
-
def tree_for node
|
175
|
-
@node_tree[node.object_id] || []
|
176
|
-
end
|
177
|
-
|
178
158
|
# Get the nearest node that contains the specified index.
|
179
159
|
#
|
180
160
|
# @param index [Integer]
|
@@ -203,6 +183,7 @@ module Solargraph
|
|
203
183
|
end
|
204
184
|
|
205
185
|
def inner_tree_at node, offset, stack
|
186
|
+
return if node.nil?
|
206
187
|
stack.unshift node
|
207
188
|
node.children.each do |c|
|
208
189
|
next unless c.is_a?(AST::Node)
|
@@ -214,47 +195,6 @@ module Solargraph
|
|
214
195
|
end
|
215
196
|
end
|
216
197
|
|
217
|
-
# Find the nearest parent node from the specified index. If one or more
|
218
|
-
# types are provided, find the nearest node whose type is in the list.
|
219
|
-
#
|
220
|
-
# @param index [Integer]
|
221
|
-
# @param types [Array<Symbol>]
|
222
|
-
# @return [AST::Node]
|
223
|
-
def parent_node_from(line, column, *types)
|
224
|
-
arr = tree_at(line, column)
|
225
|
-
arr.each { |a|
|
226
|
-
if a.kind_of?(AST::Node) and (types.empty? or types.include?(a.type))
|
227
|
-
return a
|
228
|
-
end
|
229
|
-
}
|
230
|
-
nil
|
231
|
-
end
|
232
|
-
|
233
|
-
# @return [String]
|
234
|
-
def namespace_for node
|
235
|
-
parts = []
|
236
|
-
([node] + (@node_tree[node.object_id] || [])).each do |n|
|
237
|
-
next unless n.kind_of?(AST::Node)
|
238
|
-
if n.type == :class or n.type == :module
|
239
|
-
parts.unshift unpack_name(n.children[0])
|
240
|
-
end
|
241
|
-
end
|
242
|
-
parts.join('::')
|
243
|
-
end
|
244
|
-
|
245
|
-
def path_for node
|
246
|
-
path = namespace_for(node) || ''
|
247
|
-
mp = (method_pins + attribute_pins).select{|p| p.node == node}.first
|
248
|
-
unless mp.nil?
|
249
|
-
path += (mp.scope == :instance ? '#' : '.') + mp.name
|
250
|
-
end
|
251
|
-
path
|
252
|
-
end
|
253
|
-
|
254
|
-
def include? node
|
255
|
-
node_object_ids.include? node.object_id
|
256
|
-
end
|
257
|
-
|
258
198
|
def synchronize updater
|
259
199
|
raise 'Invalid synchronization' unless updater.filename == filename
|
260
200
|
original_code = @code
|
@@ -266,11 +206,11 @@ module Solargraph
|
|
266
206
|
begin
|
267
207
|
parse
|
268
208
|
@fixed = @code
|
269
|
-
rescue Parser::SyntaxError => e
|
209
|
+
rescue Parser::SyntaxError, EncodingError => e
|
270
210
|
@fixed = updater.repair(original_fixed)
|
271
211
|
begin
|
272
212
|
parse
|
273
|
-
rescue Parser::SyntaxError => e
|
213
|
+
rescue Parser::SyntaxError, EncodingError => e
|
274
214
|
hard_fix_node
|
275
215
|
end
|
276
216
|
end
|
@@ -284,7 +224,6 @@ module Solargraph
|
|
284
224
|
|
285
225
|
def all_symbols
|
286
226
|
result = []
|
287
|
-
# result.concat namespace_pin_map.values.flatten
|
288
227
|
result.concat namespace_pins.reject{ |pin| pin.name.empty? }
|
289
228
|
result.concat method_pins
|
290
229
|
result.concat constant_pins
|
@@ -301,14 +240,6 @@ module Solargraph
|
|
301
240
|
Fragment.new(self, line, column)
|
302
241
|
end
|
303
242
|
|
304
|
-
def fragment_for node
|
305
|
-
inside = tree_for(node)
|
306
|
-
return nil if inside.empty?
|
307
|
-
line = node.loc.expression.last_line - 1
|
308
|
-
column = node.loc.expression.last_column
|
309
|
-
Fragment.new(self, line, column, inside)
|
310
|
-
end
|
311
|
-
|
312
243
|
def parsed?
|
313
244
|
@parsed
|
314
245
|
end
|
@@ -337,7 +268,7 @@ module Solargraph
|
|
337
268
|
parser.diagnostics.all_errors_are_fatal = true
|
338
269
|
parser.diagnostics.ignore_warnings = true
|
339
270
|
buffer = Parser::Source::Buffer.new(filename, 1)
|
340
|
-
buffer.source = code.
|
271
|
+
buffer.source = code.encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: ' ')
|
341
272
|
parser.parse_with_comments(buffer)
|
342
273
|
end
|
343
274
|
|
@@ -346,59 +277,6 @@ module Solargraph
|
|
346
277
|
@stime = Time.now
|
347
278
|
end
|
348
279
|
|
349
|
-
def associate_comments node, comments
|
350
|
-
return nil if comments.nil?
|
351
|
-
comment_hash = Parser::Source::Comment.associate_locations(node, comments)
|
352
|
-
yard_hash = {}
|
353
|
-
comment_hash.each_pair { |k, v|
|
354
|
-
ctxt = ''
|
355
|
-
num = nil
|
356
|
-
started = false
|
357
|
-
v.each { |l|
|
358
|
-
# Trim the comment and minimum leading whitespace
|
359
|
-
p = l.text.gsub(/^#/, '')
|
360
|
-
if num.nil? and !p.strip.empty?
|
361
|
-
num = p.index(/[^ ]/)
|
362
|
-
started = true
|
363
|
-
elsif started and !p.strip.empty?
|
364
|
-
cur = p.index(/[^ ]/)
|
365
|
-
num = cur if cur < num
|
366
|
-
end
|
367
|
-
if started
|
368
|
-
ctxt += "#{p[num..-1]}\n"
|
369
|
-
end
|
370
|
-
}
|
371
|
-
parse = YARD::Docstring.parser.parse(ctxt)
|
372
|
-
unless parse.directives.empty?
|
373
|
-
@directives[k] ||= []
|
374
|
-
@directives[k].concat parse.directives
|
375
|
-
end
|
376
|
-
yard_hash[k] = parse.to_docstring
|
377
|
-
}
|
378
|
-
yard_hash
|
379
|
-
end
|
380
|
-
|
381
|
-
def find_parent(stack, *types)
|
382
|
-
stack.reverse.each { |p|
|
383
|
-
return p if types.include?(p.type)
|
384
|
-
}
|
385
|
-
nil
|
386
|
-
end
|
387
|
-
|
388
|
-
def node_object_ids
|
389
|
-
@node_object_ids ||= @all_nodes.map(&:object_id)
|
390
|
-
end
|
391
|
-
|
392
|
-
# @return [Hash<String, Solargraph::Pin::Namespace>]
|
393
|
-
def namespace_pin_map
|
394
|
-
@namespace_pin_map ||= {}
|
395
|
-
end
|
396
|
-
|
397
|
-
# @return [Hash<String, Solargraph::Pin::Namespace>]
|
398
|
-
def method_pin_map
|
399
|
-
@method_pin_map ||= {}
|
400
|
-
end
|
401
|
-
|
402
280
|
class << self
|
403
281
|
# @return [Solargraph::Source]
|
404
282
|
def load filename
|
@@ -410,48 +288,6 @@ module Solargraph
|
|
410
288
|
def load_string code, filename = nil
|
411
289
|
Source.new code, filename
|
412
290
|
end
|
413
|
-
|
414
|
-
def fix code, filename = nil, offset = nil
|
415
|
-
tries = 0
|
416
|
-
offset = Source.get_offset(code, offset[0], offset[1]) if offset.kind_of?(Array)
|
417
|
-
pos = nil
|
418
|
-
pos = get_position_at(code, offset) unless offset.nil?
|
419
|
-
stubs = []
|
420
|
-
fixed_position = false
|
421
|
-
tmp = code.sub(/\.(\s*\z)$/, ' \1')
|
422
|
-
begin
|
423
|
-
node, comments = Source.parse(tmp, filename)
|
424
|
-
Source.new(code, node, comments, filename, stubs)
|
425
|
-
rescue Parser::SyntaxError => e
|
426
|
-
if tries < 10
|
427
|
-
tries += 1
|
428
|
-
# Stub periods before the offset to retain the expected node tree
|
429
|
-
if !offset.nil? and ['.', '{', '('].include?(tmp[offset-1])
|
430
|
-
tmp = tmp[0, offset-1] + ';' + tmp[offset..-1]
|
431
|
-
elsif !fixed_position and !offset.nil?
|
432
|
-
fixed_position = true
|
433
|
-
beg = beginning_of_line_from(tmp, offset)
|
434
|
-
tmp = "#{tmp[0, beg]}##{tmp[beg+1..-1]}"
|
435
|
-
stubs.push(pos[0])
|
436
|
-
elsif e.message.include?('token $end')
|
437
|
-
tmp += "\nend"
|
438
|
-
elsif e.message.include?("unexpected `@'")
|
439
|
-
tmp = tmp[0, e.diagnostic.location.begin_pos] + '_' + tmp[e.diagnostic.location.begin_pos+1..-1]
|
440
|
-
end
|
441
|
-
retry
|
442
|
-
end
|
443
|
-
STDERR.puts "Unable to parse file #{filename.nil? ? 'undefined' : filename}: #{e.message}"
|
444
|
-
node, comments = parse(code.gsub(/[^\s]/, ' '), filename)
|
445
|
-
Source.new(code, node, comments, filename)
|
446
|
-
end
|
447
|
-
end
|
448
|
-
|
449
|
-
def beginning_of_line_from str, i
|
450
|
-
while i > 0 and str[i-1] != "\n"
|
451
|
-
i -= 1
|
452
|
-
end
|
453
|
-
i
|
454
|
-
end
|
455
291
|
end
|
456
292
|
end
|
457
293
|
end
|