Skip to content

Commit

Permalink
Add --editor-mode CLI option
Browse files Browse the repository at this point in the history
Follow up rubocop#12657 (comment).

This PR adds `--editor-mode` CLI option, which optimize real-time feedback in editors,
adjusting behaviors for editing experience.

Editors that run RuboCop directly (e.g., by shelling out) encounter the same issues as with `--lsp`.
This option is designed for such editors.
  • Loading branch information
koic committed Feb 11, 2024
1 parent 772054e commit 8c94bf3
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 2 deletions.
1 change: 1 addition & 0 deletions changelog/new_add_editor_mode_option.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [#12682](https://github.com/rubocop/rubocop/issues/12682): Add `--editor-mode` CLI option. ([@koic][])
2 changes: 1 addition & 1 deletion docs/modules/ROOT/pages/configuration.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,7 @@ Style/PerlBackrefs:
==== `contextual`

This setting enables autocorrection when launched from the `rubocop` command, but it is not available through LSP.
e.g., `rubocop --lsp` or a program where `RuboCop::LSP.enable` has been applied.
e.g., `rubocop --lsp`, `rubocop --editor-mode`, or a program where `RuboCop::LSP.enable` has been applied.

Inspections via the command line are treated as code that has been finalized.

Expand Down
3 changes: 3 additions & 0 deletions docs/modules/ROOT/pages/usage/basic_usage.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,9 @@ $ rubocop --only Rails/Blank,Layout/HeredocIndentation,Naming/FileName
| `-s/--stdin`
| Pipe source from STDIN. This is useful for editor integration. Takes one argument, a path, relative to the root of the project. RuboCop will use this path to determine which cops are enabled (via eg. Include/Exclude), and so that certain cops like Naming/FileName can be checked.

| `--editor-mode`
| Optimize real-time feedback in editors, adjusting behaviors for editing experience. Editors that run RuboCop directly (e.g., by shelling out) encounter the same issues as with `--lsp`. This option is designed for such editors.

| `-S/--display-style-guide`
| Display style guide URLs in offense messages.

Expand Down
7 changes: 6 additions & 1 deletion lib/rubocop/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class CLI
STATUS_INTERRUPTED = Signal.list['INT'] + 128
DEFAULT_PARALLEL_OPTIONS = %i[
color config debug display_style_guide display_time display_only_fail_level_offenses
display_only_failed except extra_details fail_level fix_layout format
display_only_failed editor_mode except extra_details fail_level fix_layout format
ignore_disable_comments lint only only_guide_cops require safe
autocorrect safe_autocorrect autocorrect_all
].freeze
Expand Down Expand Up @@ -151,6 +151,7 @@ def parallel_by_default!

def act_on_options
set_options_to_config_loader
handle_editor_mode

@config_store.options_config = @options[:config] if @options[:config]
@config_store.force_default_config! if @options[:force_default_config]
Expand All @@ -174,6 +175,10 @@ def set_options_to_config_loader
ConfigLoader.ignore_unrecognized_cops = @options[:ignore_unrecognized_cops]
end

def handle_editor_mode
RuboCop::LSP.enable if @options[:editor_mode]
end

# rubocop:disable Metrics/CyclomaticComplexity
def handle_exiting_options
return unless Options::EXITING_OPTIONS.any? { |o| @options.key? o }
Expand Down
11 changes: 11 additions & 0 deletions lib/rubocop/options.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ def add_check_options(opts) # rubocop:disable Metrics/AbcSize, Metrics/MethodLen
option(opts, '--ignore-unrecognized-cops')
option(opts, '--force-default-config')
option(opts, '-s', '--stdin FILE')
option(opts, '--editor-mode')
option(opts, '-P', '--[no-]parallel')
option(opts, '--raise-cop-error')
add_severity_option(opts)
Expand Down Expand Up @@ -369,6 +370,7 @@ def validate_compatibility # rubocop:disable Metrics/MethodLength
validate_display_only_failed
validate_display_only_failed_and_display_only_correctable
validate_display_only_correctable_and_autocorrect
validate_lsp_and_editor_mode
disable_parallel_when_invalid_option_combo

return if incompatible_options.size <= 1
Expand Down Expand Up @@ -416,6 +418,13 @@ def validate_display_only_failed_and_display_only_correctable
format('--display-only-failed cannot be used together with other display options.')
end

def validate_lsp_and_editor_mode
return if !@options.key?(:lsp) || !@options.key?(:editor_mode)

raise OptionArgumentError,
format('Do not specify `--editor-mode` as it is redundant in `--lsp`.')
end

def validate_autocorrect
if @options.key?(:safe_autocorrect) && @options.key?(:autocorrect_all)
message = Rainbow(<<~MESSAGE).red
Expand Down Expand Up @@ -609,6 +618,8 @@ module OptionsHelp
'parallel. Default is true.'],
stdin: ['Pipe source from STDIN, using FILE in offense',
'reports. This is useful for editor integration.'],
editor_mode: ['Optimize real-time feedback in editors,',
'adjusting behaviors for editing experience.'],
init: 'Generate a .rubocop.yml file in the current directory.',
server: ['If a server process has not been started yet, start',
'the server process and execute inspection with server.',
Expand Down
70 changes: 70 additions & 0 deletions spec/rubocop/cli/options_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2230,6 +2230,76 @@ def f
end
end

describe '--editor-mode' do
let(:target_file) { 'example.rb' }

before do
create_file(target_file, <<~RUBY)
def empty_method
end
RUBY

create_file('.rubocop.yml', <<~YAML)
AllCops:
SuggestExtensions: false
Layout/EmptyLineAfterMagicComment:
AutoCorrect: contextual
YAML
end

after { RuboCop::LSP.disable }

context 'when using `--editor-mode`' do
it 'registers an offense, but does not correct for `Layout/EmptyLineAfterMagicComment` with `AutoCorrect: contextual`' do
status_code = cli.run(['--editor-mode', '-a', '--only', 'Style/EmptyMethod', target_file])

expect(status_code).to eq(1)
expect($stderr.string).to eq('')
expect(File.read('example.rb')).to eq(<<~RUBY)
def empty_method
end
RUBY
expect($stdout.string).to eq(<<~RESULT)
Inspecting 1 file
C
Offenses:
example.rb:1:1: C: Style/EmptyMethod: Put empty method definitions on a single line.
def empty_method ...
^^^^^^^^^^^^^^^^
1 file inspected, 1 offense detected
RESULT
end
end

context 'when not using `--editor-mode`' do
it 'registers an offense and corrects for `Layout/EmptyLineAfterMagicComment` with `AutoCorrect: contextual`' do
status_code = cli.run(['-a', '--only', 'Style/EmptyMethod', target_file])

expect(status_code).to eq(0)
expect($stderr.string).to eq('')
expect(File.read('example.rb')).to eq(<<~RUBY)
def empty_method; end
RUBY
expect($stdout.string).to eq(<<~RESULT)
Inspecting 1 file
C
Offenses:
example.rb:1:1: C: [Corrected] Style/EmptyMethod: Put empty method definitions on a single line.
def empty_method ...
^^^^^^^^^^^^^^^^
1 file inspected, 1 offense detected, 1 offense corrected
RESULT
end
end
end

describe '--require', :restore_registry do
context 'when adding an extension' do
before do
Expand Down
9 changes: 9 additions & 0 deletions spec/rubocop/options_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ def abs(path)
files are present in the directory tree.
-s, --stdin FILE Pipe source from STDIN, using FILE in offense
reports. This is useful for editor integration.
--editor-mode Optimize real-time feedback in editors,
adjusting behaviors for editing experience.
-P, --[no-]parallel Use available CPUs to execute inspection in
parallel. Default is true.
--raise-cop-error Raise cop-related errors with cause and location.
Expand Down Expand Up @@ -262,6 +264,13 @@ def abs(path)
.to raise_error(RuboCop::OptionArgumentError, msg)
end

it 'rejects using `--lsp` with `--editor-mode`' do
msg = 'Do not specify `--editor-mode` as it is redundant in `--lsp`.'
expect do
options.parse %w[--lsp --editor-mode]
end.to raise_error(RuboCop::OptionArgumentError, msg)
end

it 'mentions all incompatible options when more than two are used' do
msg = 'Incompatible cli options: [:version, :verbose_version, :show_cops]'
expect { options.parse %w[-vV --show-cops] }
Expand Down

0 comments on commit 8c94bf3

Please sign in to comment.