nrepl-lazuli 0.1.3 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3afa60bfeead6c887e8af4a6d6beb2e24e50b58984855794601d1c25cd0ba703
4
- data.tar.gz: 9a7001c799e5a0aa1d68899ed6c2e06698b2097f7d7518da515938aa9cb2ba95
3
+ metadata.gz: f4f4fa0597b301ec633b7a332a60a86ec773239fc9c199096249459c7567c0b1
4
+ data.tar.gz: ec2ce7297bd7351c1be0095af5e157b88c70a8f8ce434ea3e046cd3b97e8d1aa
5
5
  SHA512:
6
- metadata.gz: 9c60a0b98f239ee46b90400dd6a621d5ada13ef4da208c11749605fe528c1e4b1075b3e774aa6f487d8cee7b31e600a6ed410a46522764b04f638166a21ef548
7
- data.tar.gz: f34c1bc6932245fece695740be5f2211563161f7c3c4667748a0e152cb43dfaa78dd08a3dbbf57dfb2e363b6a1ad3ee44f9864eabbaba68f0e3a9b3939820900
6
+ metadata.gz: b813283650b6ef0a56d0e8a6372f5a5ffea33235322d62ddc1204cc0f696de4912be861752dac02f859ce4592f9c4c84e89c03b9050597c357f222bbe82dbf14
7
+ data.tar.gz: 5354de88865cded64e7aa9f22b1bebf43fae21d396bfe9cd212a7859d35eccb6a246b3ad273f4d08679fb485d56b75b383986ddb7c494c9a92869c5606d755bb
@@ -2,13 +2,19 @@ module NREPL
2
2
  class Connection
3
3
  @@debug_counter = 0
4
4
 
5
- def initialize(input, debug: false, out: input, watches: NREPL.class_variable_get(:@@watches))
5
+ def initialize(
6
+ input, debug: false, out: input,
7
+ watches: NREPL.class_variable_get(:@@watches), binding: nil,
8
+ auto_bindings: {}
9
+ )
6
10
  @debug = debug
7
11
  @in = input
8
12
  @out = out
9
13
  @pending_evals = {}
10
14
  @watches = watches
11
15
  @counter = 0
16
+ @binding = binding
17
+ @auto_bindings = auto_bindings
12
18
  end
13
19
 
14
20
  def treat_messages!
@@ -75,7 +81,15 @@ module NREPL
75
81
  'op' => msg['op']
76
82
  }))
77
83
  end
78
-
84
+ when 'watches_for_file'
85
+ msg['id'] ||= "eval_#{@counter += 1}"
86
+ file = msg['file']
87
+ rows_bindings = @auto_bindings[file] || {}
88
+ send_msg(response_for(msg, {
89
+ 'status' => ['done'],
90
+ 'rows' => rows_bindings.keys.sort,
91
+ 'op' => msg['op']
92
+ }))
79
93
  else
