Class: Ibex::LSP::Server
- Inherits:
-
Object
- Object
- Ibex::LSP::Server
- Includes:
- RequestHandlers
- Defined in:
- lib/ibex/lsp/server.rb,
sig/ibex/lsp/server.rbs
Overview
Coordinates JSON-RPC lifecycle, request responses, and protocol-safe logging.
Constant Summary collapse
- REQUEST_METHODS =
%w[ initialize shutdown textDocument/definition textDocument/references textDocument/prepareRename textDocument/rename textDocument/hover ].freeze
- NOTIFICATION_METHODS =
%w[ initialized exit textDocument/didOpen textDocument/didChange textDocument/didSave textDocument/didClose $/cancelRequest ].freeze
Constants included from RequestHandlers
Instance Method Summary collapse
-
#initialize(stdin:, stdout:, stderr:) ⇒ Server
constructor
A new instance of Server.
- #log(message) ⇒ void
- #notification_envelope?(message) ⇒ Boolean
- #process_message(message) ⇒ void
- #read_message ⇒ Hash[String, untyped]?
- #run ⇒ Integer
- #safe_request_id(message) ⇒ String, ...
- #send_error(request_id, error) ⇒ void
- #send_result(request_id, result) ⇒ void
- #valid_request_id?(value) ⇒ Boolean
- #validate_envelope(message) ⇒ String, ...
- #validate_lifecycle!(method) ⇒ void
- #validate_message_kind!(method, request) ⇒ void
Methods included from RequestHandlers
Methods included from RequestSupport
#hash_member, #integer_member, #params_hash, #publish, #require_running!, #require_state!, #stale_publication?, #store, #string_member, #workspace
Methods included from NavigationHandlers
#definition, #hover, #prepare_rename, #references, #rename, #with_index
Methods included from DocumentHandlers
#did_change, #did_close, #did_open, #did_save
Methods included from InitializationHandlers
#capabilities, #exit_notification, #initialization_roots, #initialize_workspace, #initialized_notification, #shutdown_request
Constructor Details
#initialize(stdin:, stdout:, stderr:) ⇒ Server
Returns a new instance of Server.
19 20 21 22 23 24 25 |
# File 'lib/ibex/lsp/server.rb', line 19 def initialize(stdin:, stdout:, stderr:) @transport = Transport.new(stdin, stdout) @stderr = stderr @state = :uninitialized @exit_requested = false @exit_status = nil #: Integer? end |
Instance Method Details
#log(message) ⇒ void
This method returns an undefined value.
141 142 143 |
# File 'lib/ibex/lsp/server.rb', line 141 def log() @stderr.puts() end |
#notification_envelope?(message) ⇒ Boolean
76 77 78 |
# File 'lib/ibex/lsp/server.rb', line 76 def notification_envelope?() !.key?("id") && ["jsonrpc"] == "2.0" && ["method"].is_a?(String) end |
#process_message(message) ⇒ void
This method returns an undefined value.
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/ibex/lsp/server.rb', line 51 def () request_id = safe_request_id() notification = notification_envelope?() request_id = validate_envelope() method = .fetch("method") (method, .key?("id")) return if request_id.nil? && method.start_with?("$/") validate_lifecycle!(method) result = dispatch(method, ["params"]) send_result(request_id, result) if request_id rescue ProtocolError => e notification ? log(e.) : send_error(request_id, e) rescue StandardError => e error = ProtocolError.new("internal error: #{e.}", code: -32_603) notification ? log(error.) : send_error(request_id, error) end |
#read_message ⇒ Hash[String, untyped]?
41 42 43 44 45 46 47 48 |
# File 'lib/ibex/lsp/server.rb', line 41 def @transport. rescue ProtocolError => e send_error(nil, e) @exit_requested = true if e.fatal retry unless e.fatal nil end |
#run ⇒ Integer
28 29 30 31 32 33 34 35 36 |
# File 'lib/ibex/lsp/server.rb', line 28 def run until @exit_requested = break unless () end @exit_status || 1 end |
#safe_request_id(message) ⇒ String, ...
70 71 72 73 |
# File 'lib/ibex/lsp/server.rb', line 70 def safe_request_id() value = ["id"] value if valid_request_id?(value) end |
#send_error(request_id, error) ⇒ void
This method returns an undefined value.
131 132 133 134 135 136 137 138 |
# File 'lib/ibex/lsp/server.rb', line 131 def send_error(request_id, error) @transport.( "jsonrpc" => "2.0", "id" => request_id, "error" => { "code" => error.code, "message" => error. } ) rescue ProtocolError => e log(e.) end |
#send_result(request_id, result) ⇒ void
This method returns an undefined value.
124 125 126 127 128 |
# File 'lib/ibex/lsp/server.rb', line 124 def send_result(request_id, result) @transport.("jsonrpc" => "2.0", "id" => request_id, "result" => result) rescue ProtocolError => e send_error(request_id, e) end |
#valid_request_id?(value) ⇒ Boolean
106 107 108 109 110 |
# File 'lib/ibex/lsp/server.rb', line 106 def valid_request_id?(value) return false unless value.is_a?(String) || value.is_a?(Integer) value.to_s.bytesize <= Limits::MAX_REQUEST_ID_BYTES end |
#validate_envelope(message) ⇒ String, ...
91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/ibex/lsp/server.rb', line 91 def validate_envelope() unless ["jsonrpc"] == "2.0" && ["method"].is_a?(String) raise ProtocolError.new("invalid JSON-RPC request", code: -32_600) end return nil unless .key?("id") request_id = ["id"] unless valid_request_id?(request_id) raise ProtocolError.new("request id must be a bounded string or integer", code: -32_600) end request_id end |
#validate_lifecycle!(method) ⇒ void
This method returns an undefined value.
113 114 115 116 117 118 119 120 121 |
# File 'lib/ibex/lsp/server.rb', line 113 def validate_lifecycle!(method) return if method == "exit" return if @state == :uninitialized && method == "initialize" return if @state == :initialized && %w[initialized shutdown].include?(method) return if @state == :running code = @state == :uninitialized ? -32_002 : -32_600 raise ProtocolError.new("request is invalid in #{@state} server state", code: code) end |
#validate_message_kind!(method, request) ⇒ void
This method returns an undefined value.
81 82 83 84 85 86 87 88 |
# File 'lib/ibex/lsp/server.rb', line 81 def (method, request) if REQUEST_METHODS.include?(method) && !request raise ProtocolError.new("#{method} must be a request", code: -32_600) end return unless NOTIFICATION_METHODS.include?(method) && request raise ProtocolError.new("#{method} must be a notification", code: -32_600) end |