Class: Mui::Lsp::JsonRpcIO

Inherits:
Object
  • Object
show all
Defined in:
lib/mui/lsp/json_rpc_io.rb

Overview

JSON-RPC 2.0 over stdio communication handler Handles LSP message framing with Content-Length headers

Constant Summary collapse

CONTENT_LENGTH_HEADER =
"Content-Length:"
HEADER_DELIMITER =
"\r\n\r\n"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(input:, output:) ⇒ JsonRpcIO



15
16
17
18
19
# File 'lib/mui/lsp/json_rpc_io.rb', line 15

def initialize(input:, output:)
  @input = input
  @output = output
  @mutex = Mutex.new
end

Instance Attribute Details

#inputObject (readonly)

Returns the value of attribute input.



13
14
15
# File 'lib/mui/lsp/json_rpc_io.rb', line 13

def input
  @input
end

#outputObject (readonly)

Returns the value of attribute output.



13
14
15
# File 'lib/mui/lsp/json_rpc_io.rb', line 13

def output
  @output
end

Class Method Details

.build_error_response(id:, code:, message:, data: nil) ⇒ Object



74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/mui/lsp/json_rpc_io.rb', line 74

def self.build_error_response(id:, code:, message:, data: nil)
  error = {
    code: code,
    message: message
  }
  error[:data] = data if data

  {
    jsonrpc: "2.0",
    id: id,
    error: error
  }
end

.build_notification(method:, params: nil) ⇒ Object



57
58
59
60
61
62
63
64
# File 'lib/mui/lsp/json_rpc_io.rb', line 57

def self.build_notification(method:, params: nil)
  message = {
    jsonrpc: "2.0",
    method: method
  }
  message[:params] = params if params
  message
end

.build_request(id:, method:, params: nil) ⇒ Object



47
48
49
50
51
52
53
54
55
# File 'lib/mui/lsp/json_rpc_io.rb', line 47

def self.build_request(id:, method:, params: nil)
  message = {
    jsonrpc: "2.0",
    id: id,
    method: method
  }
  message[:params] = params if params
  message
end

.build_response(id:, result:) ⇒ Object



66
67
68
69
70
71
72
# File 'lib/mui/lsp/json_rpc_io.rb', line 66

def self.build_response(id:, result:)
  {
    jsonrpc: "2.0",
    id: id,
    result: result
  }
end

.notification?(message) ⇒ Boolean



92
93
94
# File 'lib/mui/lsp/json_rpc_io.rb', line 92

def self.notification?(message)
  !message.key?("id") && message.key?("method")
end

.request?(message) ⇒ Boolean



88
89
90
# File 'lib/mui/lsp/json_rpc_io.rb', line 88

def self.request?(message)
  message.key?("id") && message.key?("method")
end

.response?(message) ⇒ Boolean



96
97
98
# File 'lib/mui/lsp/json_rpc_io.rb', line 96

def self.response?(message)
  message.key?("id") && !message.key?("method") && (message.key?("result") || message.key?("error"))
end

Instance Method Details

#read_messageObject



21
22
23
24
25
26
27
28
29
30
31
# File 'lib/mui/lsp/json_rpc_io.rb', line 21

def read_message
  content_length = read_headers
  return nil if content_length.nil?

  body = @input.read(content_length)
  return nil if body.nil? || body.empty?

  JSON.parse(body)
rescue JSON::ParserError => e
  raise Error, "Failed to parse JSON: #{e.message}"
end

#write_message(message) ⇒ Object



33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/mui/lsp/json_rpc_io.rb', line 33

def write_message(message)
  json = JSON.generate(message)
  content = "#{CONTENT_LENGTH_HEADER} #{json.bytesize}\r\n\r\n#{json}"

  @mutex.synchronize do
    @output.write(content)
    @output.flush
  end
  true
rescue IOError, Errno::EPIPE
  # Pipe is broken, server probably exited
  false
end