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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8c38f3cd330d07e579fff5971c656a12c4ee9f9a1488aba33d8183dd80b1236c
4
- data.tar.gz: a63be29edddccc449e4a5bbdd9f80a05e2fb2fa0b3ca0b271ee50830da521118
3
+ metadata.gz: e7d68153dc3d474b045d5856d097c51670cfeb3ae688396a45c5cd16d117232a
4
+ data.tar.gz: 5e65794b9839a3f7d9c0aa341f3675c58e1a25290afa0f57f532cb1cb23a8be2
5
5
  SHA512:
6
- metadata.gz: 2d75413ea25c513b6107daacd4f4128649c7696fc170f8536d8f636a166ce5fcb9ba675a4c218de9b9ec906f488c7cc9dfbdd48afbce0e828677d08c0bc96283
7
- data.tar.gz: a3bb98a1bc7d9ba46d9bbc0cd1ea3b30dfa186da9444a80acf03015c427430962d4bf3f14dfc0d695b7050fe8caf632b14c1bac0a92edbe65ee9fd0f04a803c5
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, debug: false, out: 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'],
@@ -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! if @tracing
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
- debug: debug?,
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
- @call_trace = TracePoint.new(:class, :call) do |tp|
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
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ require 'set'
2
3
 
3
4
  module NREPL
4
5
  VERSION = '0.1.0'
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.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: 2024-11-13 00:00:00.000000000 Z
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.5.11
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: []