steep 0.49.0 → 0.51.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -0
  3. data/Gemfile +4 -1
  4. data/Gemfile.lock +9 -6
  5. data/lib/steep/ast/annotation/collection.rb +10 -8
  6. data/lib/steep/ast/types/factory.rb +5 -5
  7. data/lib/steep/cli.rb +13 -0
  8. data/lib/steep/diagnostic/deprecated/unknown_constant_assigned.rb +28 -0
  9. data/lib/steep/diagnostic/ruby.rb +34 -15
  10. data/lib/steep/drivers/check.rb +3 -2
  11. data/lib/steep/drivers/langserver.rb +2 -2
  12. data/lib/steep/drivers/stats.rb +1 -0
  13. data/lib/steep/drivers/utils/jobs_count.rb +1 -1
  14. data/lib/steep/drivers/watch.rb +1 -1
  15. data/lib/steep/index/source_index.rb +18 -1
  16. data/lib/steep/interface/function.rb +5 -0
  17. data/lib/steep/module_helper.rb +4 -7
  18. data/lib/steep/project.rb +15 -1
  19. data/lib/steep/server/interaction_worker.rb +47 -4
  20. data/lib/steep/server/master.rb +10 -5
  21. data/lib/steep/server/type_check_worker.rb +19 -4
  22. data/lib/steep/server/worker_process.rb +15 -6
  23. data/lib/steep/services/completion_provider.rb +109 -1
  24. data/lib/steep/services/goto_service.rb +23 -10
  25. data/lib/steep/services/hover_content.rb +52 -4
  26. data/lib/steep/services/type_check_service.rb +8 -3
  27. data/lib/steep/signature/validator.rb +12 -5
  28. data/lib/steep/source.rb +19 -13
  29. data/lib/steep/type_construction.rb +238 -170
  30. data/lib/steep/type_inference/constant_env.rb +33 -15
  31. data/lib/steep/type_inference/context.rb +6 -7
  32. data/lib/steep/type_inference/type_env.rb +16 -54
  33. data/lib/steep/version.rb +1 -1
  34. data/smoke/const/test_expectations.yml +24 -19
  35. data/smoke/diagnostics/proc_type_expected.rb +3 -0
  36. data/smoke/diagnostics/test_expectations.yml +92 -10
  37. data/smoke/integer/test_expectations.yml +24 -4
  38. data/smoke/method/test_expectations.yml +30 -0
  39. data/smoke/regression/test_expectations.yml +24 -0
  40. data/smoke/yield/test_expectations.yml +20 -0
  41. data/steep.gemspec +1 -1
  42. metadata +6 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0273968ec727f3b7c5c1007f9e27966c50ad7bc3128217a4ef30be4f97321037'
4
- data.tar.gz: 195eb670673894e36af5e00ef911654f2a543c71e8de1d46c15e23035bef19c8
3
+ metadata.gz: 502d495f9b623c5d90a041a1e0bb7854be76251a8ac0f3567c1c91911eb641ee
4
+ data.tar.gz: 7845d6d26f38ceae87407d507f3f67b8d35bae18ecdd5f4ee9fdb841d434a4ad
5
5
  SHA512:
