Skip to content

Commit

Permalink
Publish RuboCop::LSP.enable to enable LSP mode
Browse files Browse the repository at this point in the history
`RuboCop::Cop::Base.enable_lsp_mode` will be renamed to `RuboCop::LSP.enable`.

Before:

```ruby
RuboCop::Cop::Base.enable_lsp_mode
```

After:

```ruby
RuboCop::LSP.enable
```

This is because whether or not it is LSP should not be set per cop
but should be a state controlled for the entire RuboCop process.

Since `RuboCop::Cop::Base.enable_lsp_mode` was an experimental private API,
it will be renamed without a deprecation warning.

Along with this, the module name has been changed from `RuboCop::Lsp` to `RuboCop::LSP`.
This change is made to align with Ruby's standard API, like `RubyVM::YJIT.enable`,
making it `RuboCop::LSP.enable` instead. `RuboCop::Lsp.enable` does not look as pretty name.

With the renaming to `RuboCop::LSP.enable`, the usage of this API will be documented.
This allows libraries like Ruby LSP and Solargraph, which use internal modules other than
RuboCop's built-in `RuboCop::LSP::Server#start`, to easily utilize the features in #12586 and #12657.
  • Loading branch information
koic committed Feb 8, 2024
1 parent dc50e80 commit 40d53cf
Show file tree
Hide file tree
Showing 17 changed files with 62 additions and 40 deletions.
1 change: 1 addition & 0 deletions changelog/new_publish_lsp_enable_api.md
@@ -0,0 +1 @@
* [#12679](https://github.com/rubocop/rubocop/pull/12679): Publish `RuboCop::LSP.enable` API to enable LSP mode. ([@koic][])
9 changes: 9 additions & 0 deletions docs/modules/ROOT/pages/usage/lsp.adoc
Expand Up @@ -259,3 +259,12 @@ user 17414 0.0 0.2 5557716 144376 ?? Ss 4:48PM 0:02.13 /
```

NOTE: `rubocop --lsp` is for starting LSP client, so users don't manually execute it.

== Language Server Development

RuboCop provides APIs for developers of original language server or tools analogous to LSP, using RuboCop as the backend, instead of the RuboCop's built-in LSP.

- `RuboCop::LSP.enable` enables LSP mode, customizing for LSP-specific features such as autocorrection and short offense message.
- `RuboCop::LSP.disable` disables LSP mode, which can be particularly useful for testing.

When implementing custom cops, `RuboCop::LSP.enabled?` can be used to achieve behavior that considers these states.
4 changes: 2 additions & 2 deletions lib/rubocop/cli/command/lsp.rb
Expand Up @@ -7,11 +7,11 @@ class CLI
module Command
# Start Language Server Protocol of RuboCop.
# @api private
class Lsp < Base
class LSP < Base
self.command_name = :lsp

def run
RuboCop::Lsp::Server.new(@config_store).start
RuboCop::LSP::Server.new(@config_store).start
end
end
end
Expand Down
18 changes: 0 additions & 18 deletions lib/rubocop/cop/base.rb
Expand Up @@ -84,24 +84,6 @@ def self.support_autocorrect?
false
end

### LSP

# This experimental feature has been under consideration for a while.
# @api private
def self.lsp_mode?
!!@lsp_mode
end

# This experimental feature has been under consideration for a while.
def self.enable_lsp_mode
@lsp_mode = true
end

# This experimental feature has been under consideration for a while.
def self.disable_lsp_mode
@lsp_mode = false
end

### Naming

def self.badge
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/lint/syntax.rb
Expand Up @@ -17,7 +17,7 @@ def on_other_file
private

def add_offense_from_diagnostic(diagnostic, ruby_version)
message = if Base.lsp_mode?
message = if LSP.enabled?
diagnostic.message
else
"#{diagnostic.message}\n(Using Ruby #{ruby_version} parser; " \
Expand Down
29 changes: 29 additions & 0 deletions lib/rubocop/lsp.rb
@@ -0,0 +1,29 @@
# frozen_string_literal: true

module RuboCop
# The RuboCop's built-in LSP module.
module LSP
module_function

# Returns true when LSP is enabled, false when disabled.
#
# @return [Boolean]
def enabled?
!!@enabled
end

# Enable LSP.
#
# @return [void]
def enable
@enabled = true
end

# Disable LSP.
#
# @return [void]
def disable
@enabled = false
end
end
end
2 changes: 1 addition & 1 deletion lib/rubocop/lsp/logger.rb
Expand Up @@ -10,7 +10,7 @@
# https://github.com/standardrb/standard/blob/main/LICENSE.txt
#
module RuboCop
module Lsp
module LSP
# Log for Language Server Protocol of RuboCop.
# @api private
class Logger
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/lsp/routes.rb
Expand Up @@ -12,7 +12,7 @@
# https://github.com/standardrb/standard/blob/main/LICENSE.txt
#
module RuboCop
module Lsp
module LSP
# Routes for Language Server Protocol of RuboCop.
# @api private
class Routes
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/lsp/runtime.rb
Expand Up @@ -10,7 +10,7 @@
# https://github.com/standardrb/standard/blob/main/LICENSE.txt
#
module RuboCop
module Lsp
module LSP
# Runtime for Language Server Protocol of RuboCop.
# @api private
class Runtime
Expand Down
7 changes: 4 additions & 3 deletions lib/rubocop/lsp/server.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require 'language_server-protocol'
require_relative '../lsp'
require_relative 'logger'
require_relative 'routes'
require_relative 'runtime'
Expand All @@ -15,16 +16,16 @@
# https://github.com/standardrb/standard/blob/main/LICENSE.txt
#
module RuboCop
module Lsp
module LSP
# Language Server Protocol of RuboCop.
# @api private
class Server
def initialize(config_store)
RuboCop::Cop::Base.enable_lsp_mode
RuboCop::LSP.enable

@reader = LanguageServer::Protocol::Transport::Io::Reader.new($stdin)
@writer = LanguageServer::Protocol::Transport::Io::Writer.new($stdout)
@runtime = RuboCop::Lsp::Runtime.new(config_store)
@runtime = RuboCop::LSP::Runtime.new(config_store)
@routes = Routes.new(self)
end

Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/lsp/severity.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true

module RuboCop
module Lsp
module LSP
# Severity for Language Server Protocol of RuboCop.
# @api private
class Severity
Expand Down
6 changes: 3 additions & 3 deletions lib/rubocop/rspec/shared_contexts.rb
Expand Up @@ -128,13 +128,13 @@ def source_range(range, buffer: source_buffer)
end
end

RSpec.shared_context 'lsp mode' do
RSpec.shared_context 'lsp' do
before do
RuboCop::Cop::Base.enable_lsp_mode
RuboCop::LSP.enable
end

after do
RuboCop::Cop::Base.disable_lsp_mode
RuboCop::LSP.disable
end
end

Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/rspec/support.rb
Expand Up @@ -13,7 +13,7 @@
config.include HostEnvironmentSimulatorHelper
config.include_context 'config', :config
config.include_context 'isolated environment', :isolated_environment
config.include_context 'lsp mode', :lsp_mode
config.include_context 'lsp', :lsp
config.include_context 'maintain registry', :restore_registry
config.include_context 'ruby 2.0', :ruby20
config.include_context 'ruby 2.1', :ruby21
Expand Down
2 changes: 1 addition & 1 deletion spec/rubocop/cop/lint/syntax_spec.rb
Expand Up @@ -51,7 +51,7 @@
end
end

context 'with `--lsp` option', :lsp_mode do
context 'with `--lsp` option', :lsp do
it 'does not include a configuration information in the offense message' do
expect(offenses.first.message).to eq('unexpected token $end')
end
Expand Down
8 changes: 4 additions & 4 deletions spec/rubocop/lsp/server_spec.rb
@@ -1,12 +1,12 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Lsp::Server, :isolated_environment do
include LspHelper
RSpec.describe RuboCop::LSP::Server, :isolated_environment do
include LSPHelper

subject(:result) { run_server_on_requests(*requests) }

after do
RuboCop::Cop::Base.disable_lsp_mode
RuboCop::LSP.disable
end

let(:messages) { result[0] }
Expand Down Expand Up @@ -1240,7 +1240,7 @@

context 'when an internal error occurs' do
before do
allow_any_instance_of(RuboCop::Lsp::Routes).to receive(:for).with('initialize').and_raise # rubocop:disable RSpec/AnyInstance
allow_any_instance_of(RuboCop::LSP::Routes).to receive(:for).with('initialize').and_raise # rubocop:disable RSpec/AnyInstance
end

let(:requests) do
Expand Down
2 changes: 1 addition & 1 deletion spec/rubocop/lsp/severity_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Lsp::Severity do
RSpec.describe RuboCop::LSP::Severity do
describe '.find_by' do
subject(:lsp_severity) { described_class.find_by(rubocop_severity) }

Expand Down
4 changes: 2 additions & 2 deletions spec/support/lsp_helper.rb
@@ -1,13 +1,13 @@
# frozen_string_literal: true

module LspHelper
module LSPHelper
def run_server_on_requests(*requests)
stdin = StringIO.new(requests.map { |request| to_jsonrpc(request) }.join)

RuboCop::Server::Helper.redirect(stdin: stdin) do
config_store = RuboCop::ConfigStore.new

RuboCop::Lsp::Server.new(config_store).start
RuboCop::LSP::Server.new(config_store).start
end

messages = parse_jsonrpc_messages($stdout)
Expand Down

0 comments on commit 40d53cf

Please sign in to comment.