lsp_router 0.1.1 → 0.1.4

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: c3ba53e8db9e41cea66c0d4f935517fe4f3e4e8e24a6173794e53ea409556847
4
- data.tar.gz: 984ea810f99d29a70efbb798b76c5d9f161b5bb5433ab0b96c52ed015529699c
3
+ metadata.gz: a4434480350b472e4784e0bc3dcd003f5863eeb5ee25accbcc5491d07ecdac39
4
+ data.tar.gz: ba46303f99aa22018ade578cf1534ccfb7149b356b43ca262ae65c5cb729eb64
5
5
  SHA512:
6
- metadata.gz: 40903c06994c73209c64535f12b417c913e59db4a7b856eae9504aac1e86102a273656e6f3a4148b3fa54e8c862855cd846e5e29d00f457b6a8e691b727ee919
7
- data.tar.gz: bde44dd17b4288879bf96dee727320241ebf143d13e4e5ee8fadbf562223db6a0c5214c584847369a6ff97f20b2048192dc2faaea076fbfc7f213b68b479818c
6
+ metadata.gz: 4e5716f9fab94ec450991faf87af92d81544341df78a795c9506a94b7feee39add469211144762b7514f5d46b76128e4c68b21d8ef12f300dbae9c28f3bdd7e4
7
+ data.tar.gz: 7795648666367d4bada69bfa336c7cdbcf41f3f4039f17e819c0c79a61acbfbd2a3381c44f1b2e222f889cb9df81b32e61bf83b0e34fbfb51862b8009798c069
data/.rubocop.yml CHANGED
@@ -185,5 +185,3 @@ Style/VariableInterpolation:
185
185
 
186
186
  Style/WordArray:
187
187
  Enabled: false
188
-
189
-
data/README.md CHANGED
@@ -17,7 +17,7 @@ logfile '/tmp/lsp_router'
17
17
  loglevel :info
18
18
 
19
19
  server :rubocop do
20
- command 'rubocop-lsp'
20
+ command 'rubocop --lsp'
21
21
  mode :stdio
22
22
  end
23
23
 
@@ -27,7 +27,7 @@ server :solargraph do
27
27
  end
28
28
  ```
29
29
 
30
- この例では、`rubocop-lsp` と `solargraph stdio` を起動して、クライアントからの処理を振り分ける。
30
+ この例では、`rubocop --lsp` と `solargraph stdio` を起動して、クライアントからの処理を振り分ける。
31
31
  最初に各サーバーの capabilities を確認して、各サーバーにどの機能があるかを確認し、クライアントからの REQUEST は対応しているサーバーに渡す。複数のサーバーが同じ機能を持っていれば上に書いたサーバーが優先される。NOTIFICATION は全サーバーに渡す。
32
32
 
33
33
  ## Example
@@ -37,3 +37,7 @@ Emacs の Eglot の場合はこんな感じに設定するといいっぽい。
37
37
  ```
38
38
  (add-to-list 'eglot-server-programs '((ruby-mode ruby-ts-mode) . ("lsp_router" "--error=lsp_router.err" "lsp_router.conf")))