80
94
  send_msg(response_for(msg, {
81
95
  'op' => msg['op'],
@@ -135,6 +149,8 @@ module NREPL
135
149
  @pending_evals.fetch(msg['stop_id'], {})[:binding]
136
150
  elsif msg['watch_id']
137
151
  @watches.fetch(msg['watch_id'], {})[:binding]
152
+ else
153
+ find_row_based_binding(msg) || @binding
138
154
  end
139
155
  evaluate_code(code, msg['file'], msg['line'], original_bind)
140
156
  end
@@ -144,6 +160,17 @@ module NREPL
144
160
  end
145
161
  end
146
162
 
163
+ private def find_row_based_binding(msg)
164
+ file = msg['file']
165
+ row = msg['line']
166
+ return if !file || !row
167
+
168
+ rows_bindings = @auto_bindings[file]
169
+ return unless rows_bindings
170
+ found_row = row.downto(-1).find { |k| rows_bindings[k] }
171
+ rows_bindings[found_row]
172
+ end
173
+
147
174
  private def define_stop_function!(msg, method_name)
148
175
  out, inp = IO.pipe
149
176
  send_stopped = proc do |ctx_binding, original_msg, caller|
@@ -1,9 +1,12 @@
1
+ require "delegate"
2
+
1
3
  module NREPL
2
- class FakeStdout
4
+ class FakeStdout < SimpleDelegator
3
5
  def initialize(connections, io, kind)
4
6
  @connections = connections
5
7
  @io = io
6
8
  @kind = kind
9
+ super(io)
7
10
  end
8
11
 
9
12
  def <<(text)
@@ -21,33 +24,13 @@ module NREPL
21
24
  nil
22
25
  end
23
26
 
24
- def method_missing(method, *args)
25
- @io.send(method, *args)
26
- end
27
-
28
27
  def write(text)
29
- @io.write(text)
30
28
  @connections.each do |conn|
31
29
  conn.send_msg(
32
30
  @kind => text
33
31
  )
34
32
  end
35
- end
36
-
37
- def flush
38
- @io.flush
39
- end
40
-
41
- def close
42
- @io.close
43
- end
44
-
45
- def sync
46
- @io.sync
47
- end
48
-
49
- def sync=(val)
50
- @io.sync = val
33
+ @io.write(text)
51
34
  end
52
35
  end
53
36
  end
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # A Ruby port of ogion https://gitlab.com/technomancy/ogion &
4
+ # https://github.com/borkdude/nrepl-server/blob/master/src/borkdude/nrepl_server.clj
5
+
6
+ require 'bencode'
7
+ require 'socket'
8
+ require_relative 'connection'
9
+ require_relative 'fake_stdout'
10
+
11
+ module NREPL
12
+ class Server
13
+ attr_reader :debug, :port, :host
14
+ alias debug? debug
15
+
16
+ def self.start(**kwargs)
17
+ new(**kwargs).start
18
+ end
19
+
20
+ def self.bind!(binding, **kwargs)
21
+ new(**kwargs.merge(binding: binding)).start
22
+ end
23
+
24
+ def initialize(port: DEFAULT_PORT, host: DEFAULT_HOST, debug: false, binding: nil, pwd: Dir.pwd)
25
+ @port = port
26
+ @pwd = pwd
27
+ @host = host
28
+ @debug = debug
29
+ @connections = Set.new
30
+ @binding = binding
31
+ @auto_bindings = {}
32
+ NREPL.class_variable_set(:@@connections, @connections)
33
+ end
34
+
35
+ private def record_port
36
+ File.open(PORT_FILENAME, 'w+') do |f|
37
+ f.write(port)
38
+ end
39
+ end
40
+
41
+ def start
42
+ puts "nREPL server started on port #{port} on host #{host} - nrepl://#{host}:#{port}"
43
+ puts "Running in debug mode" if debug?
44
+ record_port
45
+
46
+ $stdout = FakeStdout.new(@connections, STDOUT, "out")
47
+ $stderr = FakeStdout.new(@connections, STDERR, "err")
48
+ auto_create_bindings!
49
+
50
+ Signal.trap("INT") { stop }
51
+ Signal.trap("TERM") { stop }
52
+
53
+ s = TCPServer.new(host, port)
54
+ loop do
55
+ Thread.start(s.accept) do |client|
56
+ connection = Connection.new(client, debug: debug?, binding: @binding, auto_bindings: @auto_bindings)
57
+ @connections << connection
58
+ connection.treat_messages!
59
+ @connections.delete(connection)
60
+ end
61
+ end
62
+ ensure
63
+ File.unlink(PORT_FILENAME)
64
+ end
65
+
66
+ def auto_create_bindings!
67
+ dir_regex = Regexp.new("^#{Regexp.escape(@pwd)}")
68
+ @call_trace = TracePoint.new(:call) do |tp|
69
+ @auto_bindings[tp.path] ||= {}
70
+ @auto_bindings[tp.path][tp.lineno-1] = tp.binding
71
+ if tp.path =~ dir_regex
72
+ # puts "Tracing #{tp.path}:#{tp.lineno}"
73
+ @connections.each do |connection|
74
+ connection.send_msg(
75
+ 'op' => 'hit_auto_watch',
76
+ 'file' => tp.path,
77
+ 'line' => tp.lineno-1,
78
+ 'status' => ['done']
79
+ )
80
+ end
81
+ end
82
+ end
83
+ @call_trace.enable
84
+ end
85
+
86
+ def stop
87
+ Thread.exit
88
+ exit(0)
89
+ end
90
+ end
91
+
92
+ # Sorry, no other way...
93
+ module ThreadPatch
94
+ def initialize(*args, &b)
95
+ @parent = Thread.current
96
+ super
97
+ end
98
+
99
+ def parent
100
+ @parent
101
+ end
102
+ end
103
+
104
+ Thread.prepend(ThreadPatch)
105
+
106
+ # Also...
107
+ module MethodLocationFixer
108
+ def __lazuli_source_location
109
+ @__lazuli_source_location || source_location
110
+ end
111
+ end
112
+
113
+ module DefinitionFixer
114
+ @@definitions = {}
115
+
116
+ def __lazuli_source_location(method)
117
+ final_loc = nil
118
+ loc = ancestors.each do |klass|
119
+ loc = (klass.instance_variable_get(:@__lazuli_methods) || {})[method]
120
+ if loc
121
+ final_loc = loc
122
+ break
123
+ end
124
+ end
125
+
126
+ if(final_loc && File.exist?(final_loc[0]))
127
+ final_loc
128
+ else
129
+ instance_method(method).source_location
130
+ end
131
+ end
132
+
133
+ def method_added(method_name)
134
+ return if method_name == :__lazuli_source_location
135
+ path = caller.reject { |x| x =~ /gems.*gems/ }[0]
136
+ if path
137
+ (file, row) = path.split(/:/)
138
+
139
+ known = instance_variable_get(:@__lazuli_methods)
140
+ if !known
141
+ known = {}
142
+ instance_variable_set(:@__lazuli_methods, known)
143
+ end
144
+ known[method_name] = [file, row.to_i]
145
+ end
146
+ end
147
+
148
+ Module.prepend(DefinitionFixer)
149
+ end
150
+ end
@@ -6,7 +6,7 @@ module NREPL
6
6
  DEFAULT_HOST = '127.0.0.1'
7
7
  PORT_FILENAME = '.nrepl-port'
8
8
 
9
- require_relative 'nrepl/server'
9
+ require_relative 'nrepl-lazuli/server'
10
10
  @@watches = {}
11
11
  @@connections = Set.new
12
12
 
@@ -25,5 +25,6 @@ module NREPL
25
25
  'status' => ['done']
26
26
  )
27
27
  end
28
+ nil
28
29
  end
29
30
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nrepl-lazuli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maurício Szabo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-03-22 00:00:00.000000000 Z
11
+ date: 2024-04-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bencode
@@ -31,11 +31,11 @@ executables: []
31
31
  extensions: []
32
32
  extra_rdoc_files: []
33
33
  files:
34
- - lib/nrepl.rb
35
- - lib/nrepl/connection.rb
36
- - lib/nrepl/fake_stdout.rb
37
- - lib/nrepl/server.rb
38
- homepage: https://rubygems.org/gems/nrepl-lazuli
34
+ - lib/nrepl-lazuli.rb
35
+ - lib/nrepl-lazuli/connection.rb
36
+ - lib/nrepl-lazuli/fake_stdout.rb
37
+ - lib/nrepl-lazuli/server.rb
38
+ homepage: https://gitlab.com/clj-editors/nrepl-lazuli
39
39
  licenses:
40
40
  - MIT
41
41
  metadata: {}
data/lib/nrepl/server.rb DELETED
@@ -1,77 +0,0 @@
1
- # frozen_string_literal: true
2
- #
3
- # A Ruby port of ogion https://gitlab.com/technomancy/ogion &
4
- # https://github.com/borkdude/nrepl-server/blob/master/src/borkdude/nrepl_server.clj
5
-
6
- require 'bencode'
7
- require 'socket'
8
- require_relative 'connection'
9
- require_relative 'fake_stdout'
10
-
11
- module NREPL
12
- class Server
13
- attr_reader :debug, :port, :host
14
- alias debug? debug
15
-
16
- def self.start(**kwargs)
17
- new(**kwargs).start
18
- end
19
-
20
- def initialize(port: DEFAULT_PORT, host: DEFAULT_HOST, debug: false)
21
- @port = port
22
- @host = host
23
- @debug = debug
24
- @connections = Set.new
25
- NREPL.class_variable_set(:@@connections, @connections)
26
- end
27
-
28
- private def record_port
29
- File.open(PORT_FILENAME, 'w+') do |f|
30
- f.write(port)
31
- end
32
- end
33
-
34
- def start
35
- puts "nREPL server started on port #{port} on host #{host} - nrepl://#{host}:#{port}"
36
- puts "Running in debug mode" if debug?
37
- record_port
38
-
39
- $stdout = FakeStdout.new(@connections, STDOUT, "out")
40
- $stderr = FakeStdout.new(@connections, STDERR, "err")
41
-
42
- Signal.trap("INT") { stop }
43
- Signal.trap("TERM") { stop }
44
-
45
- s = TCPServer.new(host, port)
46
- loop do
47
- Thread.start(s.accept) do |client|
48
- connection = Connection.new(client, debug: debug?)
49
- @connections << connection
50
- connection.treat_messages!
51
- @connections.delete(connection)
52
- end
53
- end
54
- ensure
55
- File.unlink(PORT_FILENAME)
56
- end
57
-
58
- def stop
59
- Thread.exit
60
- exit(0)
61
- end
62
- end
63
- end
64
-
65
- # Sorry, no other way...
66
- module ThreadPatch
67
- def initialize(*args, &b)
68
- @parent = Thread.current
69
- super
70
- end
71
-
72
- def parent
73
- @parent
74
- end
75
- end
76
-
77
- Thread.prepend(ThreadPatch)