steep 0.51.0 → 0.52.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 502d495f9b623c5d90a041a1e0bb7854be76251a8ac0f3567c1c91911eb641ee
4
- data.tar.gz: 7845d6d26f38ceae87407d507f3f67b8d35bae18ecdd5f4ee9fdb841d434a4ad
3
+ metadata.gz: 3c9d5eb873780b31a2431d2e6c4efdc558fbb3a4a42c08cbe2580bb191db5bc8
4
+ data.tar.gz: dee794e9cb098309b9875396ed1dc9904a4c6882aeadb27c83c26604ebcbc87d
5
5
  SHA512:
6
- metadata.gz: e2e61987da5ef5d78381affeb2f4fbb8b84dd2a6fede0baa60c68f54a3464e3cb7eea0e2822f22a66d62f1de3b9f8b223cd6399dceb927397a3dab0bed3fea5d
7
- data.tar.gz: ee91ba6b1a4d8f35ec1fbc157efd2fb54f27b11e398af09a7ef3d4f403ae0ae2fab3258404316c6ded646f688b61ff38b47a514fec83cd9fe1b4fcf136fdc441
6
+ metadata.gz: ba05f88c28a78414ffcd41744558bdea978b72621f422571cb1450b7b0d56fb77c2b65329064226863db2517d4769a6f54e7c47ce92eef59d97f0403bb9e9425
7
+ data.tar.gz: 6e260b48940214b7c0910bf2678c587b469e163e70265f197ef8fd17a1703a68fd9488c77c3d1f8254939c074281717593e49812875fb705615189cd3ec4cdf0
@@ -1,8 +1,15 @@
1
1
  version: 2
2
+
2
3
  updates:
3
- - package-ecosystem: bundler
4
- directory: "/"
5
- schedule:
6
- interval: daily
7
- time: "20:00"
8
- open-pull-requests-limit: 10
4
+ - package-ecosystem: bundler
5
+ directory: "/"
6
+ schedule:
7
+ interval: daily
8
+ time: "20:00"
9
+ open-pull-requests-limit: 10
10
+
11
+ - package-ecosystem: "github-actions"
12
+ directory: "/"
13
+ schedule:
14
+ # Check for updates to GitHub Actions every weekday
15
+ interval: "daily"
@@ -14,6 +14,7 @@ jobs:
14
14
  container_tag:
15
15
  - "2.7"
16
16
  - "3.0"
17
+ - "3.1"
17
18
  - "master-nightly-focal"
18
19
  task:
19
20
  - test
@@ -22,9 +23,10 @@ jobs:
22
23
  container:
23
24
  image: rubylang/ruby:${{ matrix.container_tag }}
24
25
  steps:
25
- - uses: actions/checkout@v1
26
+ - uses: actions/checkout@v3
26
27
  - name: Run test
27
28
  run: |
29
+ git config --global --add safe.directory /__w/steep/steep
28
30
  ruby -v
29
31
  gem install bundler
30
32
  bundle install --jobs 4 --retry 3