39
39
  ```
40
+
41
+ ## License
42
+
43
+ GPLv3
@@ -16,21 +16,26 @@ class LspRouter
16
16
  @command = server.attr[:command]
17
17
  @stdin, @stdout, @stderr = Open3.popen3(@command)
18
18
  @capabilities = {}
19
+ @terminated = false
19
20
  end
20
21
 
21
22
  # @param req [Hash]
22
23
  def init(req)
23
24
  write(req)
24
- data = read
25
- capa = data.dig('result', 'capabilities')
26
- capa.keys.grep(/Provider/).each do |key|
27
- @capabilities[key.sub(/Provider\z/, '')] = true
25
+ while (data = read)
26
+ capa = data.dig('result', 'capabilities')
27
+ next unless capa
28
+ capa.keys.grep(/Provider/).each do |key|
29
+ @capabilities[key.sub(/Provider\z/, '')] = true
30
+ end
31
+ break
28
32
  end
29
33
  data
30
34
  end
31
35
 
32
36
  # @param data [Hash]
33
37
  def write(data)
38
+ return if @terminated
34
39
  log("#{name}<", data)
35
40
  json = data.to_json
36
41
  @stdin.puts "Content-Length: #{json.bytesize}\r\n\r\n"
@@ -40,8 +45,12 @@ class LspRouter
40
45
 
41
46
  # @return [Hash]
42
47
  def read
48
+ return nil if @terminated
43
49
  header = @stdout.gets("\r\n\r\n")
44
- return unless header
50
+ unless header
51
+ @terminated = true
52
+ return nil
53
+ end
45
54
  fields = header.lines.map do |line|
46
55
  n, v = line.chomp.split(/: */, 2)
47
56
  [n.downcase, v] if n
@@ -1,3 +1,3 @@
1
1
  class LspRouter
2
- VERSION = '0.1.1'
2
+ VERSION = '0.1.4'
3
3
  end
data/lib/lsp_router.rb CHANGED
@@ -42,13 +42,21 @@ class LspRouter
42
42
  end
43
43
 
44
44
  def loop
45
- req = @client.read
46
- servers = @config.servers.map{LspRouter::ServerSide.new(_1, logger: @logger)}
47
- primary = servers.first
45
+ @servers = @config.servers.map{LspRouter::ServerSide.new(_1, logger: @logger)}
46
+ @primary = @servers.first
47
+ @server_map = @servers.map.to_h{[_1.name.to_s, _1]}
48
+ @capa_server = {}
49
+
50
+ initial_packet
51
+ threads = server_loop
52
+ threads.push client_loop
53
+ threads.each(&:join)
54
+ end
48
55
 
56
+ def initial_packet
57
+ req = @client.read
49
58
  res = nil
50
- capa_server = {}
51
- servers.each do |server|
59
+ @servers.each do |server|
52
60
  data = server.init(req)
53
61
  if res
54
62
  res['result']['capabilities'].update(data.dig('result', 'capabilities')){|_, v, _| v}
@@ -56,40 +64,55 @@ class LspRouter
56
64
  res = data
57
65
  end
58
66
  server.capabilities.each_key do |key|
59
- capa_server[key] ||= server
67
+ @capa_server[key] ||= server
60
68
  end
61
69
  end
62
70
  @client.write(res)
71
+ end
63
72
 
64
- thr = Thread.new do
73
+ def client_loop
74
+ Thread.new do
65
75
  Thread.abort_on_exception = true
66
76
  while true
67
77
  data = @client.read
68
78
  break unless data
69
- if data['id']
70
- # request
79
+ if data['method'] == 'shutdown' || data['method'] == 'exit'
80
+ @servers.each{_1.write(data)}
81
+ break if data['method'] == 'exit'
82
+ next
83
+ end
84
+ if data['id'] # request or response
71
85
  method = data['method']&.split('/')&.last
72
- server = capa_server[method] || primary
73
- server.write(data)
74
- else
75
- # notification
76
- servers.each do |server|
77
- server.write(data)
86
+ if data['method'] # request
87
+ server = @capa_server[method] || @primary
88
+ else # response
89
+ server_name, id = JSON.parse(data['id'])
90
+ data['id'] = id
91
+ server = @server_map[server_name]
78
92
  end
93
+ server.write(data)
94
+ else # notification
95
+ @servers.each{_1.write(data)}
79
96
  end
80
97
  end
98
+ @logger.info "client: end"
81
99
  end
100
+ end
82
101
 
83
- servers.each do |server|
102
+ def server_loop
103
+ @servers.map do |server|
84
104
  Thread.new do
85
105
  Thread.abort_on_exception = true
86
106
  while true
87
107
  data = server.read
88
108
  break unless data
109
+ if data['id'] && data['method'] # request
110
+ data['id'] = [server.name, data['id']].to_json
111
+ end
89
112
  @client.write(data)
90
113
  end
114
+ @logger.info "server: [#{server.name}] end"
91
115
  end
92
116
  end
93
- thr.join
94
117
  end
95
118
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lsp_router
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - TOMITA Masahiro
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2023-12-20 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies: []
13
12
  description: routing multiple LSP server by capability
14
13
  email:
@@ -38,7 +37,6 @@ metadata:
38
37
  homepage_uri: https://gitlab.com/tmtms/lsp_router
39
38
  source_code_uri: https://gitlab.com/tmtms/lsp_router
40
39
  rubygems_mfa_required: 'true'
41
- post_install_message:
42
40
  rdoc_options: []
43
41
  require_paths:
44
42
  - lib
@@ -53,8 +51,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
53
51
  - !ruby/object:Gem::Version
54
52
  version: '0'
55
53
  requirements: []
56
- rubygems_version: 3.5.0.dev
57
- signing_key:
54
+ rubygems_version: 3.7.0.dev
58
55
  specification_version: 4
59
56
  summary: LSP router
60
57
  test_files: []