steep 0.29.0 → 0.33.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -14,6 +14,8 @@ module Steep
14
14
  attr_reader :signature_worker
15
15
  attr_reader :code_workers
16
16
 
17
+ include Utils
18
+
17
19
  def initialize(project:, reader:, writer:, interaction_worker:, signature_worker:, code_workers:, queue: Queue.new)
18
20
  @project = project
19
21
  @reader = reader
@@ -27,19 +29,24 @@ module Steep
27
29
  end
28
30
 
29
31
  def start
30
- source_paths = project.targets.flat_map {|target| target.source_files.keys }
32
+ source_paths = project.all_source_files
31
33
  bin_size = (source_paths.size / code_workers.size) + 1
32
34
  source_paths.each_slice(bin_size).with_index do |paths, index|
33
35
  register_code_to_worker(paths, worker: code_workers[index])
34
36
  end
35
37
 
38
+ tags = Steep.logger.formatter.current_tags.dup
39
+ tags << "master"
40
+
36
41
  Thread.new do
42
+ Steep.logger.formatter.push_tags(*tags, "from-worker@interaction")
37
43
  interaction_worker.reader.read do |message|
38
44
  process_message_from_worker(message)
39
45
  end
40
46
  end
41
47
 
42
48
  Thread.new do
49
+ Steep.logger.formatter.push_tags(*tags, "from-worker@signature")
43
50
  signature_worker.reader.read do |message|
44
51
  process_message_from_worker(message)
45
52
  end
@@ -47,6 +54,7 @@ module Steep
47
54
 
48
55
  code_workers.each do |worker|
49
56
  Thread.new do
57
+ Steep.logger.formatter.push_tags(*tags, "from-worker@#{worker.name}")
50
58
  worker.reader.read do |message|
51
59
  process_message_from_worker(message)
52
60
  end
@@ -54,6 +62,7 @@ module Steep
54
62
  end
55
63
 
56
64
  Thread.new do
65
+ Steep.logger.formatter.push_tags(*tags, "from-client")
57
66
  reader.read do |request|
58
67
  process_message_from_client(request)
59
68
  end
