1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
|
#!/usr/bin/env ruby
# frozen_string_literal: true
require "optparse"
original_args = ARGV.dup
options = {}
parser = OptionParser.new do |opts|
opts.banner = "Usage: ruby-lsp [options]"
opts.on("--version", "Print ruby-lsp version") do
require "ruby-lsp"
puts RubyLsp::VERSION
exit(0)
end
opts.on("--debug", "Launch the Ruby LSP with a debugger attached") do
options[:debug] = true
end
opts.on("--time-index", "Measure the time it takes to index the project") do
options[:time_index] = true
end
opts.on(
"--branch [BRANCH]",
"Launch the Ruby LSP using the specified branch rather than the release version",
) do |branch|
options[:branch] = branch
end
opts.on("--doctor", "Run troubleshooting steps") do
options[:doctor] = true
end
opts.on("--use-launcher", "[EXPERIMENTAL] Use launcher mechanism to handle missing dependencies gracefully") do
options[:launcher] = true
end
opts.on("-h", "--help", "Print this help") do
puts opts.help
puts
puts "See https://shopify.github.io/ruby-lsp/ for more information"
exit(0)
end
end
begin
parser.parse!
rescue OptionParser::InvalidOption => e
warn(e)
warn("")
warn(parser.help)
exit(1)
end
# When we're running without bundler, then we need to make sure the composed bundle is fully configured and re-execute
# using `BUNDLE_GEMFILE=.ruby-lsp/Gemfile bundle exec ruby-lsp` so that we have access to the gems that are a part of
# the application's bundle
if ENV["BUNDLE_GEMFILE"].nil?
# Substitute the current process by the launcher. RubyGems activates all dependencies of a gem's executable eagerly,
# but we can't have that happen because we want to invoke Bundler.setup ourselves with the composed bundle and avoid
# duplicate spec activation errors. Replacing the process with the launcher executable will clear the activated specs,
# which gives us the opportunity to control which specs are activated and enter degraded mode if any gems failed to
# install rather than failing to boot the server completely
if options[:launcher]
flags = []
flags << "--debug" if options[:debug]
exit exec(Gem.ruby, File.expand_path("ruby-lsp-launcher", __dir__), *flags)
end
require_relative "../lib/ruby_lsp/setup_bundler"
begin
env = RubyLsp::SetupBundler.new(Dir.pwd, **options).setup!
rescue RubyLsp::SetupBundler::BundleNotLocked
warn("Project contains a Gemfile, but no Gemfile.lock. Run `bundle install` to lock gems and restart the server")
exit(78)
end
bundler_path = File.join(Gem.default_bindir, "bundle")
base_command = (!Gem.win_platform? && File.exist?(bundler_path) ? "#{Gem.ruby} #{bundler_path}" : "bundle").dup
if env["BUNDLER_VERSION"]
base_command << " _#{env["BUNDLER_VERSION"]}_"
end
exit exec(env, "#{base_command} exec ruby-lsp #{original_args.join(" ")}".strip)
end
$stdin.sync = true
$stdout.sync = true
$stderr.sync = true
$stdin.binmode
$stdout.binmode
$stderr.binmode
$LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
require "ruby_lsp/internal"
if options[:debug]
if ["x64-mingw-ucrt", "x64-mingw32"].include?(RUBY_PLATFORM)
$stderr.puts "Debugging is not supported on Windows"
exit 1
end
begin
ENV.delete("RUBY_DEBUG_IRB_CONSOLE")
require "debug/open_nonstop"
rescue LoadError
$stderr.puts("You need to install the debug gem to use the --debug flag")
end
end
if options[:time_index]
index = RubyIndexer::Index.new
time_start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
index.index_all
elapsed_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) - time_start
entries = index.instance_variable_get(:@entries)
entries_by_entry_type = entries.values.flatten.group_by(&:class)
puts <<~MSG
Ruby LSP v#{RubyLsp::VERSION}: Indexing took #{elapsed_time.round(5)} seconds and generated:
- #{entries_by_entry_type.sort_by { |k, _| k.to_s }.map { |k, v| "#{k.name.split("::").last}: #{v.size}" }.join("\n- ")}
MSG
return
end
if options[:doctor]
index = RubyIndexer::Index.new
if File.exist?(".index.yml")
begin
config = YAML.parse_file(".index.yml").to_ruby
rescue => e
abort("Error parsing config: #{e.message}")
end
index.configuration.apply_config(config)
end
puts "Globbing for indexable files"
index.configuration.indexable_uris.each do |uri|
puts "indexing: #{uri}"
index.index_file(uri)
end
return
end
server = RubyLsp::Server.new
# Ensure all output goes out stderr by default to allow puts/p/pp to work
# without specifying output device.
$> = $stderr
server.start
|