steep 2.1.0.dev.1 → 2.1.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/CHANGELOG.md +35 -0
- data/CLAUDE.md +2 -2
- data/README.md +2 -2
- data/bin/steep-check.rb +4 -4
- data/lib/steep/ast/types/helper.rb +0 -1
- data/lib/steep/ast/types/name.rb +1 -1
- data/lib/steep/cli.rb +32 -3
- data/lib/steep/daemon.rb +49 -9
- data/lib/steep/drivers/init.rb +4 -3
- data/lib/steep/drivers/langserver.rb +33 -1
- data/lib/steep/drivers/query.rb +40 -2
- data/lib/steep/interface/builder.rb +24 -4
- data/lib/steep/server/base_worker.rb +15 -0
- data/lib/steep/server/command_socket.rb +181 -0
- data/lib/steep/server/custom_methods.rb +12 -0
- data/lib/steep/server/master.rb +383 -2
- data/lib/steep/server/type_check_worker.rb +48 -2
- data/lib/steep/services/goto_service.rb +6 -2
- data/lib/steep/services/hover_provider/content.rb +1 -1
- data/lib/steep/source.rb +3 -4
- data/lib/steep/subtyping/check.rb +6 -3
- data/lib/steep/tagged_logging.rb +4 -1
- data/lib/steep/type_construction.rb +20 -13
- data/lib/steep/type_inference/case_when.rb +2 -2
- data/lib/steep/type_inference/send_args.rb +9 -5
- data/lib/steep/version.rb +1 -1
- data/lib/steep.rb +1 -0
- data/steep.gemspec +2 -8
- metadata +6 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3836d60ec7ec072655011df06539859dbbca90170c94a15a6f636537c486eba4
|
|
4
|
+
data.tar.gz: '01394e50e3759284559f635e5f2ef34d79a5b4716a6bbebbf07c383cffd14c41'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 66603b9a15c9a6a5f34c1812969d32967d2755c60fe5470d225e13426bfec93f2ff6174a6675c15278fe99fe7d2fec17ae5dbf32d6ab4d9abc6c8bd96ba14166
|
|
7
|
+
data.tar.gz: 0c41cbcdf631c3d5528681b990cad4f36f1dce2ae029aa97ea6e6bbb6199b7af890470c4ca9358cd5152f267cf7f1797d10482e5d5f1e667ae2dce2434fd181f
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## 2.1.0 (2026-08-27)
|
|
4
|
+
|
|
5
|
+
Steep 2.1 opens the running server to commands other than the editor's. `steep langserver` now binds
|
|
6
|
+
the per-project UNIX socket that `steep server` serves, so `steep check` and `steep query` reach the
|
|
7
|
+
language server the editor is already running instead of needing a daemon of their own, and the new
|
|
8
|
+
`steep query diagnostics` reads the diagnostics that server has already computed rather than starting
|
|
9
|
+
a type check of its own. Both are aimed at tools that edit files on disk and want fast feedback,
|
|
10
|
+
coding agents in particular.
|
|
11
|
+
|
|
12
|
+
The type checker gains support for Ruby 3.4's `it` block parameter, and RBS is updated to 4.2.0.
|
|
13
|
+
|
|
14
|
+
### Type checker core
|
|
15
|
+
|
|
16
|
+
* Infer tuple types for array literals against pair interface hints like `Hash::_Pair` ([#2253](https://github.com/soutaro/steep/pull/2253))
|
|
17
|
+
* Accept a type alias as the type of a lambda's block parameter ([#2263](https://github.com/soutaro/steep/pull/2263))
|
|
18
|
+
* Build expensive log tags only when something is logged ([#2271](https://github.com/soutaro/steep/pull/2271))
|
|
19
|
+
* Accept block-pass arguments for optional blocks ([#2261](https://github.com/soutaro/steep/pull/2261))
|
|
20
|
+
* feat: support the `it` block parameter ([#2238](https://github.com/soutaro/steep/pull/2238))
|
|
21
|
+
* Fix `UnreachableBranch` on `==` against literal supertype (`Symbol` / `Integer` / `String`) ([#2223](https://github.com/soutaro/steep/pull/2223))
|
|
22
|
+
|
|
23
|
+
### Commandline tool
|
|
24
|
+
|
|
25
|
+
* Stop `steep query definition` from hanging on inline sources ([#2276](https://github.com/soutaro/steep/pull/2276))
|
|
26
|
+
* Serve steep query/check through the language server's UNIX socket ([#2273](https://github.com/soutaro/steep/pull/2273))
|
|
27
|
+
* Add `steep query diagnostics` ([#2274](https://github.com/soutaro/steep/pull/2274))
|
|
28
|
+
* Point the Steepfile template, README and CLAUDE.md at rbs collection ([#2269](https://github.com/soutaro/steep/pull/2269))
|
|
29
|
+
|
|
30
|
+
### Miscellaneous
|
|
31
|
+
|
|
32
|
+
* Update RBS to 4.2.0 ([#2277](https://github.com/soutaro/steep/pull/2277))
|
|
33
|
+
* Fix `bin/steep-check.rb` for the current API ([#2270](https://github.com/soutaro/steep/pull/2270))
|
|
34
|
+
* Update RBS to 4.2.0.pre.1 ([#2267](https://github.com/soutaro/steep/pull/2267))
|
|
35
|
+
* Fix Ruby warnings printed while running tests ([#2266](https://github.com/soutaro/steep/pull/2266))
|
|
36
|
+
* Run test subprocesses outside the parent Bundler env ([#2225](https://github.com/soutaro/steep/pull/2225))
|
|
37
|
+
|
|
3
38
|
## 2.0.0 (2026-04-14)
|
|
4
39
|
|
|
5
40
|
### Summary
|
data/CLAUDE.md
CHANGED
|
@@ -98,8 +98,8 @@ bundle exec rake build
|
|
|
98
98
|
**Steepfile**: Defines type checking targets
|
|
99
99
|
- `check`: Directories to type check
|
|
100
100
|
- `signature`: RBS signature directories
|
|
101
|
-
- `library`:
|
|
102
|
-
- `collection_config`:
|
|
101
|
+
- `library`: RBSs that rbs collection doesn't manage
|
|
102
|
+
- `collection_config`: Path to `rbs_collection.yaml` (the project root one is read by default)
|
|
103
103
|
- Multiple targets supported (app, test, bin)
|
|
104
104
|
|
|
105
105
|
**RBS Collection**: Manages external type definitions via `rbs_collection.steep.yaml`
|
data/README.md
CHANGED
|
@@ -29,11 +29,11 @@ Edit the `Steepfile`:
|
|
|
29
29
|
target :app do
|
|
30
30
|
check "lib"
|
|
31
31
|
signature "sig"
|
|
32
|
-
|
|
33
|
-
library "pathname"
|
|
34
32
|
end
|
|
35
33
|
```
|
|
36
34
|
|
|
35
|
+
RBSs for the gems in `Gemfile.lock` are loaded via [rbs collection](https://github.com/ruby/rbs/blob/master/docs/collection.md), which you set up with `rbs collection init` and `rbs collection install`. Add a `library` call only for an RBS that rbs collection doesn't manage.
|
|
36
|
+
|
|
37
37
|
### 1. Declare Types
|
|
38
38
|
|
|
39
39
|
Declare types in `.rbs` files in `sig` directory.
|
data/bin/steep-check.rb
CHANGED
|
@@ -67,7 +67,7 @@ class Command
|
|
|
67
67
|
target.options.load_collection_lock
|
|
68
68
|
|
|
69
69
|
signature_service = Steep::Project::Target.construct_env_loader(options: target.options, project: project).yield_self do |loader|
|
|
70
|
-
Steep::Services::SignatureService.load_from(loader)
|
|
70
|
+
Steep::Services::SignatureService.load_from(loader, implicitly_returns_nil: target.implicitly_returns_nil)
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
env = signature_service.latest_env
|
|
@@ -76,8 +76,8 @@ class Command
|
|
|
76
76
|
|
|
77
77
|
signature_files.each do |path, content|
|
|
78
78
|
buffer = RBS::Buffer.new(name: path.to_s, content: content)
|
|
79
|
-
|
|
80
|
-
env.
|
|
79
|
+
_, dirs, decls = RBS::Parser.parse_signature(buffer)
|
|
80
|
+
env.add_source(RBS::Source::RBS.new(buffer, dirs, decls))
|
|
81
81
|
new_decls.merge(decls)
|
|
82
82
|
end
|
|
83
83
|
|
|
@@ -94,7 +94,7 @@ class Command
|
|
|
94
94
|
|
|
95
95
|
definition_builder = RBS::DefinitionBuilder.new(env: env)
|
|
96
96
|
factory = AST::Types::Factory.new(builder: definition_builder)
|
|
97
|
-
builder = Interface::Builder.new(factory)
|
|
97
|
+
builder = Interface::Builder.new(factory, implicitly_returns_nil: target.implicitly_returns_nil)
|
|
98
98
|
subtyping = Subtyping::Check.new(builder: builder)
|
|
99
99
|
|
|
100
100
|
typings = {}
|
data/lib/steep/ast/types/name.rb
CHANGED
data/lib/steep/cli.rb
CHANGED
|
@@ -355,6 +355,9 @@ Options:
|
|
|
355
355
|
BANNER
|
|
356
356
|
handle_steepfile_option(opts, command)
|
|
357
357
|
opts.on("--refork") { command.refork = true }
|
|
358
|
+
opts.on("--[no-]command-socket", "Accept `steep query`/`steep check` connections on a UNIX socket (default: true)") do |v|
|
|
359
|
+
command.command_socket = v ? true : false
|
|
360
|
+
end
|
|
358
361
|
handle_jobs_option command.jobs_option, opts
|
|
359
362
|
handle_logging_options opts
|
|
360
363
|
end.parse!(argv)
|
|
@@ -618,8 +621,9 @@ BANNER
|
|
|
618
621
|
The user interface and output format may change without deprecation.
|
|
619
622
|
|
|
620
623
|
Available subcommands:
|
|
621
|
-
hover
|
|
622
|
-
definition
|
|
624
|
+
hover Get hover information (type, documentation) for a position
|
|
625
|
+
definition Get the definition(s) of a class, type alias, constant, or method name
|
|
626
|
+
diagnostics Get the type check diagnostics the server has computed
|
|
623
627
|
|
|
624
628
|
Options:
|
|
625
629
|
--help Show this help message
|
|
@@ -628,6 +632,7 @@ BANNER
|
|
|
628
632
|
steep query hover lib/foo.rb:10:5
|
|
629
633
|
steep query definition RBS::Location
|
|
630
634
|
steep query definition RBS::Parser.parse_signature
|
|
635
|
+
steep query diagnostics lib/foo.rb sig/foo.rbs
|
|
631
636
|
HELP
|
|
632
637
|
return 0
|
|
633
638
|
end
|
|
@@ -714,9 +719,33 @@ BANNER
|
|
|
714
719
|
end
|
|
715
720
|
|
|
716
721
|
Drivers::Query.new(stdout: stdout, stderr: stderr).run_definition(names: argv.dup)
|
|
722
|
+
when "diagnostics"
|
|
723
|
+
OptionParser.new do |opts|
|
|
724
|
+
opts.banner = <<BANNER
|
|
725
|
+
Usage: steep query diagnostics [options] [FILE ...]
|
|
726
|
+
|
|
727
|
+
Description:
|
|
728
|
+
Get the type check diagnostics the server has computed.
|
|
729
|
+
Connects to the running Steep server, reloads files changed on disk, waits for the
|
|
730
|
+
type checking to finish, and prints the diagnostics as JSONL (one JSON object per
|
|
731
|
+
line for each file).
|
|
732
|
+
|
|
733
|
+
When FILEs are given, only the diagnostics of those files are printed.
|
|
734
|
+
`"diagnostics": null` means the server has not type checked the file yet.
|
|
735
|
+
|
|
736
|
+
Note:
|
|
737
|
+
This is an experimental command.
|
|
738
|
+
The user interface and output format may change without deprecation.
|
|
739
|
+
|
|
740
|
+
Options:
|
|
741
|
+
BANNER
|
|
742
|
+
handle_logging_options opts
|
|
743
|
+
end.parse!(argv)
|
|
744
|
+
|
|
745
|
+
Drivers::Query.new(stdout: stdout, stderr: stderr).run_diagnostics(paths: argv.dup)
|
|
717
746
|
else
|
|
718
747
|
stderr.puts "Unknown query subcommand: #{subcommand}"
|
|
719
|
-
stderr.puts " available subcommands: hover, definition"
|
|
748
|
+
stderr.puts " available subcommands: hover, definition, diagnostics"
|
|
720
749
|
1
|
|
721
750
|
end
|
|
722
751
|
end
|
data/lib/steep/daemon.rb
CHANGED
|
@@ -43,18 +43,22 @@ module Steep
|
|
|
43
43
|
false
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
+
# Returns true when something is serving the socket, whether it is a daemon or a language server
|
|
47
|
+
#
|
|
48
|
+
# The socket is the only reliable signal: a language server records its pid elsewhere, so
|
|
49
|
+
# requiring `pid_path` here would hide it from `steep check` and `steep query`.
|
|
50
|
+
#
|
|
46
51
|
def running?
|
|
47
|
-
return false unless File.exist?(
|
|
52
|
+
return false unless File.exist?(socket_path)
|
|
48
53
|
|
|
49
|
-
pid = File.read(pid_path).to_i
|
|
50
|
-
Process.kill(0, pid)
|
|
51
54
|
socket = UNIXSocket.new(socket_path)
|
|
52
55
|
socket.close
|
|
53
56
|
true
|
|
54
|
-
rescue Errno::
|
|
57
|
+
rescue Errno::ENOENT, Errno::ECONNREFUSED, Errno::ENOTSOCK
|
|
55
58
|
false
|
|
56
59
|
end
|
|
57
60
|
|
|
61
|
+
|
|
58
62
|
def cleanup
|
|
59
63
|
[socket_path, pid_path].each do |path|
|
|
60
64
|
File.delete(path)
|
|
@@ -64,8 +68,13 @@ module Steep
|
|
|
64
68
|
end
|
|
65
69
|
|
|
66
70
|
def start(stderr:)
|
|
71
|
+
if pid = live_pid(pid_path)
|
|
72
|
+
stderr.puts "Steep server already running (PID: #{pid})"
|
|
73
|
+
return true
|
|
74
|
+
end
|
|
75
|
+
|
|
67
76
|
if running?
|
|
68
|
-
stderr.puts "
|
|
77
|
+
stderr.puts "Another process is already serving this project (e.g. `steep langserver`)"
|
|
69
78
|
return true
|
|
70
79
|
end
|
|
71
80
|
|
|
@@ -106,7 +115,12 @@ module Steep
|
|
|
106
115
|
|
|
107
116
|
def stop(stderr:)
|
|
108
117
|
unless File.exist?(pid_path)
|
|
109
|
-
|
|
118
|
+
if running?
|
|
119
|
+
stderr.puts "Steep server is not running. This project is served by another process"
|
|
120
|
+
stderr.puts "(e.g. `steep langserver`), which this command does not stop."
|
|
121
|
+
else
|
|
122
|
+
stderr.puts "Steep server is not running"
|
|
123
|
+
end
|
|
110
124
|
return
|
|
111
125
|
end
|
|
112
126
|
|
|
@@ -129,13 +143,29 @@ module Steep
|
|
|
129
143
|
end
|
|
130
144
|
cleanup
|
|
131
145
|
rescue Errno::ESRCH
|
|
132
|
-
|
|
133
|
-
|
|
146
|
+
# The pid file was stale. The socket may still belong to another live server,
|
|
147
|
+
# which `cleanup` would break by deleting it.
|
|
148
|
+
if running?
|
|
149
|
+
begin
|
|
150
|
+
File.delete(pid_path)
|
|
151
|
+
rescue Errno::ENOENT
|
|
152
|
+
# Already deleted
|
|
153
|
+
end
|
|
154
|
+
stderr.puts "Removed a stale pid file. This project is served by another process."
|
|
155
|
+
else
|
|
156
|
+
cleanup
|
|
157
|
+
stderr.puts "Steep server was not running (cleaned up stale files)"
|
|
158
|
+
end
|
|
134
159
|
end
|
|
135
160
|
|
|
136
161
|
def status(stderr:)
|
|
137
162
|
if running?
|
|
138
|
-
pid =
|
|
163
|
+
unless pid = live_pid(pid_path)
|
|
164
|
+
stderr.puts "This project is served by another process (e.g. `steep langserver`)"
|
|
165
|
+
stderr.puts " Socket: #{socket_path}"
|
|
166
|
+
return
|
|
167
|
+
end
|
|
168
|
+
|
|
139
169
|
stderr.puts "Steep server running (PID: #{pid})"
|
|
140
170
|
stderr.puts " Socket: #{socket_path}"
|
|
141
171
|
stderr.puts " Log: #{log_path}"
|
|
@@ -167,6 +197,16 @@ module Steep
|
|
|
167
197
|
|
|
168
198
|
private
|
|
169
199
|
|
|
200
|
+
# The pid recorded in `path`, when the file exists and that process is alive
|
|
201
|
+
def live_pid(path)
|
|
202
|
+
pid = File.read(path).to_i
|
|
203
|
+
return nil unless pid > 0
|
|
204
|
+
Process.kill(0, pid)
|
|
205
|
+
pid
|
|
206
|
+
rescue Errno::ESRCH, Errno::ENOENT
|
|
207
|
+
nil
|
|
208
|
+
end
|
|
209
|
+
|
|
170
210
|
def run_server(stderr:)
|
|
171
211
|
project = load_project
|
|
172
212
|
server = Server.new(config: config, project: project, stderr:)
|
data/lib/steep/drivers/init.rb
CHANGED
|
@@ -19,8 +19,9 @@ module Steep
|
|
|
19
19
|
# check "app/models/**/*.rb" # Glob
|
|
20
20
|
# # ignore "lib/templates/*.rb"
|
|
21
21
|
#
|
|
22
|
-
# #
|
|
23
|
-
# #
|
|
22
|
+
# # RBSs for the gems in Gemfile.lock are loaded via rbs collection automatically.
|
|
23
|
+
# # Set it up with `rbs collection init` and `rbs collection install`.
|
|
24
|
+
# # library "monitor" # Load an RBS that rbs collection doesn't manage
|
|
24
25
|
#
|
|
25
26
|
# # configure_code_diagnostics(D::Ruby.default) # `default` diagnostics setting (applies by default)
|
|
26
27
|
# # configure_code_diagnostics(D::Ruby.strict) # `strict` diagnostics setting
|
|
@@ -38,7 +39,7 @@ module Steep
|
|
|
38
39
|
#
|
|
39
40
|
# configure_code_diagnostics(D::Ruby.lenient) # Weak type checking for test code
|
|
40
41
|
#
|
|
41
|
-
# # library "
|
|
42
|
+
# # library "monitor" # Load an RBS that rbs collection doesn't manage
|
|
42
43
|
# end
|
|
43
44
|
EOF
|
|
44
45
|
|
|
@@ -9,6 +9,7 @@ module Steep
|
|
|
9
9
|
attr_reader :type_check_thread
|
|
10
10
|
attr_reader :jobs_option
|
|
11
11
|
attr_accessor :refork
|
|
12
|
+
attr_accessor :command_socket
|
|
12
13
|
|
|
13
14
|
include Utils::DriverHelper
|
|
14
15
|
|
|
@@ -20,6 +21,7 @@ module Steep
|
|
|
20
21
|
@type_check_queue = Queue.new
|
|
21
22
|
@jobs_option = Utils::JobsOption.new(jobs_count_modifier: -1)
|
|
22
23
|
@refork = false
|
|
24
|
+
@command_socket = true
|
|
23
25
|
end
|
|
24
26
|
|
|
25
27
|
def writer
|
|
@@ -50,10 +52,40 @@ module Steep
|
|
|
50
52
|
)
|
|
51
53
|
master.typecheck_automatically = true
|
|
52
54
|
|
|
53
|
-
master
|
|
55
|
+
socket = start_command_socket(master)
|
|
56
|
+
|
|
57
|
+
begin
|
|
58
|
+
master.start()
|
|
59
|
+
ensure
|
|
60
|
+
socket&.stop
|
|
61
|
+
end
|
|
54
62
|
|
|
55
63
|
0
|
|
56
64
|
end
|
|
65
|
+
|
|
66
|
+
# Starts accepting `steep query`/`steep check` connections on the UNIX socket
|
|
67
|
+
#
|
|
68
|
+
# Returns `nil` when the command socket is disabled, is not supported on the platform,
|
|
69
|
+
# or is already served by another process.
|
|
70
|
+
#
|
|
71
|
+
def start_command_socket(master)
|
|
72
|
+
return nil unless command_socket
|
|
73
|
+
|
|
74
|
+
configuration = Daemon::Configuration.new(base_dir: project.base_dir.to_s)
|
|
75
|
+
socket = Server::CommandSocket.new(master: master, configuration: configuration)
|
|
76
|
+
|
|
77
|
+
if socket.start
|
|
78
|
+
stderr.puts "Steep command socket is ready: #{configuration.socket_path}"
|
|
79
|
+
socket
|
|
80
|
+
else
|
|
81
|
+
stderr.puts "Steep command socket is not available: #{configuration.socket_path}"
|
|
82
|
+
nil
|
|
83
|
+
end
|
|
84
|
+
rescue NotImplementedError, StandardError => error
|
|
85
|
+
Steep.logger.error { "Failed to start command socket: #{error.inspect}" }
|
|
86
|
+
stderr.puts "Failed to start Steep command socket: #{error.message}"
|
|
87
|
+
nil
|
|
88
|
+
end
|
|
57
89
|
end
|
|
58
90
|
end
|
|
59
91
|
end
|
data/lib/steep/drivers/query.rb
CHANGED
|
@@ -15,7 +15,7 @@ module Steep
|
|
|
15
15
|
# @rbs return: Integer
|
|
16
16
|
def run_hover(locations:)
|
|
17
17
|
unless Daemon.running?
|
|
18
|
-
stderr.puts "Error: Steep
|
|
18
|
+
stderr.puts "Error: Steep server is not running. Start it with `steep server start` or `steep langserver`."
|
|
19
19
|
return 1
|
|
20
20
|
end
|
|
21
21
|
|
|
@@ -51,7 +51,7 @@ module Steep
|
|
|
51
51
|
# @rbs return: Integer
|
|
52
52
|
def run_definition(names:)
|
|
53
53
|
unless Daemon.running?
|
|
54
|
-
stderr.puts "Error: Steep
|
|
54
|
+
stderr.puts "Error: Steep server is not running. Start it with `steep server start` or `steep langserver`."
|
|
55
55
|
return 1
|
|
56
56
|
end
|
|
57
57
|
|
|
@@ -72,6 +72,44 @@ module Steep
|
|
|
72
72
|
1
|
|
73
73
|
end
|
|
74
74
|
|
|
75
|
+
def run_diagnostics(paths:)
|
|
76
|
+
unless Daemon.running?
|
|
77
|
+
stderr.puts "Error: Steep server is not running. Start it with `steep server start` or `steep langserver`."
|
|
78
|
+
return 1
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
absolute_paths = [] #: Array[Pathname]
|
|
82
|
+
paths.each do |path|
|
|
83
|
+
pathname = Pathname(path)
|
|
84
|
+
pathname = Pathname.pwd + pathname unless pathname.absolute?
|
|
85
|
+
absolute_paths << pathname
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
request = {
|
|
89
|
+
id: SecureRandom.uuid,
|
|
90
|
+
method: Server::CustomMethods::Query__Diagnostics::METHOD,
|
|
91
|
+
params: { paths: absolute_paths.empty? ? nil : absolute_paths.map(&:to_s) }
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
result = send_request(request) #: Array[{ uri: String, diagnostics: Array[untyped]? }]?
|
|
95
|
+
|
|
96
|
+
(result || []).each do |entry|
|
|
97
|
+
path = PathHelper.to_pathname(entry[:uri]) || Pathname(entry[:uri])
|
|
98
|
+
begin
|
|
99
|
+
path = path.relative_path_from(Pathname.pwd)
|
|
100
|
+
rescue ArgumentError
|
|
101
|
+
# Keep the absolute path of files outside of the current directory
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
stdout.puts JSON.generate({ path: path.to_s, diagnostics: entry[:diagnostics] })
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
0
|
|
108
|
+
rescue Errno::ECONNREFUSED, Errno::ENOENT => e
|
|
109
|
+
stderr.puts "Error: Failed to connect to Steep server: #{e.message}"
|
|
110
|
+
1
|
|
111
|
+
end
|
|
112
|
+
|
|
75
113
|
private
|
|
76
114
|
|
|
77
115
|
def to_absolute_path(path)
|
|
@@ -65,7 +65,7 @@ module Steep
|
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
def shape(type, config)
|
|
68
|
-
Steep.logger.tagged "shape(#{type})" do
|
|
68
|
+
Steep.logger.tagged(-> { "shape(#{type})" }) do
|
|
69
69
|
if shape = raw_shape(type, config)
|
|
70
70
|
# Optimization that skips unnecessary substitution
|
|
71
71
|
if type.free_variables.include?(AST::Types::Self.instance)
|
|
@@ -82,7 +82,7 @@ module Steep
|
|
|
82
82
|
end
|
|
83
83
|
|
|
84
84
|
def fetch_cache(cache, key)
|
|
85
|
-
if cache.key?(key)
|
|
85
|
+
if cache.key?(key)
|
|
86
86
|
return cache.fetch(key)
|
|
87
87
|
end
|
|
88
88
|
|
|
@@ -277,7 +277,7 @@ module Steep
|
|
|
277
277
|
definition = factory.definition_builder.build_singleton(type_name)
|
|
278
278
|
|
|
279
279
|
definition.methods.each do |name, method|
|
|
280
|
-
Steep.logger.tagged "method = #{type_name}.#{name}" do
|
|
280
|
+
Steep.logger.tagged(-> { "method = #{type_name}.#{name}" }) do
|
|
281
281
|
overloads = method.defs.map do |type_def|
|
|
282
282
|
method_name = method_name_for(type_def, name)
|
|
283
283
|
method_type = factory.method_type(type_def.type)
|
|
@@ -309,7 +309,7 @@ module Steep
|
|
|
309
309
|
definition or raise
|
|
310
310
|
|
|
311
311
|
definition.methods.each do |name, method|
|
|
312
|
-
Steep.logger.tagged "method = #{type_name}##{name}" do
|
|
312
|
+
Steep.logger.tagged(-> { "method = #{type_name}##{name}" }) do
|
|
313
313
|
overloads = method.defs.map do |type_def|
|
|
314
314
|
method_name = method_name_for(type_def, name)
|
|
315
315
|
method_type = factory.method_type(type_def.type)
|
|
@@ -592,11 +592,31 @@ module Steep
|
|
|
592
592
|
)
|
|
593
593
|
end
|
|
594
594
|
|
|
595
|
+
to_ary_entry = Shape::Entry.new(
|
|
596
|
+
method_name: :to_ary,
|
|
597
|
+
private_method: false,
|
|
598
|
+
overloads: [
|
|
599
|
+
Shape::MethodOverload.new(
|
|
600
|
+
MethodType.new(
|
|
601
|
+
type_params: [],
|
|
602
|
+
type: Function.new(
|
|
603
|
+
params: Function::Params.empty,
|
|
604
|
+
return_type: tuple,
|
|
605
|
+
location: nil
|
|
606
|
+
),
|
|
607
|
+
block: nil
|
|
608
|
+
),
|
|
609
|
+
[]
|
|
610
|
+
)
|
|
611
|
+
]
|
|
612
|
+
)
|
|
613
|
+
|
|
595
614
|
shape.methods[:[]] = aref_entry
|
|
596
615
|
shape.methods[:[]=] = aref_update_entry
|
|
597
616
|
shape.methods[:fetch] = fetch_entry
|
|
598
617
|
shape.methods[:first] = first_entry
|
|
599
618
|
shape.methods[:last] = last_entry
|
|
619
|
+
shape.methods[:to_ary] = to_ary_entry
|
|
600
620
|
|
|
601
621
|
shape
|
|
602
622
|
end
|
|
@@ -56,6 +56,21 @@ module Steep
|
|
|
56
56
|
handle_job(job)
|
|
57
57
|
rescue => exn
|
|
58
58
|
Steep.log_error exn
|
|
59
|
+
|
|
60
|
+
# Jobs that carry an `id` answer a request. Reply with an error response, or the
|
|
61
|
+
# client would wait for a response that never arrives.
|
|
62
|
+
if job.respond_to?(:id) && (id = job.id)
|
|
63
|
+
writer.write(
|
|
64
|
+
{
|
|
65
|
+
id: id,
|
|
66
|
+
error: {
|
|
67
|
+
code: LSP::Constant::ErrorCodes::INTERNAL_ERROR,
|
|
68
|
+
message: "Unexpected error: #{exn.message} (#{exn.class})"
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
)
|
|
72
|
+
end
|
|
73
|
+
|
|
59
74
|
writer.write(
|
|
60
75
|
{
|
|
61
76
|
method: "window/showMessage",
|