@@ -97,7 +106,7 @@ module Steep
97
106
  result: LSP::Interface::InitializeResult.new(
98
107
  capabilities: LSP::Interface::ServerCapabilities.new(
99
108
  text_document_sync: LSP::Interface::TextDocumentSyncOptions.new(
100
- change: LSP::Constant::TextDocumentSyncKind::FULL
109
+ change: LSP::Constant::TextDocumentSyncKind::INCREMENTAL
101
110
  ),
102
111
  hover_provider: true,
103
112
  completion_provider: LSP::Interface::CompletionOptions.new(
@@ -112,36 +121,10 @@ module Steep
112
121
  end
113
122
 
114
123
  when "textDocument/didChange"
124
+ update_source(message)
125
+
115
126
  uri = URI.parse(message[:params][:textDocument][:uri])
116
127
  path = project.relative_path(Pathname(uri.path))
117
- text = message[:params][:contentChanges][0][:text]
118
-
119
- project.targets.each do |target|
120
- case
121
- when target.source_file?(path)
122
- if text.empty? && !path.file?
123
- Steep.logger.info { "Deleting source file: #{path}..." }
124
- target.remove_source(path)
125
- else
126
- Steep.logger.info { "Updating source file: #{path}..." }
127
- target.update_source(path, text)
128
- end
129
- when target.possible_source_file?(path)
130
- Steep.logger.info { "Adding source file: #{path}..." }
131
- target.add_source(path, text)
132
- when target.signature_file?(path)
133
- if text.empty? && !path.file?
134
- Steep.logger.info { "Deleting signature file: #{path}..." }
135
- target.remove_signature(path)
136
- else
137
- Steep.logger.info { "Updating signature file: #{path}..." }
138
- target.update_signature(path, text)
139
- end
140
- when target.possible_signature_file?(path)
141
- Steep.logger.info { "Adding signature file: #{path}..." }
142
- target.add_signature(path, text)
143
- end
144
- end
145
128
 
146
129
  unless registered_path?(path)
147
130
  register_code_to_worker [path], worker: least_busy_worker()
@@ -7,23 +7,56 @@ module Steep
7
7
  project.relative_path(Pathname(uri.path))
8
8
  end
9
9
 
10
+ def apply_change(change, text)
11
+ range = change[:range]
12
+
13
+ if range
14
+ text = text.dup
15
+
16
+ buf = RBS::Buffer.new(name: :_, content: text)
17
+
18
+ start_pos = buf.loc_to_pos(range[:start].yield_self {|pos| [pos[:line]+1, pos[:character]] })
19
+ end_pos = buf.loc_to_pos(range[:end].yield_self {|pos| [pos[:line]+1, pos[:character]] })
20
+
21
+ text[start_pos...end_pos] = change[:text]
22
+ text
23
+ else
24
+ change[:text]
25
+ end
26
+ end
27
+
10
28
  def update_source(request)
11
29
  path = source_path(URI.parse(request[:params][:textDocument][:uri]))
12
- text = request[:params][:contentChanges][0][:text]
13
30
  version = request[:params][:textDocument][:version]
31
+ Steep.logger.info { "Updating source: path=#{path}, version=#{version}..." }
32
+
33
+ changes = request[:params][:contentChanges]
34
+
35
+ source_target, signature_targets = project.targets_for_path(path)
36
+
37
+ if source_target
38
+ changes.each do |change|
39
+ case
40
+ when source_target.source_file?(path)
41
+ Steep.logger.debug { "Updating source in #{source_target.name}: path=#{path}" }
42
+ source_target.update_source(path) {|text| apply_change(change, text) }
43
+ when source_target.possible_source_file?(path)
44
+ Steep.logger.debug { "Adding source to #{source_target.name}: path=#{path}" }
45
+ source_target.add_source(path, change[:text])
46
+ end
47
+ end
48
+ end
14
49
 
15
- Steep.logger.debug "Updateing source: path=#{path}, version=#{version}, size=#{text.bytesize}"
16
-
17
- project.targets.each do |target|
18
- case
19
- when target.source_file?(path)
20
- target.update_source path, text
21
- when target.possible_source_file?(path)
22
- target.add_source path, text
23
- when target.signature_file?(path)
24
- target.update_signature path, text
25
- when target.possible_signature_file?(path)
26
- target.add_signature path, text
50
+ signature_targets.each do |target|
51
+ changes.each do |change|
52
+ case
53
+ when target.signature_file?(path)
54
+ Steep.logger.debug { "Updating signature in #{target.name}: path=#{path}" }
55
+ target.update_signature(path) {|text| apply_change(change, text) }
56
+ when target.possible_signature_file?(path)
57
+ Steep.logger.debug { "Adding signature to #{target.name}: path=#{path}" }
58
+ target.add_signature(path, change[:text])
59
+ end
27
60
  end
28
61
  end
29
62
 
@@ -5,13 +5,15 @@ module Steep
5
5
  attr_reader :writer
6
6
  attr_reader :stderr
7
7
 
8
+ attr_reader :name
8
9
  attr_reader :wait_thread
9
10
 
10
- def initialize(reader:, writer:, stderr:, wait_thread:)
11
+ def initialize(reader:, writer:, stderr:, wait_thread:, name:)
11
12
  @reader = reader
12
13
  @writer = writer
13
14
  @stderr = stderr
14
15
  @wait_thread = wait_thread
16
+ @name = name
15
17
  end
16
18
 
17
19
  def self.spawn_worker(type, name:, steepfile:)
@@ -33,7 +35,7 @@ module Steep
33
35
  writer = LanguageServer::Protocol::Transport::Io::Writer.new(stdin)
34
36
  reader = LanguageServer::Protocol::Transport::Io::Reader.new(stdout)
35
37
 
36
- new(reader: reader, writer: writer, stderr: stderr, wait_thread: thread)
38
+ new(reader: reader, writer: writer, stderr: stderr, wait_thread: thread, name: name)
37
39
  end
38
40
 
39
41
  def self.spawn_code_workers(steepfile:, count: [Etc.nprocessors-3, 1].max)
@@ -65,11 +65,11 @@ module Steep
65
65
  parser.tokenize(buffer)
66
66
  end
67
67
 
68
- buffer = AST::Buffer.new(name: path, content: source_code)
68
+ buffer = RBS::Buffer.new(name: path, content: source_code)
69
69
 
70
70
  comments.each do |comment|
71
71
  src = comment.text.gsub(/\A#\s*/, '')
72
- location = AST::Location.new(buffer: buffer,
72
+ location = RBS::Location.new(buffer: buffer,
73
73
  start_pos: comment.location.expression.begin_pos + 1,
74
74
  end_pos: comment.location.expression.end_pos)
75
75
  annotation = AnnotationParser.new(factory: factory).parse(src, location: location)
@@ -107,7 +107,7 @@ module Steep
107
107
 
108
108
  if node.children[1]
109
109
  if node.loc.keyword.source == "if" || node.loc.keyword.source == "elsif"
110
- then_start = node.loc.begin&.loc&.last_line || node.children[0].loc.last_line
110
+ then_start = node.loc.begin&.last_line || node.children[0].loc.last_line
111
111
  then_end = node.children[2] ? node.loc.else.line : node.loc.last_line
112
112
  else
113
113
  then_start = node.loc.else.last_line
@@ -276,6 +276,18 @@ module Steep
276
276
  end
277
277
  end
278
278
 
279
+ def self.map_child_nodes(node)
280
+ children = node.children.map do |child|
281
+ if child.is_a?(::AST::Node)
282
+ yield child
283
+ else
284
+ child
285
+ end
286
+ end
287
+
288
+ node.updated(nil, children)
289
+ end
290
+
279
291
  def annotations(block:, factory:, current_module:)
280
292
  AST::Annotation::Collection.new(
281
293
  annotations: mapping[block.__id__] || [],
@@ -316,5 +328,50 @@ module Steep
316
328
  end
317
329
  end
318
330
  end
331
+
332
+ def self.delete_defs(node, allow_list)
333
+ case node.type
334
+ when :def
335
+ if allow_list.include?(node)
336
+ node
337
+ else
338
+ node.updated(:nil, [])
339
+ end
340
+ when :defs
341
+ if allow_list.include?(node)
342
+ node
343
+ else
344
+ delete_defs(node.children[0], allow_list)
345
+ end
346
+ else
347
+ map_child_nodes(node) do |child|
348
+ delete_defs(child, allow_list)
349
+ end
350
+ end
351
+ end
352
+
353
+ def without_unrelated_defs(line:, column:)
354
+ nodes = find_nodes(line: line, column: column) || []
355
+ defs = Set[].compare_by_identity.merge(nodes.select {|node| node.type == :def || node.type == :defs })
356
+
357
+ node_ = Source.delete_defs(node, defs)
358
+
359
+ Source.new(path: path, node: node_, mapping: mapping)
360
+ end
361
+
362
+ def compact_siblings(node)
363
+ case node
364
+ when :def
365
+ node.updated(:nil, [])
366
+ when :defs
367
+ node.children[0]
368
+ when :class
369
+ node.updated(:class, [node.children[0], node.children[1], nil])
370
+ when :module
371
+ node.updated(:module, [node.children[0], nil])
372
+ else
373
+ node
374
+ end
375
+ end
319
376
  end
320
377
  end
@@ -29,7 +29,7 @@ module Steep
29
29
  else
30
30
  ""
31
31
  end
32
- buffer = AST::Buffer.new(name: source.path, content: content)
32
+ buffer = RBS::Buffer.new(name: source.path, content: content)
33
33
  new(buffer: buffer, context: context, range: range || 0..buffer.content.size)
34
34
  end
35
35
 
@@ -207,6 +207,12 @@ module Steep
207
207
  [type]
208
208
  ]
209
209
 
210
+ when AST::Types::Name::Interface
211
+ [
212
+ [instance_type],
213
+ [type]
214
+ ]
215
+
210
216
  else
211
217
  [
212
218
  [],
@@ -1,3 +1,3 @@
1
1
  module Steep
2
- VERSION = "0.29.0"
2
+ VERSION = "0.33.0"
3
3
  end
@@ -0,0 +1,8 @@
1
+ class Fun
2
+ def foo(v)
3
+ !v.nil? && foo2(v)
4
+ end
5
+
6
+ def foo2(_)
7
+ end
8
+ end
@@ -0,0 +1,4 @@
1
+ class Fun
2
+ def foo: (Integer?) -> void
3
+ def foo2: (Integer) -> void
4
+ end
@@ -0,0 +1,5 @@
1
+ target :test do
2
+ typing_options :strict
3
+ check "*.rb"
4
+ signature "*.rbs"
5
+ end
@@ -0,0 +1,4 @@
1
+ # !expects MethodBodyTypeMismatch: method=fizz_buzz, expected=::String, actual=nil
2
+ def fizz_buzz(n)
3
+ nil
4
+ end
@@ -0,0 +1,3 @@
1
+ class Object
2
+ def fizz_buzz: (Integer) -> String
3
+ end
@@ -32,7 +32,7 @@ Gem::Specification.new do |spec|
32
32
  spec.add_runtime_dependency "ast_utils", "~> 0.3.0"
33
33
  spec.add_runtime_dependency "activesupport", ">= 5.1"
34
34
  spec.add_runtime_dependency "rainbow", ">= 2.2.2", "< 4.0"
35
- spec.add_runtime_dependency "listen", "~> 3.1"
35
+ spec.add_runtime_dependency "listen", "~> 3.0"
36
36
  spec.add_runtime_dependency "language_server-protocol", "~> 3.15.0.1"
37
37
  spec.add_runtime_dependency "rbs", "~> 0.12.0"
38
38
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: steep
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.29.0
4
+ version: 0.33.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Soutaro Matsumoto
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-09-28 00:00:00.000000000 Z
11
+ date: 2020-10-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parser
@@ -78,14 +78,14 @@ dependencies:
78
78
  requirements:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
- version: '3.1'
81
+ version: '3.0'
82
82
  type: :runtime
83
83
  prerelease: false
84
84
  version_requirements: !ruby/object:Gem::Requirement
85
85
  requirements:
86
86
  - - "~>"
87
87
  - !ruby/object:Gem::Version
88
- version: '3.1'
88
+ version: '3.0'
89
89
  - !ruby/object:Gem::Dependency
90
90
  name: language_server-protocol
91
91
  requirement: !ruby/object:Gem::Requirement
@@ -140,9 +140,7 @@ files:
140
140
  - lib/steep/annotation_parser.rb
141
141
  - lib/steep/ast/annotation.rb
142
142
  - lib/steep/ast/annotation/collection.rb
143
- - lib/steep/ast/buffer.rb
144
143
  - lib/steep/ast/builtin.rb
145
- - lib/steep/ast/location.rb
146
144
  - lib/steep/ast/type_params.rb
147
145
  - lib/steep/ast/types.rb
148
146
  - lib/steep/ast/types/any.rb
@@ -187,10 +185,11 @@ files:
187
185
  - lib/steep/project.rb
188
186
  - lib/steep/project/completion_provider.rb
189
187
  - lib/steep/project/dsl.rb
190
- - lib/steep/project/file.rb
191
188
  - lib/steep/project/file_loader.rb
192
189
  - lib/steep/project/hover_content.rb
193
190
  - lib/steep/project/options.rb
191
+ - lib/steep/project/signature_file.rb
192
+ - lib/steep/project/source_file.rb
194
193
  - lib/steep/project/target.rb
195
194
  - lib/steep/server/base_worker.rb
196
195
  - lib/steep/server/code_worker.rb
@@ -330,6 +329,8 @@ files:
330
329
  - smoke/regexp/b.rb
331
330
  - smoke/regression/Steepfile
332
331
  - smoke/regression/array.rb
332
+ - smoke/regression/fun.rb
333
+ - smoke/regression/fun.rbs
333
334
  - smoke/regression/hash.rb
334
335
  - smoke/regression/poly_new.rb
335
336
  - smoke/regression/poly_new.rbs
@@ -347,6 +348,9 @@ files:
347
348
  - smoke/super/Steepfile
348
349
  - smoke/super/a.rb
349
350
  - smoke/super/a.rbs
351
+ - smoke/toplevel/Steepfile
352
+ - smoke/toplevel/a.rb
353
+ - smoke/toplevel/a.rbs
350
354
  - smoke/type_case/Steepfile
351
355
  - smoke/type_case/a.rb
352
356
  - smoke/yield/Steepfile
@@ -1,51 +0,0 @@
1
- module Steep
2
- module AST
3
- class Buffer
4
- attr_reader :name
5
- attr_reader :content
6
- attr_reader :lines
7
- attr_reader :ranges
8
-
9
- def initialize(name:, content:)
10
- @name = name
11
- @content = content
12
-
13
- @lines = content.split(/\n/, -1)
14
-
15
- @ranges = []
16
- offset = 0
17
- lines.each.with_index do |line, index|
18
- if index == lines.size - 1
19
- ranges << (offset..offset)
20
- else
21
- size = line.size
22
- range = offset..(offset+size)
23
- ranges << range
24
- offset += size+1
25
- end
26
- end
27
- end
28
-
29
- def pos_to_loc(pos)
30
- index = ranges.bsearch_index do |range|
31
- pos <= range.end
32
- end
33
-
34
- if index
35
- [index + 1, pos - ranges[index].begin]
36
- else
37
- [1, pos]
38
- end
39
- end
40
-
41
- def loc_to_pos(loc)
42
- line, column = loc
43
- ranges[line - 1].begin + column
44
- end
45
-
46
- def source(range)
47
- content[range]
48
- end
49
- end
50
- end
51
- end