Created
November 13, 2023 19:31
-
-
Save tenderlove/6903ddbe8eb0f568a8e88f28bb28f56f 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: "# #{Time.now}" | |
} | |
} | |
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 | |
else | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment