Skip to content

Instantly share code, notes, and snippets.

@tenderlove
Created July 14, 2023 16:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tenderlove/8168ecc089cc8a325e83a089933d5ac9 to your computer and use it in GitHub Desktop.
Save tenderlove/8168ecc089cc8a325e83a089933d5ac9 to your computer and use it in GitHub Desktop.
#!/Users/aaron/.rubies/arm64/ruby-trunk/bin/ruby
# Configure Vim (using vim-lsp) like this where `ls.rb` is this script:
#
# if executable('./ls.rb')
# au User lsp_setup call lsp#register_server({
# \ 'name': 'ls.rb',
# \ 'cmd': ['./ls.rb'],
# \ 'allowlist': ['ruby'],
# \ })
# endif
require "logger"
require "json"
require "uri"
module LSP
class Writer
def initialize
@io = $stdout.binmode
end
def write response
str = JSON.dump(response.merge("jsonrpc" => "2.0"))
@io.write "Content-Length: #{str.bytesize}\r\n"
@io.write "\r\n"
@io.write str
@io.flush
end
end
class Reader
def initialize
@io = $stdin.binmode
end
def read
buffer = @io.gets("\r\n\r\n")
content_length = buffer.match(/Content-Length: (\d+)/i)[1].to_i
message = @io.read(content_length)
JSON.parse message, symbolize_names: true
end
end
$logger = Logger.new("#{File.dirname(File.expand_path(__FILE__))}/out.log")
class Events
DISPATCH = {
"initialize" => :on_initialize,
"textDocument/didSave" => :did_save,
"textDocument/hover" => :did_hover,
"textDocument/definition" => :on_definition,
}
def handle method, message, write
send DISPATCH.fetch(method) { :unknown }, message, write
end
def on_definition message, writer
uri = message.dig(:params, :textDocument, :uri)
file = URI.parse(message.dig(:params, :textDocument, :uri)).path
text = File.binread file
line = text.lines[message.dig(:params, :position, :line)]
idx = message.dig(:params, :position, :character)
token = line[/^.{#{idx}}\w+/][/\w+$/]
$logger.debug "Want definition for #{token}"
end
def on_initialize message, writer
result = {
"capabilities" => {
"textDocumentSync" => {
"openClose" => true,
"change" => 1,
"save" => true
},
"diagnosticProvider" => {
"interFileDependencies" => true,
},
"definitionProvider" => true,
"hoverProvider" => true,
}
}
writer.write(id: message[:id], result: result)
end
def did_save message, writer
saved_file = URI.parse(message.dig(:params, :textDocument, :uri)).path
# If we got a "did_save" event for this file, then `exec` ourselves
# so that we can get the updated code.
if saved_file == File.expand_path(__FILE__)
$logger.debug "Refreshing LSP"
exec $0
end
end
def did_hover message, writer
result = {
contents: {
kind: "markdown",
value: "# Hi YouTubers!"
},
}
writer.write(id: message[:id], result: result)
end
def unknown message, writer
$logger.debug "GOT MESSAGE: #{message}"
end
end
def self.run
reader = Reader.new
writer = Writer.new
subscriber = LSP::Events.new
loop do
message = reader.read
$logger.debug message.inspect
subscriber.handle message[:method], message, writer
end
end
end
if $0 == __FILE__
LSP.run
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment