Created
July 14, 2023 16:25
-
-
Save tenderlove/8168ecc089cc8a325e83a089933d5ac9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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