class SyntaxTree::LanguageServer

Syntax Tree additionally ships with a language server conforming to the language server protocol. It can be invoked through the CLI by running:

stree lsp

Attributes

input[R]
output[R]
print_width[R]

Public Class Methods

new( input: $stdin, output: $stdout, print_width: DEFAULT_PRINT_WIDTH ) click to toggle source
# File lib/syntax_tree/language_server.rb, line 217
def initialize(
  input: $stdin,
  output: $stdout,
  print_width: DEFAULT_PRINT_WIDTH
)
  @input = input.binmode
  @output = output.binmode
  @print_width = print_width
end

Public Instance Methods

run() click to toggle source

rubocop:disable Layout/LineLength

# File lib/syntax_tree/language_server.rb, line 228
def run
  store =
    Hash.new do |hash, uri|
      filepath = CGI.unescape(URI.parse(uri).path)
      File.exist?(filepath) ? (hash[uri] = File.read(filepath)) : nil
    end

  while (headers = input.gets("\r\n\r\n"))
    source = input.read(headers[/Content-Length: (\d+)/i, 1].to_i)
    request = JSON.parse(source, symbolize_names: true)

    # stree-ignore
    case request
    when Request[method: "initialize", id: :any]
      store.clear
      write(id: request[:id], result: { capabilities: capabilities })
    when Request[method: "initialized"]
      # ignored
    when Request[method: "shutdown"] # tolerate missing ID to be a good citizen
      store.clear
      write(id: request[:id], result: {})
      return
    when Request[method: "textDocument/didChange", params: { textDocument: { uri: :any }, contentChanges: [{ text: :any }] }]
      store[request.dig(:params, :textDocument, :uri)] = request.dig(:params, :contentChanges, 0, :text)
    when Request[method: "textDocument/didOpen", params: { textDocument: { uri: :any, text: :any } }]
      store[request.dig(:params, :textDocument, :uri)] = request.dig(:params, :textDocument, :text)
    when Request[method: "textDocument/didClose", params: { textDocument: { uri: :any } }]
      store.delete(request.dig(:params, :textDocument, :uri))
    when Request[method: "textDocument/formatting", id: :any, params: { textDocument: { uri: :any } }]
      uri = request.dig(:params, :textDocument, :uri)
      contents = store[uri]
      write(id: request[:id], result: contents ? format(contents, uri.split(".").last) : nil)
    when Request[method: "textDocument/inlayHint", id: :any, params: { textDocument: { uri: :any } }]
      uri = request.dig(:params, :textDocument, :uri)
      contents = store[uri]
      write(id: request[:id], result: contents ? inlay_hints(contents) : nil)
    when Request[method: "syntaxTree/visualizing", id: :any, params: { textDocument: { uri: :any } }]
      uri = request.dig(:params, :textDocument, :uri)
      write(id: request[:id], result: PP.pp(SyntaxTree.parse(store[uri]), +""))
    when Request[method: %r{\$/.+}]
      # ignored
    when Request[method: "textDocument/documentColor", params: { textDocument: { uri: :any } }]
      # ignored
    else
      raise ArgumentError, "Unhandled: #{request}"
    end
  end
end