data/CHANGELOG.md CHANGED
@@ -2,6 +2,25 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 0.52.2 (2022-05-02)
6
+
7
+ * Handle class declaration with non-const super class ([\#546](https://github.com/soutaro/steep/pull/546))
8
+ * Remove `#to_a` error message ([\#545](https://github.com/soutaro/steep/pull/545))
9
+ * Add `#filter_map` shim ([\#544](https://github.com/soutaro/steep/pull/544))
10
+
11
+ ## 0.52.1 (2022-04-25)
12
+
13
+ * Better union type inference (it type checks `Array#filter_map` now!) ([\#531](https://github.com/soutaro/steep/pull/531))
14
+ * Improve method call hover message ([\#537](https://github.com/soutaro/steep/pull/537), [\#538](https://github.com/soutaro/steep/pull/538))
15
+ * Make `NilClass#!` a special method to improve flow-sensitive typing ([\#539](https://github.com/soutaro/steep/pull/539))
16
+ * Fix `steep binstub` ([\#540](https://github.com/soutaro/steep/pull/540), [\#541](https://github.com/soutaro/steep/pull/541))
17
+
18
+ ## 0.52.0 (2022-04-05)
19
+
20
+ * Add `steep binstub` command ([\#527](https://github.com/soutaro/steep/pull/527))
21
+ * Let hover and completion work in heredoc ([\#528](https://github.com/soutaro/steep/pull/528))
22
+ * Better constant typing ([\#529](https://github.com/soutaro/steep/pull/529))
23
+
5
24
  ## 0.51.0 (2022-04-01)
6
25
 
7
26
  * Completion for constant ([\#524](https://github.com/soutaro/steep/pull/524))
data/Gemfile.lock CHANGED
@@ -1,14 +1,14 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- steep (0.51.0)
4
+ steep (0.52.2)
5
5
  activesupport (>= 5.1)
6
6
  language_server-protocol (>= 3.15, < 4.0)
7
7
  listen (~> 3.0)
8
8
  parallel (>= 1.0.0)
9
9
  parser (>= 3.0)
10
10
  rainbow (>= 2.2.2, < 4.0)
11
- rbs (>= 2.3.0)
11
+ rbs (>= 2.3.2)
12
12
  terminal-table (>= 2, < 4)
13
13
 
14
14
  PATH
@@ -24,7 +24,7 @@ PATH
24
24
  GEM
25
25
  remote: https://rubygems.org/
26
26
  specs:
27
- activesupport (7.0.2.3)
27
+ activesupport (7.0.2.4)
28
28
  concurrent-ruby (~> 1.0, >= 1.0.2)
29
29
  i18n (>= 1.6, < 2)
30
30
  minitest (>= 5.1)
@@ -44,14 +44,14 @@ GEM
44
44
  minitest-slow_test (0.2.0)
45
45
  minitest (>= 5.0)
46
46
  parallel (1.22.1)
47
- parser (3.1.1.0)
47
+ parser (3.1.2.0)
48
48
  ast (~> 2.4.1)
49
49
  rainbow (3.1.1)
50
50
  rake (13.0.6)
51
51
  rb-fsevent (0.11.1)
52
52
  rb-inotify (0.10.1)
53
53
  ffi (~> 1.0)
54
- rbs (2.3.0)
54
+ rbs (2.3.2)
55
55
  stackprof (0.2.19)
56
56
  terminal-table (3.0.2)
57
57
  unicode-display_width (>= 1.1.1, < 3)
@@ -431,7 +431,8 @@ module Steep
431
431
  case defined_in
432
432
  when RBS::BuiltinNames::BasicObject.name,
433
433
  RBS::BuiltinNames::TrueClass.name,
434
- RBS::BuiltinNames::FalseClass.name
434
+ RBS::BuiltinNames::FalseClass.name,
435
+ AST::Builtin::NilClass.module_name
435
436
  return method_type.with(
436
437
  type: method_type.type.with(
437
438
  return_type: AST::Types::Logic::Not.new(location: method_type.type.return_type.location)
data/lib/steep/cli.rb CHANGED
@@ -18,7 +18,7 @@ module Steep
18
18
  end
19
19
 
20
20
  def self.available_commands
21
- [:init, :check, :validate, :annotations, :version, :project, :watch, :langserver, :stats]
21
+ [:init, :check, :validate, :annotations, :version, :project, :watch, :langserver, :stats, :binstub]
22
22
  end
23
23
 
24
24
  def process_global_options
@@ -208,6 +208,84 @@ module Steep
208
208
  end.run
209
209
  end
210
210
 
211
+ def process_binstub
212
+ path = Pathname("bin/steep")
213
+ root_path = Pathname.pwd
214
+ force = false
215
+
216
+ OptionParser.new do |opts|
217
+ opts.banner = <<BANNER
218
+ Usage: steep binstub [options]
219
+
220
+ Generate a binstub to execute Steep with setting up Bundler and rbenv/rvm.
221
+ Use the executable for LSP integration setup.
222
+
223
+ Options:
224
+ BANNER
225
+ handle_logging_options opts
226
+
227
+ opts.on("-o PATH", "--output=PATH", "The path of the executable file (defaults to `bin/steep`)") do |v|
228
+ path = Pathname(v)
229
+ end
230
+
231
+ opts.on("--root=PATH", "The repository root path (defaults to `.`)") do |v|
232
+ root_path = (Pathname.pwd + v).cleanpath
233
+ end
234
+
235
+ opts.on("--[no-]force", "Overwrite file (defaults to false)") do
236
+ force = true
237
+ end
238
+ end.parse!(argv)
239
+
240
+ binstub_path = (Pathname.pwd + path).cleanpath
241
+ bindir_path = binstub_path.parent
242
+
243
+ bindir_path.mkpath
244
+
245
+ gemfile_path =
246
+ if defined?(Bundler)
247
+ Bundler.default_gemfile.relative_path_from(bindir_path)
248
+ else
249
+ Pathname("../Gemfile")
250
+ end
251
+
252
+ if binstub_path.file?
253
+ if force
254
+ stdout.puts Rainbow("#{path} already exists. Overwriting...").yellow
255
+ else
256
+ stdout.puts Rainbow(''"⚠️ #{path} already exists. Bye! 👋").red
257
+ return 0
258
+ end
259
+ end
260
+
261
+ template = <<TEMPLATE
262
+ #!/usr/bin/env bash
263
+
264
+ BINSTUB_DIR=$(cd $(dirname $0); pwd)
265
+ GEMFILE=$(readlink -f ${BINSTUB_DIR}/#{gemfile_path})
266
+ ROOT_DIR=$(readlink -f ${BINSTUB_DIR}/#{root_path.relative_path_from(bindir_path)})
267
+
268
+ STEEP="bundle exec --gemfile=${GEMFILE} steep"
269
+
270
+ if type "rbenv" > /dev/null 2>&1; then
271
+ STEEP="rbenv exec ${STEEP}"
272
+ else
273
+ if type "rvm" > /dev/null 2>&1; then
274
+ STEEP="rvm ${ROOT_DIR} do ${STEEP}"
275
+ fi
276
+ fi
277
+
278
+ exec $STEEP $@
279
+ TEMPLATE
280
+
281
+ binstub_path.write(template)
282
+ binstub_path.chmod(0755)
283
+
284
+ stdout.puts Rainbow("Successfully generated executable #{path} 🎉").blue
285
+
286
+ 0
287
+ end
288
+
211
289
  def process_version
212
290
  stdout.puts Steep::VERSION
213
291
  0
@@ -78,8 +78,7 @@ module Steep
78
78
  Steep.measure "Generating hover response" do
79
79
  Steep.logger.info { "path=#{job.path}, line=#{job.line}, column=#{job.column}" }
80
80
 
81
- hover = Services::HoverContent.new(service: service)
82
- content = hover.content_for(path: job.path, line: job.line, column: job.column)
81
+ content = Services::HoverProvider.content_for(service: service, path: job.path, line: job.line, column: job.column)
83
82
  if content
84
83
  range = content.location.yield_self do |location|
85
84
  lsp_range = location.as_lsp_range
@@ -89,7 +88,10 @@ module Steep
89
88
  end
90
89
 
91
90
  LSP::Interface::Hover.new(
92
- contents: { kind: "markdown", value: format_hover(content)&.gsub(/<!--(?~-->)-->/, "") },
91
+ contents: {
92
+ kind: "markdown",
93
+ value: LSPFormatter.format_hover_content(content).to_s
94
+ },
93
95
  range: range
94
96
  )
95
97
  end
@@ -100,101 +102,6 @@ module Steep
100
102
  end
101
103
  end
102
104
 
103
- def format_hover(content)
104
- case content
105
- when Services::HoverContent::TypeAliasContent
106
- comment = content.decl.comment&.string || ''
107
-
108
- <<-MD
109
- #{comment}
110
-
111
- ```rbs
112
- #{retrieve_decl_information(content.decl)}
113
- ```
114
- MD
115
- when Services::HoverContent::InterfaceContent
116
- comment = content.decl.comment&.string || ''
117
-
118
- <<-MD
119
- #{comment}
120
-
121
- ```rbs
122
- #{retrieve_decl_information(content.decl)}
123
- ```
124
- MD
125
- when Services::HoverContent::ClassContent
126
- comment = content.decl.comment&.string || ''
127
-
128
- <<-MD
129
- #{comment}
130
-
131
- ```rbs
132
- #{retrieve_decl_information(content.decl)}
133
- ```
134
- MD
135
- when Services::HoverContent::VariableContent
136
- "`#{content.name}`: `#{content.type.to_s}`"
137
- when Services::HoverContent::MethodCallContent
138
- method_name = case content.method_name
139
- when Services::HoverContent::InstanceMethodName
140
- "#{content.method_name.class_name}##{content.method_name.method_name}"
141
- when Services::HoverContent::SingletonMethodName
142
- "#{content.method_name.class_name}.#{content.method_name.method_name}"
143
- else
144
- nil
145
- end
146
-
147
- if method_name
148
- string = <<HOVER
149
- ```
150
- #{method_name} ~> #{content.type}
151
- ```
152
- HOVER
153
- if content.definition
154
- if content.definition.comments
155
- string << "\n----\n\n#{content.definition.comments.map(&:string).join("\n\n")}"
156
- end
157
-
158
- string << "\n----\n\n#{content.definition.method_types.map {|x| "- `#{x}`\n" }.join()}"
159
- end
160
- else
161
- "`#{content.type}`"
162
- end
163
- when Services::HoverContent::DefinitionContent
164
- string = <<HOVER
165
- ```
166
- def #{content.method_name}: #{content.method_type}
167
- ```
168
- HOVER
169
- if (comment = content.comment_string)
170
- string << "\n----\n\n#{comment}\n"
171
- end
172
-
173
- if content.definition.method_types.size > 1
174
- string << "\n----\n\n#{content.definition.method_types.map {|x| "- `#{x}`\n" }.join()}"
175
- end
176
-
177
- string
178
- when Services::HoverContent::ConstantContent
179
- ss = []
180
- if content.class_or_module?
181
- ss << ["```rbs", retrieve_decl_information(content.decl.primary.decl), "```"].join("\n")
182
- end
183
-
184
- if content.constant?
185
- ss << ["```rbs", "#{content.full_name}: #{content.type}", "```"].join("\n")
186
- end
187
-
188
- if s = content.comment_string
189
- ss << s
190
- end
191
-
192
- ss.join("\n\n----\n\n")
193
- when Services::HoverContent::TypeContent
194
- "`#{content.type}`"
195
- end
196
- end
197
-
198
105
  def process_completion(job)
199
106
  Steep.logger.tagged("#response_to_completion") do
200
107
  Steep.measure "Generating response" do
@@ -356,59 +263,6 @@ HOVER
356
263
  end
357
264
  end
358
265
 
359
- def name_and_params(name, params)
360
- if params.empty?
361
- "#{name}"
362
- else
363
- ps = params.each.map do |param|
364
- s = ""
365
- if param.unchecked?
366
- s << "unchecked "
367
- end
368
- case param.variance
369
- when :invariant
370
- # nop
371
- when :covariant
372
- s << "out "
373
- when :contravariant
374
- s << "in "
375
- end
376
- s + param.name.to_s
377
- end
378
-
379
- "#{name}[#{ps.join(", ")}]"
380
- end
381
- end
382
-
383
- def name_and_args(name, args)
384
- if name && args
385
- if args.empty?
386
- "#{name}"
387
- else
388
- "#{name}[#{args.join(", ")}]"
389
- end
390
- end
391
- end
392
-
393
- def retrieve_decl_information(decl)
394
- case decl
395
- when RBS::AST::Declarations::Class
396
- super_class = if super_class = decl.super_class
397
- " < #{name_and_args(super_class.name, super_class.args)}"
398
- end
399
- "class #{name_and_params(decl.name, decl.type_params)}#{super_class}"
400
- when RBS::AST::Declarations::Module
401
- self_type = unless decl.self_types.empty?
402
- " : #{decl.self_types.join(", ")}"
403
- end
404
- "module #{name_and_params(decl.name, decl.type_params)}#{self_type}"
405
- when RBS::AST::Declarations::Alias
406
- "type #{decl.name} = #{decl.type}"
407
- when RBS::AST::Declarations::Interface
408
- "interface #{name_and_params(decl.name, decl.type_params)}"
409
- end
410
- end
411
-
412
266
  def format_completion_item(item)
413
267
  range = LanguageServer::Protocol::Interface::Range.new(
414
268
  start: LanguageServer::Protocol::Interface::Position.new(
@@ -0,0 +1,234 @@
1
+ module Steep
2
+ module Server
3
+ module LSPFormatter
4
+ include Services
5
+
6
+ class CommentBuilder
7
+ def initialize
8
+ @array = []
9
+ end
10
+
11
+ def self.build
12
+ builder = CommentBuilder.new
13
+ yield builder
14
+ builder.to_s
15
+ end
16
+
17
+ def to_s
18
+ unless @array.empty?
19
+ @array.join("\n\n----\n\n")
20
+ end
21
+ end
22
+
23
+ def <<(string)
24
+ if string
25
+ s = string.rstrip.gsub(/^[ \t]*<!--(?~-->)-->\n/, "").gsub(/\A([ \t]*\n)+/, "")
26
+ unless @array.include?(s)
27
+ @array << s
28
+ end
29
+ end
30
+ end
31
+
32
+ def push
33
+ s = ""
34
+ yield s
35
+ self << s
36
+ end
37
+ end
38
+
39
+ module_function
40
+
41
+ def format_hover_content(content)
42
+ case content
43
+ when HoverProvider::Ruby::VariableContent
44
+ "`#{content.name}`: `#{content.type.to_s}`"
45
+
46
+ when HoverProvider::Ruby::MethodCallContent
47
+ CommentBuilder.build do |builder|
48
+ call = content.method_call
49
+ builder.push do |s|
50
+ case call
51
+ when TypeInference::MethodCall::Typed
52
+ mt = call.actual_method_type.with(
53
+ type: call.actual_method_type.type.with(return_type: call.return_type)
54
+ )
55
+ s << "```rbs\n#{mt.to_s}\n```\n\n"
56
+ when TypeInference::MethodCall::Error
57
+ s << "```rbs\n( ??? ) -> #{call.return_type.to_s}\n```\n\n"
58
+ end
59
+
60
+ s << to_list(call.method_decls) do |decl|
61
+ "`#{decl.method_name}`"
62
+ end
63
+ end
64
+
65
+ call.method_decls.each do |decl|
66
+ if comment = decl.method_def.comment
67
+ builder << <<EOM
68
+ **#{decl.method_name.to_s}**
69
+
70
+ ```rbs
71
+ #{decl.method_type}
72
+ ```
73
+
74
+ #{decl.method_def.comment.string.gsub(/\A([ \t]*\n)+/, "")}
75
+ EOM
76
+ end
77
+ end
78
+ end
79
+
80
+ when HoverProvider::Ruby::DefinitionContent
81
+ CommentBuilder.build do |builder|
82
+ builder << <<EOM
83
+ ```
84
+ #{content.method_name}: #{content.method_type}
85
+ ```
86
+ EOM
87
+ if comments = content.definition&.comments
88
+ comments.each do |comment|
89
+ builder << comment.string
90
+ end
91
+ end
92
+
93
+ if content.definition.method_types.size > 1
94
+ builder << to_list(content.definition.method_types) {|type| "`#{type.to_s}`" }
95
+ end
96
+ end
97
+ when HoverProvider::Ruby::ConstantContent
98
+ CommentBuilder.build do |builder|
99
+ if content.class_or_module?
100
+ builder << <<EOM
101
+ ```rbs
102
+ #{declaration_summary(content.decl.primary.decl)}
103
+ ```
104
+ EOM
105
+ end
106
+
107
+ if content.constant?
108
+ builder << <<EOM
109
+ ```rbs
110
+ #{content.full_name}: #{content.type}
111
+ ```
112
+ EOM
113
+ end
114
+
115
+ content.comments.each do |comment|
116
+ builder << comment.string
117
+ end
118
+ end
119
+ when HoverProvider::Ruby::TypeContent
120
+ "`#{content.type}`"
121
+ when HoverProvider::RBS::TypeAliasContent
122
+ CommentBuilder.build do |builder|
123
+ builder << <<EOM
124
+ ```rbs
125
+ #{declaration_summary(content.decl)}
126
+ ```
127
+ EOM
128
+ if comment = content.decl.comment
129
+ builder << comment.string
130
+ end
131
+ end
132
+ when HoverProvider::RBS::ClassContent
133
+ CommentBuilder.build do |builder|
134
+ builder << <<EOM
135
+ ```rbs
136
+ #{declaration_summary(content.decl)}
137
+ ```
138
+ EOM
139
+ if comment = content.decl.comment
140
+ builder << comment.string
141
+ end
142
+ end
143
+ when HoverProvider::RBS::InterfaceContent
144
+ CommentBuilder.build do |builder|
145
+ builder << <<EOM
146
+ ```rbs
147
+ #{declaration_summary(content.decl)}
148
+ ```
149
+ EOM
150
+ if comment = content.decl.comment
151
+ builder << comment.string
152
+ end
153
+ end
154
+ else
155
+ raise content.class.to_s
156
+ end
157
+ end
158
+
159
+ def to_list(collection, &block)
160
+ buffer = ""
161
+
162
+ strings =
163
+ if block
164
+ collection.map(&block)
165
+ else
166
+ collection.map(&:to_s)
167
+ end
168
+
169
+ strings.each do |s|
170
+ buffer << "- #{s}\n"
171
+ end
172
+
173
+ buffer
174
+ end
175
+
176
+ def name_and_args(name, args)
177
+ if args.empty?
178
+ "#{name}"
179
+ else
180
+ "#{name}[#{args.map(&:to_s).join(", ")}]"
181
+ end
182
+ end
183
+
184
+ def name_and_params(name, params)
185
+ if params.empty?
186
+ "#{name}"
187
+ else
188
+ ps = params.each.map do |param|
189
+ s = ""
190
+ if param.unchecked?
191
+ s << "unchecked "
192
+ end
193
+ case param.variance
194
+ when :invariant
195
+ # nop
196
+ when :covariant
197
+ s << "out "
198
+ when :contravariant
199
+ s << "in "
200
+ end
201
+ s << param.name.to_s
202
+
203
+ if param.upper_bound
204
+ s << " < #{param.upper_bound.to_s}"
205
+ end
206
+
207
+ s
208
+ end
209
+
210
+ "#{name}[#{ps.join(", ")}]"
211
+ end
212
+ end
213
+
214
+ def declaration_summary(decl)
215
+ case decl
216
+ when RBS::AST::Declarations::Class
217
+ super_class = if super_class = decl.super_class
218
+ " < #{name_and_args(super_class.name, super_class.args)}"
219
+ end
220
+ "class #{name_and_params(decl.name, decl.type_params)}#{super_class}"
221
+ when RBS::AST::Declarations::Module
222
+ self_type = unless decl.self_types.empty?
223
+ " : #{decl.self_types.map {|s| name_and_args(s.name, s.args) }.join(", ")}"
224
+ end
225
+ "module #{name_and_params(decl.name, decl.type_params)}#{self_type}"
226
+ when RBS::AST::Declarations::Alias
227
+ "type #{decl.name} = #{decl.type}"
228
+ when RBS::AST::Declarations::Interface
229
+ "interface #{name_and_params(decl.name, decl.type_params)}"
230
+ end
231
+ end
232
+ end
233
+ end
234
+ end