6
- metadata.gz: '0908edc4a3221256f450c9fd945d7127bd9ece3fa0359b7da88be8cebea30f7c766e023b84527e89e8f0c7956752310a3b0e98343b8c4808bfde518a89284456'
7
- data.tar.gz: 4004adb0d0e8f2e0cd2629cd7e0c2bd6513a3a48bbd96d1d77621bbe0979b73686ab9c8ad718e3243081fdf492ff9728b5bf6df8e7357e1b1cf810393dad264c
6
+ metadata.gz: e2e61987da5ef5d78381affeb2f4fbb8b84dd2a6fede0baa60c68f54a3464e3cb7eea0e2822f22a66d62f1de3b9f8b223cd6399dceb927397a3dab0bed3fea5d
7
+ data.tar.gz: ee91ba6b1a4d8f35ec1fbc157efd2fb54f27b11e398af09a7ef3d4f403ae0ae2fab3258404316c6ded646f688b61ff38b47a514fec83cd9fe1b4fcf136fdc441
data/CHANGELOG.md CHANGED
@@ -2,6 +2,29 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 0.51.0 (2022-04-01)
6
+
7
+ * Completion for constant ([\#524](https://github.com/soutaro/steep/pull/524))
8
+ * Better hover/completion message ([\#525](https://github.com/soutaro/steep/pull/525))
9
+ * Show available commands when using `--help` ([\#523](https://github.com/soutaro/steep/pull/523))
10
+
11
+ ## 0.50.0 (2022-03-22)
12
+
13
+ * CLI option for override steep command at spawn worker ([\#511](https://github.com/soutaro/steep/pull/511))
14
+ * LSP related improvements for Sublime LSP ([\#513](https://github.com/soutaro/steep/pull/513))
15
+ * Support Windows environment ([\#514](https://github.com/soutaro/steep/pull/514))
16
+ * Let `&:foo` proc work with methods with optional parameters ([\#516](https://github.com/soutaro/steep/pull/516))
17
+ * Fix unexpected error when or-asgn/and-asgn ([\#517](https://github.com/soutaro/steep/pull/517))
18
+ * Fix goto-definition from method call inside block ([\#518](https://github.com/soutaro/steep/pull/518))
19
+ * Better splat in array typing ([\#519](https://github.com/soutaro/steep/pull/519))
20
+
21
+ ## 0.49.1 (2022-03-11)
22
+
23
+ * Fix lambda typing ([\#506](https://github.com/soutaro/steep/pull/506))
24
+ * Validate type descendants ([\#507](https://github.com/soutaro/steep/pull/507))
25
+ * Fix print error with absolute path ([\#508](https://github.com/soutaro/steep/pull/508))
26
+ * Skip non-target ruby code on `steep stats` ([\#509](https://github.com/soutaro/steep/pull/509))
27
+
5
28
  ## 0.49.0 (2022-03-08)
6
29
 
7
30
  * Better typing for `#flat_map` ([\#504](https://github.com/soutaro/steep/pull/504))
data/Gemfile CHANGED
@@ -9,4 +9,7 @@ gem "without_steep_types", path: "test/gems/without_steep_types"
9
9
  gem "rake"
10
10
  gem "minitest", "~> 5.15"
11
11
  gem "minitest-hooks"
12
- gem "stackprof"
12
+ group :stackprof, optional: true do
13
+ gem "stackprof"
14
+ end
15
+ gem 'minitest-slow_test'
data/Gemfile.lock CHANGED
@@ -1,14 +1,14 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- steep (0.49.0)
4
+ steep (0.51.0)
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.2.0)
11
+ rbs (>= 2.3.0)
12
12
  terminal-table (>= 2, < 4)
13
13
 
14
14
  PATH
@@ -24,13 +24,13 @@ PATH
24
24
  GEM
25
25
  remote: https://rubygems.org/
26
26
  specs:
27
- activesupport (7.0.2.2)
27
+ activesupport (7.0.2.3)
28
28
  concurrent-ruby (~> 1.0, >= 1.0.2)
29
29
  i18n (>= 1.6, < 2)
30
30
  minitest (>= 5.1)
31
31
  tzinfo (~> 2.0)
32
32
  ast (2.4.2)
33
- concurrent-ruby (1.1.9)
33
+ concurrent-ruby (1.1.10)
34
34
  ffi (1.15.5)
35
35
  i18n (1.10.0)
36
36
  concurrent-ruby (~> 1.0)
@@ -41,7 +41,9 @@ GEM
41
41
  minitest (5.15.0)
42
42
  minitest-hooks (1.5.0)
43
43
  minitest (> 5.3)
44
- parallel (1.21.0)
44
+ minitest-slow_test (0.2.0)
45
+ minitest (>= 5.0)
46
+ parallel (1.22.1)
45
47
  parser (3.1.1.0)
46
48
  ast (~> 2.4.1)
47
49
  rainbow (3.1.1)
@@ -49,7 +51,7 @@ GEM
49
51
  rb-fsevent (0.11.1)
50
52
  rb-inotify (0.10.1)
51
53
  ffi (~> 1.0)
52
- rbs (2.2.2)
54
+ rbs (2.3.0)
53
55
  stackprof (0.2.19)
54
56
  terminal-table (3.0.2)
55
57
  unicode-display_width (>= 1.1.1, < 3)
@@ -63,6 +65,7 @@ PLATFORMS
63
65
  DEPENDENCIES
64
66
  minitest (~> 5.15)
65
67
  minitest-hooks
68
+ minitest-slow_test
66
69
  rake
67
70
  stackprof
68
71
  steep!
@@ -4,7 +4,7 @@ module Steep
4
4
  class Collection
5
5
  attr_reader :annotations
6
6
  attr_reader :factory
7
- attr_reader :current_module
7
+ attr_reader :context
8
8
 
9
9
  attr_reader :var_type_annotations
10
10
  attr_reader :const_type_annotations
@@ -19,10 +19,10 @@ module Steep
19
19
  attr_reader :dynamic_annotations
20
20
  attr_reader :break_type_annotation
21
21
 
22
- def initialize(annotations:, factory:, current_module:)
22
+ def initialize(annotations:, factory:, context:)
23
23
  @annotations = annotations
24
24
  @factory = factory
25
- @current_module = current_module
25
+ @context = context
26
26
 
27
27
  @var_type_annotations = {}
28
28
  @method_type_annotations = {}
@@ -64,7 +64,7 @@ module Steep
64
64
 
65
65
  def absolute_type(type)
66
66
  if type
67
- factory.absolute_type(type, namespace: current_module)
67
+ factory.absolute_type(type, context: context)
68
68
  end
69
69
  end
70
70
 
@@ -140,7 +140,7 @@ module Steep
140
140
  end
141
141
 
142
142
  def merge_block_annotations(annotations)
143
- if annotations.current_module != current_module || annotations.factory != factory
143
+ if annotations.context != context || annotations.factory != factory
144
144
  raise "Cannot merge another annotation: self=#{self}, other=#{annotations}"
145
145
  end
146
146
 
@@ -148,9 +148,11 @@ module Steep
148
148
  annotation.is_a?(BlockType) || annotation.is_a?(BreakType)
149
149
  end
150
150
 
151
- self.class.new(annotations: retained_annotations + annotations.annotations,
152
- factory: factory,
153
- current_module: current_module)
151
+ self.class.new(
152
+ annotations: retained_annotations + annotations.annotations,
153
+ factory: factory,
154
+ context: context
155
+ )
154
156
  end
155
157
 
156
158
  def any?(&block)
@@ -18,7 +18,7 @@ module Steep
18
18
  end
19
19
 
20
20
  def type_name_resolver
21
- @type_name_resolver ||= RBS::TypeNameResolver.from_env(definition_builder.env)
21
+ @type_name_resolver ||= RBS::Resolver::TypeNameResolver.new(definition_builder.env)
22
22
  end
23
23
 
24
24
  def type_opt(type)
@@ -810,15 +810,15 @@ module Steep
810
810
  @env ||= definition_builder.env
811
811
  end
812
812
 
813
- def absolute_type(type, namespace:)
813
+ def absolute_type(type, context:)
814
814
  absolute_type = type_1(type).map_type_name do |name|
815
- absolute_type_name(name, namespace: namespace) || name.absolute!
815
+ absolute_type_name(name, context: context) || name.absolute!
816
816
  end
817
817
  type(absolute_type)
818
818
  end
819
819
 
820
- def absolute_type_name(type_name, namespace:)
821
- type_name_resolver.resolve(type_name, context: namespace.ascend)
820
+ def absolute_type_name(type_name, context:)
821
+ type_name_resolver.resolve(type_name, context: context)
822
822
  end
823
823
 
824
824
  def instance_type(type_name, args: nil, location: nil)
data/lib/steep/cli.rb CHANGED
@@ -23,6 +23,14 @@ module Steep
23
23
 
24
24
  def process_global_options
25
25
  OptionParser.new do |opts|
26
+ opts.banner = <<~USAGE
27
+ Usage: steep [options]
28
+
29
+ available commands: #{CLI.available_commands.join(', ')}
30
+
31
+ Options:
32
+ USAGE
33
+
26
34
  opts.on("--version") do
27
35
  process_version
28
36
  exit 0
@@ -72,6 +80,11 @@ module Steep
72
80
  opts.on("-j N", "--jobs=N", "Specify the number of type check workers (defaults: #{default})") do |count|
73
81
  command.jobs_count = Integer(count) if Integer(count) > 0
74
82
  end
83
+
84
+ command.steep_command = "steep"
85
+ opts.on("--steep-command=COMMAND", "Specify command to exec Steep CLI for worker (defaults: steep)") do |cmd|
86
+ command.steep_command = cmd
87
+ end
75
88
  end
76
89
 
77
90
  def process_init
@@ -0,0 +1,28 @@
1
+ Steep.logger.error "Diagnostic `Ruby::UnknownConstantAssigned` is deprecated. Use `Ruby::UnknownConstant` instead."
2
+
3
+ module Steep
4
+ module Diagnostic
5
+ module Ruby
6
+ class UnknownConstantAssigned < Base
7
+ attr_reader :context
8
+ attr_reader :name
9
+
10
+ def initialize(node:, context:, name:)
11
+ const = node.children[0]
12
+ loc = if const
13
+ const.loc.expression.join(node.loc.name)
14
+ else
15
+ node.loc.name
16
+ end
17
+ super(node: node, location: loc)
18
+ @context = context
19
+ @name = name
20
+ end
21
+
22
+ def header_line
23
+ "Cannot find the declaration of constant `#{name}`"
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -551,27 +551,33 @@ module Steep
551
551
  end
552
552
  end
553
553
 
554
- class UnknownConstantAssigned < Base
555
- attr_reader :context
554
+ class UnknownConstant < Base
556
555
  attr_reader :name
556
+ attr_reader :kind
557
557
 
558
- def initialize(node:, context:, name:)
559
- const = node.children[0]
560
- loc = if const
561
- const.loc.expression.join(node.loc.name)
562
- else
563
- node.loc.name
564
- end
565
- super(node: node, location: loc)
566
- @context = context
558
+ def initialize(node:, name:)
559
+ super(node: node, location: node.loc.name)
567
560
  @name = name
561
+ @kind = :constant
562
+ end
563
+
564
+ def class!
565
+ @kind = :class
566
+ self
567
+ end
568
+
569
+ def module!
570
+ @kind = :module
571
+ self
568
572
  end
569
573
 
570
574
  def header_line
571
- "Cannot find the declaration of constant `#{name}`"
575
+ "Cannot find the declaration of #{kind}: `#{name}`"
572
576
  end
573
577
  end
574
578
 
579
+ autoload :UnknownConstantAssigned, "steep/diagnostic/deprecated/unknown_constant_assigned"
580
+
575
581
  class FallbackAny < Base
576
582
  def initialize(node:)
577
583
  super(node: node)
@@ -669,6 +675,19 @@ module Steep
669
675
  end
670
676
  end
671
677
 
678
+ class ProcTypeExpected < Base
679
+ attr_reader :type
680
+
681
+ def initialize(node:, type:)
682
+ super(node: node)
683
+ @type = type
684
+ end
685
+
686
+ def header_line
687
+ "Proc type is expected but `#{type.to_s}` is specified"
688
+ end
689
+ end
690
+
672
691
  class UnsupportedSyntax < Base
673
692
  attr_reader :message
674
693
 
@@ -731,7 +750,7 @@ module Steep
731
750
  ImplicitBreakValueMismatch => :warning,
732
751
  FallbackAny => :information,
733
752
  ElseOnExhaustiveCase => :warning,
734
- UnknownConstantAssigned => :warning,
753
+ UnknownConstant => :warning,
735
754
  MethodDefinitionMissing => :information
736
755
  }
737
756
  ).freeze
@@ -744,7 +763,7 @@ module Steep
744
763
  ImplicitBreakValueMismatch => nil,
745
764
  FallbackAny => nil,
746
765
  ElseOnExhaustiveCase => nil,
747
- UnknownConstantAssigned => nil,
766
+ UnknownConstant => nil,
748
767
  MethodDefinitionMissing => nil
749
768
  }
750
769
  ).freeze
@@ -757,7 +776,7 @@ module Steep
757
776
  ImplicitBreakValueMismatch => nil,
758
777
  FallbackAny => nil,
759
778
  ElseOnExhaustiveCase => nil,
760
- UnknownConstantAssigned => nil,
779
+ UnknownConstant => nil,
761
780
  MethodDefinitionMissing => nil,
762
781
  UnexpectedJump => nil
763
782
  }
@@ -39,6 +39,7 @@ module Steep
39
39
  steepfile: project.steepfile_path,
40
40
  args: command_line_patterns,
41
41
  delay_shutdown: true,
42
+ steep_command: steep_command,
42
43
  count: jobs_count
43
44
  )
44
45
 
@@ -214,8 +215,8 @@ module Steep
214
215
  total = errors.sum {|notification| notification[:diagnostics].size }
215
216
 
216
217
  errors.each do |notification|
217
- path = project.relative_path(Pathname(URI.parse(notification[:uri]).path))
218
- buffer = RBS::Buffer.new(name: path, content: path.read)
218
+ path = Pathname(URI.parse(notification[:uri]).path)
219
+ buffer = RBS::Buffer.new(name: project.relative_path(path), content: path.read)
219
220
  printer = DiagnosticPrinter.new(buffer: buffer, stdout: stdout)
220
221
 
221
222
  notification[:diagnostics].each do |diag|
@@ -37,8 +37,8 @@ module Steep
37
37
  def run
38
38
  @project = load_config()
39
39
 
40
- interaction_worker = Server::WorkerProcess.spawn_worker(:interaction, name: "interaction", steepfile: project.steepfile_path)
41
- typecheck_workers = Server::WorkerProcess.spawn_typecheck_workers(steepfile: project.steepfile_path, args: [], count: jobs_count)
40
+ interaction_worker = Server::WorkerProcess.spawn_worker(:interaction, name: "interaction", steepfile: project.steepfile_path, steep_command: steep_command)
41
+ typecheck_workers = Server::WorkerProcess.spawn_typecheck_workers(steepfile: project.steepfile_path, args: [], steep_command: steep_command, count: jobs_count)
42
42
 
43
43
  master = Server::Master.new(
44
44
  project: project,
@@ -129,6 +129,7 @@ module Steep
129
129
  steepfile: project.steepfile_path,
130
130
  delay_shutdown: true,
131
131
  args: command_line_patterns,
132
+ steep_command: steep_command,
132
133
  count: jobs_count
133
134
  )
134
135
 
@@ -2,7 +2,7 @@ module Steep
2
2
  module Drivers
3
3
  module Utils
4
4
  module JobsCount
5
- attr_accessor :jobs_count
5
+ attr_accessor :jobs_count, :steep_command
6
6
  end
7
7
  end
8
8
  end
@@ -41,7 +41,7 @@ module Steep
41
41
  server_reader = LanguageServer::Protocol::Transport::Io::Reader.new(server_read)
42
42
  server_writer = LanguageServer::Protocol::Transport::Io::Writer.new(server_write)
43
43
 
44
- typecheck_workers = Server::WorkerProcess.spawn_typecheck_workers(steepfile: project.steepfile_path, args: dirs.map(&:to_s), count: jobs_count)
44
+ typecheck_workers = Server::WorkerProcess.spawn_typecheck_workers(steepfile: project.steepfile_path, args: dirs.map(&:to_s), steep_command: steep_command, count: jobs_count)
45
45
 
46
46
  master = Server::Master.new(
47
47
  project: project,
@@ -16,7 +16,7 @@ module Steep
16
16
 
17
17
  def add_definition(node)
18
18
  case node.type
19
- when :casgn, :class, :module
19
+ when :casgn, :const
20
20
  @definitions << node
21
21
  else
22
22
  raise "Unexpected constant definition: #{node.type}"
@@ -145,6 +145,23 @@ module Steep
145
145
  raise
146
146
  end
147
147
  end
148
+
149
+ def reference(constant_node: nil)
150
+ case
151
+ when constant_node
152
+ constant_index.each do |name, entry|
153
+ if entry.references.include?(constant_node)
154
+ return name
155
+ end
156
+
157
+ if entry.definitions.include?(constant_node)
158
+ return name
159
+ end
160
+ end
161
+
162
+ nil
163
+ end
164
+ end
148
165
  end
149
166
  end
150
167
  end
@@ -879,6 +879,11 @@ module Steep
879
879
  !has_positional? && !has_keywords?
880
880
  end
881
881
 
882
+ # Returns true if all arguments are non-required.
883
+ def optional?
884
+ required.empty? && required_keywords.empty?
885
+ end
886
+
882
887
  # self + params returns a new params for overloading.
883
888
  #
884
889
  def +(other)
@@ -1,12 +1,9 @@
1
1
  module Steep
2
2
  module ModuleHelper
3
- def module_name_from_node(node)
4
- case node.type
5
- when :const, :casgn
6
- namespace = namespace_from_node(node.children[0]) or return
7
- name = node.children[1]
8
- RBS::TypeName.new(name: name, namespace: namespace)
9
- end
3
+ def module_name_from_node(parent_node, constant_name)
4
+ namespace = namespace_from_node(parent_node) or return
5
+ name = constant_name
6
+ RBS::TypeName.new(name: name, namespace: namespace)
10
7
  end
11
8
 
12
9
  def namespace_from_node(node)
data/lib/steep/project.rb CHANGED
@@ -16,7 +16,21 @@ module Steep
16
16
  steepfile_path.parent
17
17
  end
18
18
 
19
- def relative_path(path)
19
+ def relative_path(orig_path)
20
+ path = if Gem.win_platform?
21
+ path_str = URI.decode_www_form_component(
22
+ orig_path.to_s.delete_prefix("/")
23
+ )
24
+ unless path_str.start_with?(%r{[a-z]:/}i)
25
+ # FIXME: Sometimes drive letter is missing, taking from base_dir
26
+ path_str = base_dir.to_s.split("/")[0] + "/" + path_str
27
+ end
28
+ Pathname.new(
29
+ path_str
30
+ )
31
+ else
32
+ orig_path
33
+ end
20
34
  path.relative_path_from(base_dir)
21
35
  end
22
36
 
@@ -89,7 +89,7 @@ module Steep
89
89
  end
90
90
 
91
91
  LSP::Interface::Hover.new(
92
- contents: { kind: "markdown", value: format_hover(content) },
92
+ contents: { kind: "markdown", value: format_hover(content)&.gsub(/<!--(?~-->)-->/, "") },
93
93
  range: range
94
94
  )
95
95
  end
@@ -175,6 +175,21 @@ HOVER
175
175
  end
176
176
 
177
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")
178
193
  when Services::HoverContent::TypeContent
179
194
  "`#{content.type}`"
180
195
  end
@@ -271,7 +286,7 @@ HOVER
271
286
  ),
272
287
  end: LanguageServer::Protocol::Interface::Position.new(
273
288
  line: job.line - 1,
274
- character: job.column - prefix.size
289
+ character: job.column
275
290
  )
276
291
  )
277
292
 
@@ -327,7 +342,16 @@ HOVER
327
342
  if comment
328
343
  LSP::Interface::MarkupContent.new(
329
344
  kind: LSP::Constant::MarkupKind::MARKDOWN,
330
- value: comment.string
345
+ value: comment.string.gsub(/<!--(?~-->)-->/, "")
346
+ )
347
+ end
348
+ end
349
+
350
+ def format_comments(comments)
351
+ unless comments.empty?
352
+ LSP::Interface::MarkupContent.new(
353
+ kind: LSP::Constant::MarkupKind::MARKDOWN,
354
+ value: comments.map(&:string).join("\n----\n").gsub(/<!--(?~-->)-->/, "")
331
355
  )
332
356
  end
333
357
  end
@@ -408,6 +432,25 @@ HOVER
408
432
  new_text: item.identifier
409
433
  )
410
434
  )
435
+ when Services::CompletionProvider::ConstantItem
436
+ case
437
+ when item.class? || item.module?
438
+ kind = LanguageServer::Protocol::Constant::CompletionItemKind::CLASS
439
+ detail = item.full_name.to_s
440
+ else
441
+ kind = LanguageServer::Protocol::Constant::CompletionItemKind::CONSTANT
442
+ detail = item.type.to_s
443
+ end
444
+ LanguageServer::Protocol::Interface::CompletionItem.new(
445
+ label: item.identifier,
446
+ kind: kind,
447
+ detail: detail,
448
+ documentation: format_comments(item.comments),
449
+ text_edit: LanguageServer::Protocol::Interface::TextEdit.new(
450
+ range: range,
451
+ new_text: item.identifier
452
+ )
453
+ )
411
454
  when Services::CompletionProvider::MethodNameItem
412
455
  method_type_snippet = method_type_to_snippet(item.method_type)
413
456
  LanguageServer::Protocol::Interface::CompletionItem.new(
@@ -418,7 +461,7 @@ HOVER
418
461
  new_text: "#{item.identifier}#{method_type_snippet}",
419
462
  range: range
420
463
  ),
421
- documentation: item.comment&.string,
464
+ documentation: format_comment(item.comment),
422
465
  insert_text_format: LanguageServer::Protocol::Constant::InsertTextFormat::SNIPPET,
423
466
  sort_text: item.inherited? ? 'z' : 'a' # Ensure language server puts non-inherited methods before inherited methods
424
467
  )
@@ -49,9 +49,14 @@ module Steep
49
49
  end
50
50
 
51
51
  def checking_path?(path)
52
- library_paths.include?(path) ||
53
- signature_paths.include?(path) ||
54
- code_paths.include?(path)
52
+ [library_paths, signature_paths, code_paths].any? do |paths|
53
+ if Gem.win_platform?
54
+ # FIXME: Sometimes drive letter is missing, so comparing without drive letter.
55
+ paths.any? {|p| p.to_s.split("/", 2)[1] == path.to_s.split("/", 2)[1]}
56
+ else
57
+ paths.include?(path)
58
+ end
59
+ end
55
60
  end
56
61
 
57
62
  def checked(path)
@@ -496,7 +501,7 @@ module Steep
496
501
  partialResult: true
497
502
  },
498
503
  completion_provider: LSP::Interface::CompletionOptions.new(
499
- trigger_characters: [".", "@"],
504
+ trigger_characters: [".", "@", ":"],
500
505
  work_done_progress: true
501
506
  ),
502
507
  workspace_symbol_provider: true,
@@ -739,7 +744,7 @@ module Steep
739
744
  { kind: "end" }
740
745
  else
741
746
  progress_string = ("▮"*(percentage/5)) + ("▯"*(20 - percentage/5))
742
- { kind: "report", percentage: percentage, message: "#{progress_string} (#{percentage}%)" }
747
+ { kind: "report", percentage: percentage, message: "#{progress_string}" }
743
748
  end
744
749
 
745
750
  job_queue << SendMessageJob.to_client(