rider-server 0.1.0 → 0.1.1
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 +6 -0
- data/COPYING +20 -0
- data/README.md +6 -4
- data/lib/rider_server/inspect.rb +7 -11
- data/lib/rider_server/operations.rb +7 -7
- data/lib/rider_server/ops/completions.rb +66 -21
- data/lib/rider_server/ops/eval.rb +2 -2
- data/lib/rider_server/ops/lookup.rb +66 -45
- data/lib/rider_server/ops/ls_exceptions.rb +1 -1
- data/lib/rider_server/ops/set_namespace_variable.rb +1 -1
- data/lib/rider_server/server.rb +1 -1
- data/lib/rider_server/services/capture_exceptions.rb +18 -2
- data/lib/rider_server/session.rb +16 -4
- data/lib/rider_server/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: acb6833a29ab9facb82c72d8f2e012ab0dd7a44dbd1ad93dfe69f8d1bff2a765
|
4
|
+
data.tar.gz: 62834c0a615baa860e1e7650f14353180b874cf877833cc94b6f9804edd32efa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bec9b6906b7e47954bdf9a85fcb3a47ca89d86f63f68023b90d0c8ac83028f6aa7681ad0a4042934cd4a663a0f86f344d8ee11374816efe5616d5eaeaa2a8b75
|
7
|
+
data.tar.gz: a0d1b287bfeeaf68bbd82c9d72d7bb9405a9873286993e6171cd5f754c545c56cdcde1f186e8c9edb755a1e883a627ce6b33eeea2b21a047220ced97e3e973e5
|
data/CHANGELOG.md
CHANGED
data/COPYING
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2024 Russell Sim <rsl@simopolis.xyz>
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
“Software”), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -32,10 +32,12 @@ dependencies. Then, run `rake test` to run the tests. You can also run
|
|
32
32
|
experiment.
|
33
33
|
|
34
34
|
To install this gem onto your local machine, run `bundle exec rake
|
35
|
-
install`.
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
install`.
|
36
|
+
|
37
|
+
To release a new version run `rake bump:patch` and then run `bundle
|
38
|
+
exec rake release`, which will create a git tag for the version, push
|
39
|
+
git commits and the created tag, and push the `.gem` file to
|
40
|
+
[rubygems.org](https://rubygems.org).
|
39
41
|
|
40
42
|
## Contributing
|
41
43
|
|
data/lib/rider_server/inspect.rb
CHANGED
@@ -11,14 +11,13 @@ require "rider_server/utils"
|
|
11
11
|
|
12
12
|
module RiderServer
|
13
13
|
module Inspect
|
14
|
-
|
15
14
|
def self.safely_eval(string, file, line)
|
16
15
|
code = <<~HEREDOC
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
16
|
+
begin
|
17
|
+
#{string}
|
18
|
+
rescue StandardError => e
|
19
|
+
e
|
20
|
+
end
|
22
21
|
HEREDOC
|
23
22
|
eval(code, TOPLEVEL_BINDING, file, line) # rubocop:disable Security/Eval
|
24
23
|
end
|
@@ -34,11 +33,8 @@ module RiderServer
|
|
34
33
|
end
|
35
34
|
|
36
35
|
def self.ancestors(obj)
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
if obj.class.respond_to?(:ancestors)
|
41
|
-
obj.class.ancestors.map do |item|
|
36
|
+
if obj.respond_to?(:ancestors)
|
37
|
+
obj.ancestors.map do |item|
|
42
38
|
{
|
43
39
|
"name" => item.to_s,
|
44
40
|
"value" => Utils.rider_inspect(item),
|
@@ -104,14 +104,14 @@ module RiderServer
|
|
104
104
|
response.set("out", e.full_message)
|
105
105
|
response.status("eval-error", "done")
|
106
106
|
if session
|
107
|
-
|
108
|
-
response.set("rider/exception-id",
|
107
|
+
exception = session.push_exception(operation["id"], e)
|
108
|
+
response.set("rider/exception-id", exception["id"])
|
109
109
|
end
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
110
|
+
@sessions_catching_exceptions.each do |session_id|
|
111
|
+
session = @sessions[session_id]
|
112
|
+
next if session.nil?
|
113
|
+
exception = session.push_exception(operation["id"], e)
|
114
|
+
response.set("rider/exception-id", exception["id"])
|
115
115
|
end
|
116
116
|
send_response(response)
|
117
117
|
end
|
@@ -9,6 +9,7 @@ module RiderServer
|
|
9
9
|
|
10
10
|
argument :id, :string, "The request id", required: true
|
11
11
|
argument :prefix, :string, "The prefix to complete", required: true
|
12
|
+
argument :complete_fn, :string, "What completion function to use, top-level, module, method or singleton-method"
|
12
13
|
argument :ns, :string, "The namespace to search for completions"
|
13
14
|
|
14
15
|
def initialize(*args)
|
@@ -20,38 +21,40 @@ module RiderServer
|
|
20
21
|
response = Response.new(operation)
|
21
22
|
|
22
23
|
prefix = operation["prefix"]
|
23
|
-
log.info "prefix: #{prefix}"
|
24
24
|
ns = operation["ns"]
|
25
|
-
|
25
|
+
complete_fn = operation.fetch("complete-fn", "top-level")
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
27
|
+
if prefix.nil? || parse_string(prefix).nil?
|
28
|
+
response.set("completions", [])
|
29
|
+
else
|
30
|
+
ns_object = if ns.empty?
|
31
|
+
::Object
|
32
|
+
else
|
33
|
+
@workspace.lookup_module(ns)
|
34
|
+
end
|
33
35
|
|
36
|
+
# If the prefix isn't parseable, return an empty list
|
37
|
+
response.set("completions", lookup_module(prefix, klass: ns_object, completion_fn: complete_fn))
|
38
|
+
end
|
34
39
|
response.status("done")
|
35
40
|
response
|
36
|
-
rescue ScriptError, StandardError => e
|
37
|
-
log.error "Error in completions: #{e}"
|
38
|
-
log.error e.backtrace.join("\n")
|
39
|
-
raise e
|
40
41
|
end
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
def lookup_module(module_name, klass = ::Object)
|
43
|
+
def lookup_module(module_name, klass: ::Object, completion_fn: "top-level")
|
45
44
|
node = parse_string(module_name)
|
46
45
|
case node.type
|
47
46
|
when :const
|
48
47
|
ns = lookup_module_ast(node.children.first, klass)
|
49
48
|
prefix = node.children.last
|
50
|
-
all_constants(ns, prefix)
|
49
|
+
all_constants(ns, prefix)
|
51
50
|
when :send
|
52
51
|
ns = lookup_module_ast(node.children.first, klass)
|
53
52
|
prefix = node.children.last
|
54
|
-
|
53
|
+
if completion_fn == "method"
|
54
|
+
all_constants(ns, prefix) + encode_methods(class_instance_methods(ns, prefix) + class_singleton_methods(::Kernel, prefix))
|
55
|
+
else
|
56
|
+
all_constants(ns, prefix) + encode_methods(class_methods(ns, prefix) + class_singleton_methods(::Kernel, prefix))
|
57
|
+
end
|
55
58
|
else
|
56
59
|
[]
|
57
60
|
end
|
@@ -64,6 +67,8 @@ module RiderServer
|
|
64
67
|
end
|
65
68
|
|
66
69
|
def lookup_module_ast(node, klass = ::Object)
|
70
|
+
return klass if node.nil?
|
71
|
+
|
67
72
|
case node.type
|
68
73
|
when :cbase
|
69
74
|
::Object
|
@@ -78,17 +83,57 @@ module RiderServer
|
|
78
83
|
end
|
79
84
|
end
|
80
85
|
|
86
|
+
def parent_constant(ns_object)
|
87
|
+
ns_object_name = ns_object.to_s
|
88
|
+
parent_name, _ = ns_object_name.rpartition("::")
|
89
|
+
parent_name.empty? ? nil : ::Object.const_get(parent_name)
|
90
|
+
end
|
91
|
+
|
81
92
|
def all_constants(ns_object, prefix)
|
82
|
-
|
93
|
+
consts = []
|
94
|
+
ns_object.constants.grep(/^#{prefix}/).each do |constant|
|
95
|
+
consts << constant.to_s
|
96
|
+
end
|
97
|
+
|
98
|
+
# Search up the tree to find all the other constants
|
99
|
+
constant = ns_object
|
100
|
+
loop do
|
101
|
+
constant = parent_constant(constant)
|
102
|
+
break if constant.nil?
|
103
|
+
|
104
|
+
constant.constants.grep(/^#{prefix}/).each do |constant|
|
105
|
+
consts << constant.to_s
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
consts.map do |constant|
|
83
110
|
{
|
84
|
-
"candidate" => constant
|
111
|
+
"candidate" => constant,
|
85
112
|
"type" => "constant"
|
86
113
|
}
|
87
114
|
end
|
88
115
|
end
|
89
116
|
|
90
|
-
|
91
|
-
|
117
|
+
##
|
118
|
+
# Get all instance methods that match a +prefix+ for a given object +obj+
|
119
|
+
#
|
120
|
+
# This method should be called when in the context of an
|
121
|
+
# instance method, as all other instance methods will be
|
122
|
+
# acessable.
|
123
|
+
def class_instance_methods(obj, prefix)
|
124
|
+
Set.new(obj.instance_methods.grep(/^#{prefix}/))
|
125
|
+
end
|
126
|
+
|
127
|
+
def class_methods(obj, prefix)
|
128
|
+
Set.new(obj.methods.grep(/^#{prefix}/))
|
129
|
+
end
|
130
|
+
|
131
|
+
def class_singleton_methods(obj, prefix)
|
132
|
+
Set.new(obj.singleton_methods.grep(/^#{prefix}/))
|
133
|
+
end
|
134
|
+
|
135
|
+
def encode_methods(methods)
|
136
|
+
methods.map do |method|
|
92
137
|
{
|
93
138
|
"candidate" => method.to_s,
|
94
139
|
"type" => "method"
|
@@ -46,8 +46,8 @@ module RiderServer
|
|
46
46
|
response.set("ex", e.inspect)
|
47
47
|
response.set("ns", session.workspace.evaluate("inspect"))
|
48
48
|
response.status("eval-error", "done")
|
49
|
-
|
50
|
-
response.set("rider/exception-id",
|
49
|
+
exception = session.push_exception(operation["id"], e)
|
50
|
+
response.set("rider/exception-id", exception["id"])
|
51
51
|
send_response(response)
|
52
52
|
end
|
53
53
|
|
@@ -5,10 +5,11 @@ require "rider_server/inspect"
|
|
5
5
|
module RiderServer
|
6
6
|
module Ops
|
7
7
|
class Lookup < Operation
|
8
|
-
documentation "Get
|
8
|
+
documentation "Get info about a symbol."
|
9
9
|
|
10
10
|
argument :id, :string, "The request id", required: true
|
11
11
|
argument :sym, :string, "The symbol to lookup", required: true
|
12
|
+
argument :lookup_fn, :string, "What lookup function to use, top-level, module, method or singleton-method"
|
12
13
|
argument :ns, :string, "The namespace to search for completions"
|
13
14
|
|
14
15
|
def initialize(*args)
|
@@ -20,63 +21,83 @@ module RiderServer
|
|
20
21
|
response = Response.new(operation)
|
21
22
|
ns = operation["ns"]
|
22
23
|
sym = operation["sym"]
|
24
|
+
lookup_fn = operation.fetch("lookup-fn", "top-level")
|
23
25
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
method = sym.split(".").last
|
33
|
-
method_type = :class
|
34
|
-
method = method.to_sym
|
35
|
-
elsif sym.include?(".")
|
36
|
-
sym, method = sym.split(".")
|
37
|
-
method_type = :class
|
38
|
-
method = method.to_sym
|
39
|
-
end
|
26
|
+
if sym.nil? || parse_string(sym).nil?
|
27
|
+
response.set("info", {})
|
28
|
+
else
|
29
|
+
ns_object = if ns.empty?
|
30
|
+
::Object
|
31
|
+
else
|
32
|
+
@workspace.lookup_module(ns)
|
33
|
+
end
|
40
34
|
|
41
|
-
|
42
|
-
|
35
|
+
# If the prefix isn't parseable, return an empty list
|
36
|
+
response.set("info", lookup_module(sym, klass: ns_object, lookup_fn: lookup_fn))
|
43
37
|
end
|
44
|
-
|
38
|
+
response.status("done")
|
39
|
+
response
|
40
|
+
end
|
45
41
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
42
|
+
def lookup_module(module_name, klass: ::Object, lookup_fn: "top-level")
|
43
|
+
node = parse_string(module_name)
|
44
|
+
case node.type
|
45
|
+
when :const
|
46
|
+
ns = lookup_module_ast(node.children.first, klass)
|
47
|
+
name = node.children.last
|
48
|
+
encode_const(ns, name)
|
49
|
+
when :send
|
50
|
+
ns = lookup_module_ast(node.children.first, klass)
|
51
|
+
prefix = node.children.last
|
52
|
+
if lookup_fn == "method"
|
53
|
+
encode_method(ns.instance_method(prefix))
|
54
|
+
else
|
55
|
+
encode_method(ns.method(prefix))
|
56
|
+
end
|
56
57
|
else
|
57
|
-
|
58
|
+
[]
|
58
59
|
end
|
60
|
+
end
|
59
61
|
|
60
|
-
|
61
|
-
|
62
|
-
|
62
|
+
def parse_string(string)
|
63
|
+
buffer = Parser::Source::Buffer.new("(string)")
|
64
|
+
buffer.source = string
|
65
|
+
Parser::CurrentRuby.new.parse(buffer)
|
63
66
|
end
|
64
67
|
|
65
|
-
|
68
|
+
def lookup_module_ast(node, klass = ::Object)
|
69
|
+
return klass if node.nil?
|
66
70
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
+
case node.type
|
72
|
+
when :cbase
|
73
|
+
::Object
|
74
|
+
when :const
|
75
|
+
if node.children.first.nil?
|
76
|
+
klass.const_get(node.children.last)
|
77
|
+
else
|
78
|
+
lookup_module_ast(node.children.first, klass).const_get(node.children.last)
|
79
|
+
end
|
80
|
+
else
|
81
|
+
raise ModuleLookupError, "Unknown node type #{node.type}"
|
71
82
|
end
|
83
|
+
end
|
72
84
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
85
|
+
def encode_const(ns, const_name)
|
86
|
+
if ns.const_defined? const_name
|
87
|
+
{
|
88
|
+
"name" => "#{ns}::#{const_name}",
|
89
|
+
"source_location" => ns.const_source_location(const_name)
|
90
|
+
}
|
91
|
+
else
|
92
|
+
{}
|
77
93
|
end
|
78
|
-
|
79
|
-
|
94
|
+
end
|
95
|
+
|
96
|
+
def encode_method(thing)
|
97
|
+
{
|
98
|
+
"name" => thing.name.to_s,
|
99
|
+
"source_location" => thing.source_location
|
100
|
+
}
|
80
101
|
end
|
81
102
|
end
|
82
103
|
end
|
@@ -4,7 +4,7 @@ require "rider_server/response"
|
|
4
4
|
module RiderServer
|
5
5
|
module Ops
|
6
6
|
class LsExceptions < Operation
|
7
|
-
documentation "List all exceptions that
|
7
|
+
documentation "List all exceptions that exist in the sessions cache."
|
8
8
|
|
9
9
|
argument :id, :string, "The request id", required: true
|
10
10
|
|
@@ -13,7 +13,7 @@ module RiderServer
|
|
13
13
|
def handle(session, operation)
|
14
14
|
response = Response.new(operation)
|
15
15
|
name = operation["name"]
|
16
|
-
raise "Name must be a valid Ruby identifier" unless
|
16
|
+
raise "Name must be a valid Ruby identifier" unless /\A[a-zA-Z_]\w*\z/.match?(name)
|
17
17
|
location = operation["location"]
|
18
18
|
|
19
19
|
value = traverse_location(location, nil, session)
|
data/lib/rider_server/server.rb
CHANGED
@@ -28,11 +28,27 @@ module RiderServer
|
|
28
28
|
}
|
29
29
|
end
|
30
30
|
|
31
|
-
def self.
|
31
|
+
def self.create_exception_wrapper(exception, metadata)
|
32
|
+
id = SecureRandom.uuid
|
33
|
+
{
|
34
|
+
"id" => id,
|
35
|
+
"created_at" => DateTime.now,
|
36
|
+
"exception" => exception,
|
37
|
+
"metadata" => metadata
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.handle_exception(exception, metadata: {})
|
42
|
+
wrapped_ex = create_exception_wrapper(exception, metadata)
|
43
|
+
# Firstly this needs to generate wrapper for the exception
|
44
|
+
# This needs to use push exception
|
45
|
+
|
32
46
|
@sessions.each do |session, stream_id|
|
33
|
-
ex = session.
|
47
|
+
ex = session.push_anonymous_exception(wrapped_ex)
|
34
48
|
session.response_queue.push(create_response(stream_id, ex))
|
35
49
|
end
|
50
|
+
|
51
|
+
wrapped_ex
|
36
52
|
end
|
37
53
|
|
38
54
|
def initialize(session)
|
data/lib/rider_server/session.rb
CHANGED
@@ -93,15 +93,20 @@ module RiderServer
|
|
93
93
|
# Historical Exceptions
|
94
94
|
#
|
95
95
|
|
96
|
-
def
|
96
|
+
def wrap_exception(operation_id, exception, metadata = {})
|
97
97
|
id = SecureRandom.uuid
|
98
|
-
|
98
|
+
{
|
99
99
|
"id" => id,
|
100
100
|
"operation_id" => operation_id,
|
101
101
|
"created_at" => DateTime.now,
|
102
102
|
"exception" => exception,
|
103
103
|
"metadata" => metadata
|
104
104
|
}
|
105
|
+
end
|
106
|
+
|
107
|
+
def add_exception(operation_id, exception, metadata = {})
|
108
|
+
id = SecureRandom.uuid
|
109
|
+
@exceptions << wrap_exception(operation_id, exception, metadata)
|
105
110
|
id
|
106
111
|
end
|
107
112
|
|
@@ -113,7 +118,14 @@ module RiderServer
|
|
113
118
|
|
114
119
|
# A threadsafe way to add exceptions
|
115
120
|
def push_exception(operation_id, exception, metadata = {})
|
116
|
-
|
121
|
+
ex = wrap_exception(operation_id, exception, metadata)
|
122
|
+
@exception_queue.push(ex)
|
123
|
+
ex
|
124
|
+
end
|
125
|
+
|
126
|
+
def push_anonymous_exception(exception)
|
127
|
+
@exception_queue.push(exception)
|
128
|
+
exception
|
117
129
|
end
|
118
130
|
|
119
131
|
def start_exception_processing
|
@@ -121,7 +133,7 @@ module RiderServer
|
|
121
133
|
|
122
134
|
@exception_processing_thread = Thread.new do
|
123
135
|
loop do
|
124
|
-
|
136
|
+
@exceptions << @exception_queue.pop
|
125
137
|
end
|
126
138
|
end
|
127
139
|
end
|
data/lib/rider_server/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rider-server
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Russell Sim
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-07-
|
11
|
+
date: 2024-07-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bencode
|
@@ -50,6 +50,7 @@ files:
|
|
50
50
|
- ".ruby-version"
|
51
51
|
- ".standard.yml"
|
52
52
|
- CHANGELOG.md
|
53
|
+
- COPYING
|
53
54
|
- README.md
|
54
55
|
- Rakefile
|
55
56
|
- exe/rider-server
|