class Spoom::LSP::Client

Public Class Methods

new(sorbet_bin, *sorbet_args, path: ".") click to toggle source
# File lib/spoom/sorbet/lsp.rb, line 14
def initialize(sorbet_bin, *sorbet_args, path: ".")
  @id = 0
  @in, @out, @err, @status = T.unsafe(Open3).popen3(sorbet_bin, *sorbet_args, chdir: path)
end

Public Instance Methods

close() click to toggle source
# File lib/spoom/sorbet/lsp.rb, line 184
def close
  send(Request.new(next_id, "shutdown", nil))
  @in.close
  @out.close
  @err.close
end
definitions(uri, line, column) click to toggle source
# File lib/spoom/sorbet/lsp.rb, line 106
def definitions(uri, line, column)
  json = send(Request.new(
    next_id,
    'textDocument/definition',
    {
      'textDocument' => {
        'uri' => uri,
      },
      'position' => {
        'line' => line,
        'character' => column,
      },
    }
  ))
  json['result'].map { |loc| Location.from_json(loc) }
end
document_symbols(uri) click to toggle source
# File lib/spoom/sorbet/lsp.rb, line 171
def document_symbols(uri)
  json = send(Request.new(
    next_id,
    'textDocument/documentSymbol',
    {
      'textDocument' => {
        'uri' => uri,
      },
    }
  ))
  json['result'].map { |loc| DocumentSymbol.from_json(loc) }
end
hover(uri, line, column) click to toggle source
# File lib/spoom/sorbet/lsp.rb, line 71
def hover(uri, line, column)
  json = send(Request.new(
    next_id,
    'textDocument/hover',
    {
      'textDocument' => {
        'uri' => uri,
      },
      'position' => {
        'line' => line,
        'character' => column,
      },
    }
  ))
  return nil unless json['result']
  Hover.from_json(json['result'])
end
next_id() click to toggle source
# File lib/spoom/sorbet/lsp.rb, line 19
def next_id
  @id += 1
end
open(workspace_path) click to toggle source

LSP requests

# File lib/spoom/sorbet/lsp.rb, line 56
def open(workspace_path)
  raise Error::AlreadyOpen, "Error: CLI already opened" if @open
  send(Request.new(
    next_id,
    'initialize',
    {
      'rootPath' => workspace_path,
      'rootUri' => "file://#{workspace_path}",
      'capabilities' => {},
    },
  ))
  send(Notification.new('initialized', {}))
  @open = true
end
read() click to toggle source
# File lib/spoom/sorbet/lsp.rb, line 42
def read
  json = JSON.parse(read_raw)

  # Handle error in the LSP protocol
  raise ResponseError.from_json(json['error']) if json['error']

  # Handle typechecking errors
  raise Error::Diagnostics.from_json(json['params']) if json['method'] == "textDocument/publishDiagnostics"

  json
end
read_raw() click to toggle source
# File lib/spoom/sorbet/lsp.rb, line 32
def read_raw
  header = @out.gets

  # Sorbet returned an error and forgot to answer
  raise Error::BadHeaders, "bad response headers" unless header&.match?(/Content-Length: /)

  len = header.slice(::Range.new(16, nil)).to_i
  @out.read(len + 2) # +2 'cause of the final \r\n
end
references(uri, line, column, include_decl = true) click to toggle source
# File lib/spoom/sorbet/lsp.rb, line 140
def references(uri, line, column, include_decl = true)
  json = send(Request.new(
    next_id,
    'textDocument/references',
    {
      'textDocument' => {
        'uri' => uri,
      },
      'position' => {
        'line' => line,
        'character' => column,
      },
      'context' => {
        'includeDeclaration' => include_decl,
      },
    }
  ))
  json['result'].map { |loc| Location.from_json(loc) }
end
send(message) click to toggle source
# File lib/spoom/sorbet/lsp.rb, line 27
def send(message)
  send_raw(message.to_json)
  read if message.is_a?(Request)
end
send_raw(json_string) click to toggle source
# File lib/spoom/sorbet/lsp.rb, line 23
def send_raw(json_string)
  @in.puts("Content-Length:#{json_string.length}\r\n\r\n#{json_string}")
end
signatures(uri, line, column) click to toggle source
# File lib/spoom/sorbet/lsp.rb, line 89
def signatures(uri, line, column)
  json = send(Request.new(
    next_id,
    'textDocument/signatureHelp',
    {
      'textDocument' => {
        'uri' => uri,
      },
      'position' => {
        'line' => line,
        'character' => column,
      },
    }
  ))
  json['result']['signatures'].map { |loc| SignatureHelp.from_json(loc) }
end
symbols(query) click to toggle source
# File lib/spoom/sorbet/lsp.rb, line 160
def symbols(query)
  json = send(Request.new(
    next_id,
    'workspace/symbol',
    {
      'query' => query,
    }
  ))
  json['result'].map { |loc| DocumentSymbol.from_json(loc) }
end
type_definitions(uri, line, column) click to toggle source
# File lib/spoom/sorbet/lsp.rb, line 123
def type_definitions(uri, line, column)
  json = send(Request.new(
    next_id,
    'textDocument/typeDefinition',
    {
      'textDocument' => {
        'uri' => uri,
      },
      'position' => {
        'line' => line,
        'character' => column,
      },
    }
  ))
  json['result'].map { |loc| Location.from_json(loc) }
end