Class: RubyLsp::Rails::RunnerClient

Inherits:
Object
  • Object
show all
Extended by:
T::Sig
Defined in:
lib/ruby_lsp/ruby_lsp_rails/runner_client.rb

Direct Known Subclasses

NullClient

Defined Under Namespace

Classes: EmptyMessageError, IncompleteMessageError, InitializationError

Constant Summary collapse

MAX_RETRIES =
5

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeRunnerClient

Returns a new instance of RunnerClient.



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
# File 'lib/ruby_lsp/ruby_lsp_rails/runner_client.rb', line 40

def initialize
  # Spring needs a Process session ID. It uses this ID to "attach" itself to the parent process, so that when the
  # parent ends, the spring process ends as well. If this is not set, Spring will throw an error while trying to
  # set its own session ID
  begin
    Process.setpgrp
    Process.setsid
  rescue Errno::EPERM
    # If we can't set the session ID, continue
  rescue NotImplementedError
    # setpgrp() may be unimplemented on some platform
    # https://github.com/Shopify/ruby-lsp-rails/issues/348
  end

  stdin, stdout, stderr, wait_thread = Bundler.with_original_env do
    Open3.popen3("bundle", "exec", "rails", "runner", "#{__dir__}/server.rb", "start")
  end

  @stdin = T.let(stdin, IO)
  @stdout = T.let(stdout, IO)
  @stderr = T.let(stderr, IO)
  @wait_thread = T.let(wait_thread, Process::Waiter)
  @stdin.binmode # for Windows compatibility
  @stdout.binmode # for Windows compatibility

  $stderr.puts("Ruby LSP Rails booting server")
  count = 0

  begin
    count += 1
    read_response
  rescue EmptyMessageError
    $stderr.puts("Ruby LSP Rails is retrying initialize (#{count})")
    retry if count < MAX_RETRIES
  end

  $stderr.puts("Finished booting Ruby LSP Rails server")

  unless ENV["RAILS_ENV"] == "test"
    at_exit do
      if @wait_thread.alive?
        $stderr.puts("Ruby LSP Rails is force killing the server")
        sleep(0.5) # give the server a bit of time if we already issued a shutdown notification

        # Windows does not support the `TERM` signal, so we're forced to use `KILL` here
        Process.kill(T.must(Signal.list["KILL"]), @wait_thread.pid)
      end
    end
  end
rescue Errno::EPIPE, IncompleteMessageError
  raise InitializationError, @stderr.read
end

Class Method Details

.create_clientObject



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/ruby_lsp/ruby_lsp_rails/runner_client.rb', line 14

def create_client
  if File.exist?("bin/rails")
    new
  else
    $stderr.puts(<<~MSG)
      Ruby LSP Rails failed to locate bin/rails in the current directory: #{Dir.pwd}"
    MSG
    $stderr.puts("Server dependent features will not be available")
    NullClient.new
  end
rescue Errno::ENOENT, StandardError => e # rubocop:disable Lint/ShadowedException
  $stderr.puts("Ruby LSP Rails failed to initialize server: #{e.message}\n#{e.backtrace&.join("\n")}")
  $stderr.puts("Server dependent features will not be available")
  NullClient.new
end

Instance Method Details

#association_target_location(model_name:, association_name:) ⇒ Object



107
108
109
110
111
112
113
114
115
# File 'lib/ruby_lsp/ruby_lsp_rails/runner_client.rb', line 107

def association_target_location(model_name:, association_name:)
  make_request(
    "association_target_location",
    model_name: model_name,
    association_name: association_name,
  )
rescue => e
  $stderr.puts("Ruby LSP Rails failed with #{e.message}: #{@stderr.read}")
end

#model(name) ⇒ Object



94
95
96
97
98
99
# File 'lib/ruby_lsp/ruby_lsp_rails/runner_client.rb', line 94

def model(name)
  make_request("model", name: name)
rescue IncompleteMessageError
  $stderr.puts("Ruby LSP Rails failed to get model information: #{@stderr.read}")
  nil
end

#route_location(name) ⇒ Object



118
119
120
121
122
123
# File 'lib/ruby_lsp/ruby_lsp_rails/runner_client.rb', line 118

def route_location(name)
  make_request("route_location", name: name)
rescue IncompleteMessageError
  $stderr.puts("Ruby LSP Rails failed to get route location: #{@stderr.read}")
  nil
end

#shutdownObject



135
136
137
138
139
140
# File 'lib/ruby_lsp/ruby_lsp_rails/runner_client.rb', line 135

def shutdown
  $stderr.puts("Ruby LSP Rails shutting down server")
  send_message("shutdown")
  sleep(0.5) # give the server a bit of time to shutdown
  [@stdin, @stdout, @stderr].each(&:close)
end

#stopped?Boolean

Returns:

  • (Boolean)


143
144
145
# File 'lib/ruby_lsp/ruby_lsp_rails/runner_client.rb', line 143

def stopped?
  [@stdin, @stdout, @stderr].all?(&:closed?) && !@wait_thread.alive?
end

#trigger_reloadObject



126
127
128
129
130
131
132
# File 'lib/ruby_lsp/ruby_lsp_rails/runner_client.rb', line 126

def trigger_reload
  $stderr.puts("Reloading Rails application")
  send_notification("reload")
rescue IncompleteMessageError
  $stderr.puts("Ruby LSP Rails failed to trigger reload")
  nil
end