rider-server 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|