nrepl-lazuli 0.4.0 → 0.6.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/lib/nrepl-lazuli/bencode.rb +96 -0
- data/lib/nrepl-lazuli/client.rb +66 -0
- data/lib/nrepl-lazuli/connection.rb +9 -1
- data/lib/nrepl-lazuli/server.rb +32 -6
- data/lib/nrepl-lazuli.rb +1 -0
- metadata +5 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e7d68153dc3d474b045d5856d097c51670cfeb3ae688396a45c5cd16d117232a
|
4
|
+
data.tar.gz: 5e65794b9839a3f7d9c0aa341f3675c58e1a25290afa0f57f532cb1cb23a8be2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 14c80200837368c174425e48735927e8c4e0be8214bbd5c1171e1338f19ac3b225b02a0631c9a269f19bc5846d7eb540944a96edf75ffd922cf8938923803f4a
|
7
|
+
data.tar.gz: e66a6400f737902c281c0c2c09c0d584ebbc5bd47a8d1262fd3b46db6afdbd32a57d1a5acfc220baa37bdf2fa9c02425d6f4f76acff4f16ecc7fca85bc5e910a
|
@@ -0,0 +1,96 @@
|
|
1
|
+
class BEncode
|
2
|
+
def self.encode(data)
|
3
|
+
case data
|
4
|
+
when Integer
|
5
|
+
"i#{data}e"
|
6
|
+
when String
|
7
|
+
"#{data.bytesize}:#{data}"
|
8
|
+
when Array
|
9
|
+
"l#{data.map { |e| encode(e) }.join}e"
|
10
|
+
when Hash
|
11
|
+
"d#{data.map { |k, v| encode(k) + encode(v) }.join}e"
|
12
|
+
else
|
13
|
+
raise ArgumentError, "Cannot BEncode type: #{data.class}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(stream)
|
18
|
+
@stream =
|
19
|
+
if stream.kind_of?(IO) || stream.kind_of?(StringIO)
|
20
|
+
stream
|
21
|
+
elsif stream.respond_to? :string
|
22
|
+
StringIO.new stream.string
|
23
|
+
elsif stream.respond_to? :to_s
|
24
|
+
StringIO.new stream.to_s
|
25
|
+
end
|
26
|
+
@encoding = @stream.external_encoding || Encoding::default_external
|
27
|
+
end
|
28
|
+
|
29
|
+
def parse!
|
30
|
+
case peek
|
31
|
+
when ?i then parse_integer!
|
32
|
+
when ?l then parse_list!
|
33
|
+
when ?d then parse_dict!
|
34
|
+
when ?0 .. ?9 then parse_string!
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def eos?
|
39
|
+
@stream.eof?
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def parse_integer!
|
45
|
+
@stream.getc
|
46
|
+
num = @stream.gets("e") or raise ArgumentError
|
47
|
+
num.chop.to_i
|
48
|
+
end
|
49
|
+
|
50
|
+
def parse_list!
|
51
|
+
@stream.getc
|
52
|
+
ary = []
|
53
|
+
ary.push(parse!) until peek == ?e
|
54
|
+
@stream.getc
|
55
|
+
ary
|
56
|
+
end
|
57
|
+
|
58
|
+
def parse_dict!
|
59
|
+
@stream.getc
|
60
|
+
hsh = {}
|
61
|
+
until peek == ?e
|
62
|
+
key = parse!
|
63
|
+
|
64
|
+
unless key.is_a? String or key.is_a? Integer
|
65
|
+
raise ArgumentError, "key must be a string or number"
|
66
|
+
end
|
67
|
+
|
68
|
+
val = parse!
|
69
|
+
|
70
|
+
hsh.store(key.to_s, val)
|
71
|
+
end
|
72
|
+
@stream.getc
|
73
|
+
hsh
|
74
|
+
end
|
75
|
+
|
76
|
+
def parse_string!
|
77
|
+
num = @stream.gets(":") or
|
78
|
+
raise ArgumentError, "invalid string length (no colon)"
|
79
|
+
|
80
|
+
begin
|
81
|
+
length = num.chop.to_i
|
82
|
+
return "" if length == 0 # Workaround for Rubinius bug
|
83
|
+
str = @stream.read(length).force_encoding(@encoding)
|
84
|
+
rescue => e
|
85
|
+
raise ArgumentError, "invalid string length #{e}"
|
86
|
+
end
|
87
|
+
|
88
|
+
str
|
89
|
+
end
|
90
|
+
|
91
|
+
def peek
|
92
|
+
c = @stream.getc
|
93
|
+
@stream.ungetc(c)
|
94
|
+
c
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'bencode'
|
4
|
+
require 'timeout'
|
5
|
+
|
6
|
+
module NREPL
|
7
|
+
class Client
|
8
|
+
attr_reader :host, :port
|
9
|
+
|
10
|
+
def initialize(port: DEFAULT_PORT, host: DEFAULT_HOST)
|
11
|
+
@port = port
|
12
|
+
@host = host
|
13
|
+
@socket = TCPSocket.new(@host, @port)
|
14
|
+
@bencode = BEncode.new(@socket)
|
15
|
+
@last_id = 0
|
16
|
+
end
|
17
|
+
|
18
|
+
def stop
|
19
|
+
unless closed?
|
20
|
+
@socket.close
|
21
|
+
@socket = nil
|
22
|
+
@bencode = nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def rpc(msg)
|
27
|
+
id = msg["id"] || msg[:id]
|
28
|
+
if(!id)
|
29
|
+
@last_id += 1
|
30
|
+
id = "autogen_#@last_id"
|
31
|
+
msg = msg.merge('id' => id)
|
32
|
+
end
|
33
|
+
|
34
|
+
write(msg)
|
35
|
+
Timeout.timeout(10) do
|
36
|
+
loop do
|
37
|
+
ret = read
|
38
|
+
if(ret["id"] == id)
|
39
|
+
break ret
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def write(msg)
|
46
|
+
@socket.write(BEncode.encode(msg))
|
47
|
+
@socket.flush
|
48
|
+
end
|
49
|
+
|
50
|
+
def read
|
51
|
+
@bencode.parse!
|
52
|
+
end
|
53
|
+
|
54
|
+
def register_session
|
55
|
+
write('op' => 'clone')
|
56
|
+
msg = read!
|
57
|
+
|
58
|
+
raise ArgumentError, "failed to create session" unless msg['new_session']
|
59
|
+
msg['new_session']
|
60
|
+
end
|
61
|
+
|
62
|
+
def closed?
|
63
|
+
@socket.nil?
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -3,12 +3,16 @@ module NREPL
|
|
3
3
|
@@debug_counter = 0
|
4
4
|
|
5
5
|
def initialize(
|
6
|
-
input,
|
6
|
+
input,
|
7
|
+
server:,
|
8
|
+
debug: false,
|
9
|
+
out: input,
|
7
10
|
binding: nil,
|
8
11
|
bindings: {},
|
9
12
|
bindings_by_id: {}
|
10
13
|
)
|
11
14
|
@debug = debug
|
15
|
+
@server = server
|
12
16
|
@in = input
|
13
17
|
@out = out
|
14
18
|
@pending_evals = {}
|
@@ -135,6 +139,10 @@ module NREPL
|
|
135
139
|
'rows' => rows_bindings.keys.sort,
|
136
140
|
'op' => msg['op']
|
137
141
|
}))
|
142
|
+
when 'set_trace'
|
143
|
+
disable = msg['trace'] == 0
|
144
|
+
disable ? @server.call_trace.disable : @server.call_trace.enable
|
145
|
+
send_msg(response_for(msg, { 'op' => msg['op'], 'status' => ['done'] }))
|
138
146
|
else
|
139
147
|
send_msg(response_for(msg, {
|
140
148
|
'op' => msg['op'],
|
data/lib/nrepl-lazuli/server.rb
CHANGED
@@ -10,7 +10,7 @@ require_relative 'fake_stdout'
|
|
10
10
|
|
11
11
|
module NREPL
|
12
12
|
class Server
|
13
|
-
attr_reader :debug, :port, :host
|
13
|
+
attr_reader :debug, :port, :host, :call_trace
|
14
14
|
alias debug? debug
|
15
15
|
|
16
16
|
def self.spawn(args = {})
|
@@ -35,7 +35,8 @@ module NREPL
|
|
35
35
|
debug: false,
|
36
36
|
binding: nil,
|
37
37
|
pwd: Dir.pwd,
|
38
|
-
tracing: true
|
38
|
+
tracing: true,
|
39
|
+
loader: nil
|
39
40
|
)
|
40
41
|
@port = port
|
41
42
|
@pwd = pwd
|
@@ -56,6 +57,7 @@ module NREPL
|
|
56
57
|
}
|
57
58
|
}
|
58
59
|
@tracing = tracing
|
60
|
+
@loader = loader
|
59
61
|
Thread.current[:nrepl_server] = self
|
60
62
|
NREPL.class_variable_set(:@@connections, @connections)
|
61
63
|
NREPL.class_variable_set(:@@bindings, @bindings)
|
@@ -76,7 +78,7 @@ module NREPL
|
|
76
78
|
@old_out, @old_err = $stdout, $stderr
|
77
79
|
$stdout = FakeStdout.new(@connections, STDOUT, "out")
|
78
80
|
$stderr = FakeStdout.new(@connections, STDERR, "err")
|
79
|
-
auto_create_bindings!
|
81
|
+
auto_create_bindings!
|
80
82
|
|
81
83
|
Signal.trap("INT") { stop }
|
82
84
|
Signal.trap("TERM") { stop }
|
@@ -87,7 +89,8 @@ module NREPL
|
|
87
89
|
Thread.start(@socket.accept) do |client|
|
88
90
|
connection = Connection.new(
|
89
91
|
client,
|
90
|
-
|
92
|
+
server: self,
|
93
|
+
debug: @debug,
|
91
94
|
binding: @binding,
|
92
95
|
bindings_by_id: @bindings_by_id,
|
93
96
|
bindings: @bindings
|
@@ -105,7 +108,7 @@ module NREPL
|
|
105
108
|
|
106
109
|
def auto_create_bindings!
|
107
110
|
dir_regex = Regexp.new("^#{Regexp.escape(@pwd)}")
|
108
|
-
|
111
|
+
trace_proc = proc do |tp|
|
109
112
|
path = tp.path
|
110
113
|
next if tp.path =~ /^(\<|.eval)/
|
111
114
|
path = File.join(@pwd, path) if File.dirname(path) == '.'
|
@@ -115,6 +118,13 @@ module NREPL
|
|
115
118
|
@bindings[path] ||= {}
|
116
119
|
@bindings[path][tp.lineno-1] ||= {}
|
117
120
|
@bindings[path][tp.lineno-1][id] = b
|
121
|
+
path
|
122
|
+
end
|
123
|
+
@class_trace = TracePoint.new(:class, &trace_proc)
|
124
|
+
@class_trace.enable
|
125
|
+
|
126
|
+
@call_trace = TracePoint.new(:call) do |tp|
|
127
|
+
path = trace_proc.call(tp)
|
118
128
|
if path =~ dir_regex
|
119
129
|
@connections.each do |connection|
|
120
130
|
connection.send_msg(
|
@@ -126,7 +136,23 @@ module NREPL
|
|
126
136
|
end
|
127
137
|
end
|
128
138
|
end
|
129
|
-
@call_trace.enable
|
139
|
+
@call_trace.enable if @tracing
|
140
|
+
|
141
|
+
if @loader
|
142
|
+
need_to_pause = true
|
143
|
+
original_trace = nil
|
144
|
+
@loader.on_load do
|
145
|
+
next unless need_to_pause
|
146
|
+
need_to_pause = false
|
147
|
+
original_trace = call_trace.enabled?
|
148
|
+
@call_trace.disable
|
149
|
+
Thread.new do
|
150
|
+
sleep 5
|
151
|
+
@call_trace.enable if original_trace
|
152
|
+
need_to_pause = true
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
130
156
|
|
131
157
|
@ex_trace = TracePoint.new(:raise) do |tp|
|
132
158
|
e = tp.raised_exception
|
data/lib/nrepl-lazuli.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nrepl-lazuli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Maurício Szabo
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-05-06 00:00:00.000000000 Z
|
12
11
|
dependencies: []
|
13
12
|
description: A Ruby nREPL server, made to be used with Lazuli plug-in (but can be
|
14
13
|
used with any nREPL client too)
|
@@ -18,6 +17,8 @@ extensions: []
|
|
18
17
|
extra_rdoc_files: []
|
19
18
|
files:
|
20
19
|
- lib/nrepl-lazuli.rb
|
20
|
+
- lib/nrepl-lazuli/bencode.rb
|
21
|
+
- lib/nrepl-lazuli/client.rb
|
21
22
|
- lib/nrepl-lazuli/connection.rb
|
22
23
|
- lib/nrepl-lazuli/fake_stdout.rb
|
23
24
|
- lib/nrepl-lazuli/server.rb
|
@@ -26,7 +27,6 @@ licenses:
|
|
26
27
|
- MIT
|
27
28
|
metadata:
|
28
29
|
source_code_uri: https://gitlab.com/clj-editors/nrepl-lazuli
|
29
|
-
post_install_message:
|
30
30
|
rdoc_options: []
|
31
31
|
require_paths:
|
32
32
|
- lib
|
@@ -41,8 +41,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
41
41
|
- !ruby/object:Gem::Version
|
42
42
|
version: '0'
|
43
43
|
requirements: []
|
44
|
-
rubygems_version: 3.
|
45
|
-
signing_key:
|
44
|
+
rubygems_version: 3.6.2
|
46
45
|
specification_version: 4
|
47
46
|
summary: A Ruby nREPL server
|
48
47
|
test_files: []
|