standard 1.38.0 → 1.39.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/Gemfile.lock +1 -1
- data/lib/ruby_lsp/standard/addon.rb +5 -7
- data/lib/ruby_lsp/standard/wraps_built_in_lsp_standardizer.rb +2 -64
- data/lib/standard/lsp/diagnostic.rb +168 -0
- data/lib/standard/lsp/logger.rb +3 -2
- data/lib/standard/lsp/routes.rb +1 -34
- data/lib/standard/lsp/server.rb +2 -1
- data/lib/standard/lsp/standardizer.rb +19 -54
- data/lib/standard/lsp/stdin_rubocop_runner.rb +61 -0
- data/lib/standard/version.rb +1 -1
- metadata +4 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: b15a7085baa8421e82fec821f8562214b001cfe17bd6a02f7a061bc892f047fa
         | 
| 4 | 
            +
              data.tar.gz: f67e28527faebd95dc452a57f8994523c11f2f3e5be6c28da458d374852c5f9e
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: d6040219e08da54f2ccfff731e787228e9226b20ba0380530513a41b0f29946eecf1503e41cd93e8f6beca3259258a713ad2f6815099325074a11ec2fcaf8915
         | 
| 7 | 
            +
              data.tar.gz: 6749ee4c00f5cad2c52b774e96048f82769046a9527dccc6515e0ee75ed274987d72f11d6422407c747ceed15c8b9c12a884c94573657af07811d7f013889135
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    
    
        data/Gemfile.lock
    CHANGED
    
    
| @@ -4,20 +4,18 @@ require_relative "wraps_built_in_lsp_standardizer" | |
| 4 4 | 
             
            module RubyLsp
         | 
| 5 5 | 
             
              module Standard
         | 
| 6 6 | 
             
                class Addon < ::RubyLsp::Addon
         | 
| 7 | 
            -
                  def initializer
         | 
| 8 | 
            -
                    @wraps_built_in_lsp_standardizer = nil
         | 
| 9 | 
            -
                  end
         | 
| 10 | 
            -
             | 
| 11 7 | 
             
                  def name
         | 
| 12 8 | 
             
                    "Standard Ruby"
         | 
| 13 9 | 
             
                  end
         | 
| 14 10 |  | 
| 15 11 | 
             
                  def activate(global_state, message_queue)
         | 
| 16 | 
            -
                     | 
| 12 | 
            +
                    @logger = ::Standard::Lsp::Logger.new(prefix: "[Standard Ruby]")
         | 
| 13 | 
            +
                    @logger.puts "Activating Standard Ruby LSP addon v#{::Standard::VERSION}"
         | 
| 14 | 
            +
                    RuboCop::LSP.enable
         | 
| 17 15 | 
             
                    @wraps_built_in_lsp_standardizer = WrapsBuiltinLspStandardizer.new
         | 
| 18 16 | 
             
                    global_state.register_formatter("standard", @wraps_built_in_lsp_standardizer)
         | 
| 19 17 | 
             
                    register_additional_file_watchers(global_state, message_queue)
         | 
| 20 | 
            -
                     | 
| 18 | 
            +
                    @logger.puts "Initialized Standard Ruby LSP addon #{::Standard::VERSION}"
         | 
| 21 19 | 
             
                  end
         | 
| 22 20 |  | 
| 23 21 | 
             
                  def deactivate
         | 
| @@ -52,7 +50,7 @@ module RubyLsp | |
| 52 50 | 
             
                  def workspace_did_change_watched_files(changes)
         | 
| 53 51 | 
             
                    if changes.any? { |change| change[:uri].end_with?(".standard.yml") }
         | 
| 54 52 | 
             
                      @wraps_built_in_lsp_standardizer.init!
         | 
| 55 | 
            -
                       | 
| 53 | 
            +
                      @logger.puts "Re-initialized Standard Ruby LSP addon #{::Standard::VERSION} due to .standard.yml file change"
         | 
| 56 54 | 
             
                    end
         | 
| 57 55 | 
             
                  end
         | 
| 58 56 | 
             
                end
         | 
| @@ -7,13 +7,9 @@ module RubyLsp | |
| 7 7 | 
             
                  end
         | 
| 8 8 |  | 
| 9 9 | 
             
                  def init!
         | 
| 10 | 
            -
                    @config = ::Standard::BuildsConfig.new.call([])
         | 
| 11 10 | 
             
                    @standardizer = ::Standard::Lsp::Standardizer.new(
         | 
| 12 | 
            -
                       | 
| 13 | 
            -
                      ::Standard::Lsp::Logger.new
         | 
| 11 | 
            +
                      ::Standard::BuildsConfig.new.call([])
         | 
| 14 12 | 
             
                    )
         | 
| 15 | 
            -
                    @rubocop_config = @config.rubocop_config_store.for_pwd
         | 
| 16 | 
            -
                    @cop_registry = RuboCop::Cop::Registry.global.to_h
         | 
| 17 13 | 
             
                  end
         | 
| 18 14 |  | 
| 19 15 | 
             
                  def run_formatting(uri, document)
         | 
| @@ -21,55 +17,7 @@ module RubyLsp | |
| 21 17 | 
             
                  end
         | 
| 22 18 |  | 
| 23 19 | 
             
                  def run_diagnostic(uri, document)
         | 
| 24 | 
            -
                     | 
| 25 | 
            -
             | 
| 26 | 
            -
                    offenses.map { |o|
         | 
| 27 | 
            -
                      cop_name = o[:cop_name]
         | 
| 28 | 
            -
             | 
| 29 | 
            -
                      msg = o[:message].delete_prefix(cop_name)
         | 
| 30 | 
            -
                      loc = o[:location]
         | 
| 31 | 
            -
             | 
| 32 | 
            -
                      severity = case o[:severity]
         | 
| 33 | 
            -
                      when "error", "fatal"
         | 
| 34 | 
            -
                        RubyLsp::Constant::DiagnosticSeverity::ERROR
         | 
| 35 | 
            -
                      when "warning"
         | 
| 36 | 
            -
                        RubyLsp::Constant::DiagnosticSeverity::WARNING
         | 
| 37 | 
            -
                      when "convention"
         | 
| 38 | 
            -
                        RubyLsp::Constant::DiagnosticSeverity::INFORMATION
         | 
| 39 | 
            -
                      when "refactor", "info"
         | 
| 40 | 
            -
                        RubyLsp::Constant::DiagnosticSeverity::HINT
         | 
| 41 | 
            -
                      else # the above cases fully cover what RuboCop sends at this time
         | 
| 42 | 
            -
                        logger.puts "Unknown severity: #{severity.inspect}"
         | 
| 43 | 
            -
                        RubyLsp::Constant::DiagnosticSeverity::HINT
         | 
| 44 | 
            -
                      end
         | 
| 45 | 
            -
             | 
| 46 | 
            -
                      RubyLsp::Interface::Diagnostic.new(
         | 
| 47 | 
            -
                        code: cop_name,
         | 
| 48 | 
            -
                        code_description: code_description(cop_name),
         | 
| 49 | 
            -
                        message: msg,
         | 
| 50 | 
            -
                        source: "Standard Ruby",
         | 
| 51 | 
            -
                        severity: severity,
         | 
| 52 | 
            -
                        range: RubyLsp::Interface::Range.new(
         | 
| 53 | 
            -
                          start: RubyLsp::Interface::Position.new(line: loc[:start_line] - 1, character: loc[:start_column] - 1),
         | 
| 54 | 
            -
                          end: RubyLsp::Interface::Position.new(line: loc[:last_line] - 1, character: loc[:last_column])
         | 
| 55 | 
            -
                        )
         | 
| 56 | 
            -
                        # TODO: We need to do something like to support quickfixes thru code actions
         | 
| 57 | 
            -
                        # See: https://github.com/Shopify/ruby-lsp/blob/4c1906172add4d5c39c35d3396aa29c768bfb898/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb#L62
         | 
| 58 | 
            -
                        # data: {
         | 
| 59 | 
            -
                        #   correctable: correctable?(offense),
         | 
| 60 | 
            -
                        #   code_actions: to_lsp_code_actions
         | 
| 61 | 
            -
                        # }
         | 
| 62 | 
            -
                        #
         | 
| 63 | 
            -
                        # Right now, our offenses are all just JSON parsed from stdout shelling to RuboCop, so
         | 
| 64 | 
            -
                        # it seems we don't have the corrector available to us.
         | 
| 65 | 
            -
                        #
         | 
| 66 | 
            -
                        # Lifted from:
         | 
| 67 | 
            -
                        # https://github.com/Shopify/ruby-lsp/blob/8d4c17efce4e8ecc8e7c557ab2981db6b22c0b6d/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb#L201
         | 
| 68 | 
            -
                        # def correctable?(offense)
         | 
| 69 | 
            -
                        #   !offense.corrector.nil?
         | 
| 70 | 
            -
                        # end
         | 
| 71 | 
            -
                      )
         | 
| 72 | 
            -
                    }
         | 
| 20 | 
            +
                    @standardizer.offenses(uri_to_path(uri), document.source, document.encoding)
         | 
| 73 21 | 
             
                  end
         | 
| 74 22 |  | 
| 75 23 | 
             
                  private
         | 
| @@ -83,16 +31,6 @@ module RubyLsp | |
| 83 31 | 
             
                      uri.to_s.sub(%r{^file://}, "")
         | 
| 84 32 | 
             
                    end
         | 
| 85 33 | 
             
                  end
         | 
| 86 | 
            -
             | 
| 87 | 
            -
                  # lifted from:
         | 
| 88 | 
            -
                  # https://github.com/Shopify/ruby-lsp/blob/4c1906172add4d5c39c35d3396aa29c768bfb898/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb#L84
         | 
| 89 | 
            -
                  def code_description(cop_name)
         | 
| 90 | 
            -
                    if (cop_class = @cop_registry[cop_name]&.first)
         | 
| 91 | 
            -
                      if (doc_url = cop_class.documentation_url(@rubocop_config))
         | 
| 92 | 
            -
                        Interface::CodeDescription.new(href: doc_url)
         | 
| 93 | 
            -
                      end
         | 
| 94 | 
            -
                    end
         | 
| 95 | 
            -
                  end
         | 
| 96 34 | 
             
                end
         | 
| 97 35 | 
             
              end
         | 
| 98 36 | 
             
            end
         | 
| @@ -0,0 +1,168 @@ | |
| 1 | 
            +
            module Standard
         | 
| 2 | 
            +
              module Lsp
         | 
| 3 | 
            +
                class Diagnostic
         | 
| 4 | 
            +
                  Constant = LanguageServer::Protocol::Constant
         | 
| 5 | 
            +
                  Interface = LanguageServer::Protocol::Interface
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  RUBOCOP_TO_LSP_SEVERITY = {
         | 
| 8 | 
            +
                    info: Constant::DiagnosticSeverity::HINT,
         | 
| 9 | 
            +
                    refactor: Constant::DiagnosticSeverity::INFORMATION,
         | 
| 10 | 
            +
                    convention: Constant::DiagnosticSeverity::INFORMATION,
         | 
| 11 | 
            +
                    warning: Constant::DiagnosticSeverity::WARNING,
         | 
| 12 | 
            +
                    error: Constant::DiagnosticSeverity::ERROR,
         | 
| 13 | 
            +
                    fatal: Constant::DiagnosticSeverity::ERROR
         | 
| 14 | 
            +
                  }.freeze
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  def initialize(document_encoding, offense, uri, cop_class)
         | 
| 17 | 
            +
                    @document_encoding = document_encoding
         | 
| 18 | 
            +
                    @offense = offense
         | 
| 19 | 
            +
                    @uri = uri
         | 
| 20 | 
            +
                    @cop_class = cop_class
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  def to_lsp_code_actions
         | 
| 24 | 
            +
                    code_actions = []
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                    code_actions << autocorrect_action if correctable?
         | 
| 27 | 
            +
                    code_actions << disable_line_action
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                    code_actions
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  def to_lsp_diagnostic(config)
         | 
| 33 | 
            +
                    highlighted = @offense.highlighted_area
         | 
| 34 | 
            +
                    Interface::Diagnostic.new(
         | 
| 35 | 
            +
                      message: message,
         | 
| 36 | 
            +
                      source: "Standard Ruby",
         | 
| 37 | 
            +
                      code: @offense.cop_name,
         | 
| 38 | 
            +
                      code_description: code_description(config),
         | 
| 39 | 
            +
                      severity: severity,
         | 
| 40 | 
            +
                      range: Interface::Range.new(
         | 
| 41 | 
            +
                        start: Interface::Position.new(
         | 
| 42 | 
            +
                          line: @offense.line - 1,
         | 
| 43 | 
            +
                          character: highlighted.begin_pos
         | 
| 44 | 
            +
                        ),
         | 
| 45 | 
            +
                        end: Interface::Position.new(
         | 
| 46 | 
            +
                          line: @offense.line - 1,
         | 
| 47 | 
            +
                          character: highlighted.end_pos
         | 
| 48 | 
            +
                        )
         | 
| 49 | 
            +
                      ),
         | 
| 50 | 
            +
                      data: {
         | 
| 51 | 
            +
                        correctable: correctable?,
         | 
| 52 | 
            +
                        code_actions: to_lsp_code_actions
         | 
| 53 | 
            +
                      }
         | 
| 54 | 
            +
                    )
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  private
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  def message
         | 
| 60 | 
            +
                    message = @offense.message
         | 
| 61 | 
            +
                    message += "\n\nThis offense is not auto-correctable.\n" unless correctable?
         | 
| 62 | 
            +
                    message
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                  def severity
         | 
| 66 | 
            +
                    RUBOCOP_TO_LSP_SEVERITY[@offense.severity.name]
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                  def code_description(config)
         | 
| 70 | 
            +
                    return unless @cop_class
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                    if (doc_url = @cop_class.documentation_url(config))
         | 
| 73 | 
            +
                      Interface::CodeDescription.new(href: doc_url)
         | 
| 74 | 
            +
                    end
         | 
| 75 | 
            +
                  end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                  def autocorrect_action
         | 
| 78 | 
            +
                    Interface::CodeAction.new(
         | 
| 79 | 
            +
                      title: "Autocorrect #{@offense.cop_name}",
         | 
| 80 | 
            +
                      kind: Constant::CodeActionKind::QUICK_FIX,
         | 
| 81 | 
            +
                      edit: Interface::WorkspaceEdit.new(
         | 
| 82 | 
            +
                        document_changes: [
         | 
| 83 | 
            +
                          Interface::TextDocumentEdit.new(
         | 
| 84 | 
            +
                            text_document: Interface::OptionalVersionedTextDocumentIdentifier.new(
         | 
| 85 | 
            +
                              uri: @uri.to_s,
         | 
| 86 | 
            +
                              version: nil
         | 
| 87 | 
            +
                            ),
         | 
| 88 | 
            +
                            edits: correctable? ? offense_replacements : []
         | 
| 89 | 
            +
                          )
         | 
| 90 | 
            +
                        ]
         | 
| 91 | 
            +
                      ),
         | 
| 92 | 
            +
                      is_preferred: true
         | 
| 93 | 
            +
                    )
         | 
| 94 | 
            +
                  end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                  def offense_replacements
         | 
| 97 | 
            +
                    @offense.corrector.as_replacements.map do |range, replacement|
         | 
| 98 | 
            +
                      Interface::TextEdit.new(
         | 
| 99 | 
            +
                        range: Interface::Range.new(
         | 
| 100 | 
            +
                          start: Interface::Position.new(line: range.line - 1, character: range.column),
         | 
| 101 | 
            +
                          end: Interface::Position.new(line: range.last_line - 1, character: range.last_column)
         | 
| 102 | 
            +
                        ),
         | 
| 103 | 
            +
                        new_text: replacement
         | 
| 104 | 
            +
                      )
         | 
| 105 | 
            +
                    end
         | 
| 106 | 
            +
                  end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                  def disable_line_action
         | 
| 109 | 
            +
                    Interface::CodeAction.new(
         | 
| 110 | 
            +
                      title: "Disable #{@offense.cop_name} for this line",
         | 
| 111 | 
            +
                      kind: Constant::CodeActionKind::QUICK_FIX,
         | 
| 112 | 
            +
                      edit: Interface::WorkspaceEdit.new(
         | 
| 113 | 
            +
                        document_changes: [
         | 
| 114 | 
            +
                          Interface::TextDocumentEdit.new(
         | 
| 115 | 
            +
                            text_document: Interface::OptionalVersionedTextDocumentIdentifier.new(
         | 
| 116 | 
            +
                              uri: @uri.to_s,
         | 
| 117 | 
            +
                              version: nil
         | 
| 118 | 
            +
                            ),
         | 
| 119 | 
            +
                            edits: line_disable_comment
         | 
| 120 | 
            +
                          )
         | 
| 121 | 
            +
                        ]
         | 
| 122 | 
            +
                      )
         | 
| 123 | 
            +
                    )
         | 
| 124 | 
            +
                  end
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                  def line_disable_comment
         | 
| 127 | 
            +
                    new_text = if @offense.source_line.include?(" # standard:disable ")
         | 
| 128 | 
            +
                      ",#{@offense.cop_name}"
         | 
| 129 | 
            +
                    else
         | 
| 130 | 
            +
                      " # standard:disable #{@offense.cop_name}"
         | 
| 131 | 
            +
                    end
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                    eol = Interface::Position.new(
         | 
| 134 | 
            +
                      line: @offense.line - 1,
         | 
| 135 | 
            +
                      character: length_of_line(@offense.source_line)
         | 
| 136 | 
            +
                    )
         | 
| 137 | 
            +
             | 
| 138 | 
            +
                    # TODO: fails for multiline strings - may be preferable to use block
         | 
| 139 | 
            +
                    # comments to disable some offenses
         | 
| 140 | 
            +
                    inline_comment = Interface::TextEdit.new(
         | 
| 141 | 
            +
                      range: Interface::Range.new(start: eol, end: eol),
         | 
| 142 | 
            +
                      new_text: new_text
         | 
| 143 | 
            +
                    )
         | 
| 144 | 
            +
             | 
| 145 | 
            +
                    [inline_comment]
         | 
| 146 | 
            +
                  end
         | 
| 147 | 
            +
             | 
| 148 | 
            +
                  def length_of_line(line)
         | 
| 149 | 
            +
                    if @document_encoding == Encoding::UTF_16LE
         | 
| 150 | 
            +
                      line_length = 0
         | 
| 151 | 
            +
                      line.codepoints.each do |codepoint|
         | 
| 152 | 
            +
                        line_length += 1
         | 
| 153 | 
            +
                        if codepoint > RubyLsp::Document::Scanner::SURROGATE_PAIR_START
         | 
| 154 | 
            +
                          line_length += 1
         | 
| 155 | 
            +
                        end
         | 
| 156 | 
            +
                      end
         | 
| 157 | 
            +
                      line_length
         | 
| 158 | 
            +
                    else
         | 
| 159 | 
            +
                      line.length
         | 
| 160 | 
            +
                    end
         | 
| 161 | 
            +
                  end
         | 
| 162 | 
            +
             | 
| 163 | 
            +
                  def correctable?
         | 
| 164 | 
            +
                    !@offense.corrector.nil?
         | 
| 165 | 
            +
                  end
         | 
| 166 | 
            +
                end
         | 
| 167 | 
            +
              end
         | 
| 168 | 
            +
            end
         | 
    
        data/lib/standard/lsp/logger.rb
    CHANGED
    
    | @@ -1,12 +1,13 @@ | |
| 1 1 | 
             
            module Standard
         | 
| 2 2 | 
             
              module Lsp
         | 
| 3 3 | 
             
                class Logger
         | 
| 4 | 
            -
                  def initialize
         | 
| 4 | 
            +
                  def initialize(prefix: "[server]")
         | 
| 5 | 
            +
                    @prefix = prefix
         | 
| 5 6 | 
             
                    @puts_onces = []
         | 
| 6 7 | 
             
                  end
         | 
| 7 8 |  | 
| 8 9 | 
             
                  def puts(message)
         | 
| 9 | 
            -
                    warn | 
| 10 | 
            +
                    warn [@prefix, message].compact.join(" ")
         | 
| 10 11 | 
             
                  end
         | 
| 11 12 |  | 
| 12 13 | 
             
                  def puts_once(message)
         | 
    
        data/lib/standard/lsp/routes.rb
    CHANGED
    
    | @@ -154,45 +154,12 @@ module Standard | |
| 154 154 |  | 
| 155 155 | 
             
                  def diagnostic(file_uri, text)
         | 
| 156 156 | 
             
                    @text_cache[file_uri] = text
         | 
| 157 | 
            -
                    offenses = @standardizer.offenses(uri_to_path(file_uri), text)
         | 
| 158 | 
            -
             | 
| 159 | 
            -
                    lsp_diagnostics = offenses.map { |o|
         | 
| 160 | 
            -
                      code = o[:cop_name]
         | 
| 161 | 
            -
             | 
| 162 | 
            -
                      msg = o[:message].delete_prefix(code)
         | 
| 163 | 
            -
                      loc = o[:location]
         | 
| 164 | 
            -
             | 
| 165 | 
            -
                      severity = case o[:severity]
         | 
| 166 | 
            -
                      when "error", "fatal"
         | 
| 167 | 
            -
                        SEV::ERROR
         | 
| 168 | 
            -
                      when "warning"
         | 
| 169 | 
            -
                        SEV::WARNING
         | 
| 170 | 
            -
                      when "convention"
         | 
| 171 | 
            -
                        SEV::INFORMATION
         | 
| 172 | 
            -
                      when "refactor", "info"
         | 
| 173 | 
            -
                        SEV::HINT
         | 
| 174 | 
            -
                      else # the above cases fully cover what RuboCop sends at this time
         | 
| 175 | 
            -
                        logger.puts "Unknown severity: #{severity.inspect}"
         | 
| 176 | 
            -
                        SEV::HINT
         | 
| 177 | 
            -
                      end
         | 
| 178 | 
            -
             | 
| 179 | 
            -
                      {
         | 
| 180 | 
            -
                        code: code,
         | 
| 181 | 
            -
                        message: msg,
         | 
| 182 | 
            -
                        range: {
         | 
| 183 | 
            -
                          start: {character: loc[:start_column] - 1, line: loc[:start_line] - 1},
         | 
| 184 | 
            -
                          end: {character: loc[:last_column], line: loc[:last_line] - 1}
         | 
| 185 | 
            -
                        },
         | 
| 186 | 
            -
                        severity: severity,
         | 
| 187 | 
            -
                        source: "standard"
         | 
| 188 | 
            -
                      }
         | 
| 189 | 
            -
                    }
         | 
| 190 157 |  | 
| 191 158 | 
             
                    {
         | 
| 192 159 | 
             
                      method: "textDocument/publishDiagnostics",
         | 
| 193 160 | 
             
                      params: {
         | 
| 194 161 | 
             
                        uri: file_uri,
         | 
| 195 | 
            -
                        diagnostics:  | 
| 162 | 
            +
                        diagnostics: @standardizer.offenses(uri_to_path(file_uri), text)
         | 
| 196 163 | 
             
                      }
         | 
| 197 164 | 
             
                    }
         | 
| 198 165 | 
             
                  end
         | 
    
        data/lib/standard/lsp/server.rb
    CHANGED
    
    | @@ -13,11 +13,12 @@ module Standard | |
| 13 13 | 
             
                    @writer = Proto::Transport::Io::Writer.new($stdout)
         | 
| 14 14 | 
             
                    @reader = Proto::Transport::Io::Reader.new($stdin)
         | 
| 15 15 | 
             
                    @logger = Logger.new
         | 
| 16 | 
            -
                    @standardizer = Standard::Lsp::Standardizer.new(config | 
| 16 | 
            +
                    @standardizer = Standard::Lsp::Standardizer.new(config)
         | 
| 17 17 | 
             
                    @routes = Routes.new(@writer, @logger, @standardizer)
         | 
| 18 18 | 
             
                  end
         | 
| 19 19 |  | 
| 20 20 | 
             
                  def start
         | 
| 21 | 
            +
                    RuboCop::LSP.enable
         | 
| 21 22 | 
             
                    @reader.read do |request|
         | 
| 22 23 | 
             
                      if !request.key?(:method)
         | 
| 23 24 | 
             
                        @routes.handle_method_missing(request)
         | 
| @@ -1,68 +1,33 @@ | |
| 1 | 
            -
            require_relative " | 
| 1 | 
            +
            require_relative "stdin_rubocop_runner"
         | 
| 2 | 
            +
            require_relative "diagnostic"
         | 
| 2 3 |  | 
| 3 4 | 
             
            module Standard
         | 
| 4 5 | 
             
              module Lsp
         | 
| 5 6 | 
             
                class Standardizer
         | 
| 6 | 
            -
                  def initialize(config | 
| 7 | 
            -
                    @ | 
| 8 | 
            -
                    @ | 
| 9 | 
            -
             | 
| 7 | 
            +
                  def initialize(config)
         | 
| 8 | 
            +
                    @diagnostic_runner = ::Standard::Lsp::StdinRubocopRunner.new(config)
         | 
| 9 | 
            +
                    @format_runner = ::Standard::Lsp::StdinRubocopRunner.new(config.dup.tap { |c|
         | 
| 10 | 
            +
                      c.rubocop_options[:autocorrect] = true
         | 
| 11 | 
            +
                    })
         | 
| 12 | 
            +
                    @cop_registry = RuboCop::Cop::Registry.global.to_h
         | 
| 10 13 | 
             
                  end
         | 
| 11 14 |  | 
| 12 | 
            -
                  # This abuses the --stdin option of rubocop and reads the formatted text
         | 
| 13 | 
            -
                  # from the options[:stdin] that rubocop mutates. This depends on
         | 
| 14 | 
            -
                  # parallel: false as well as the fact that rubocop doesn't otherwise dup
         | 
| 15 | 
            -
                  # or reassign that options object. Risky business!
         | 
| 16 | 
            -
                  #
         | 
| 17 | 
            -
                  # Reassigning options[:stdin] is done here:
         | 
| 18 | 
            -
                  #   https://github.com/rubocop/rubocop/blob/master/lib/rubocop/cop/team.rb#L131
         | 
| 19 | 
            -
                  # Printing options[:stdin]
         | 
| 20 | 
            -
                  #   https://github.com/rubocop/rubocop/blob/master/lib/rubocop/cli/command/execute_runner.rb#L95
         | 
| 21 | 
            -
                  # Setting `parallel: true` would break this here:
         | 
| 22 | 
            -
                  #   https://github.com/rubocop/rubocop/blob/master/lib/rubocop/runner.rb#L72
         | 
| 23 15 | 
             
                  def format(path, text)
         | 
| 24 | 
            -
                     | 
| 25 | 
            -
                     | 
| 26 | 
            -
                    ad_hoc_config.rubocop_options[:stdin]
         | 
| 16 | 
            +
                    @format_runner.run(path, text)
         | 
| 17 | 
            +
                    @format_runner.formatted_source
         | 
| 27 18 | 
             
                  end
         | 
| 28 19 |  | 
| 29 | 
            -
                  def offenses(path, text)
         | 
| 30 | 
            -
                     | 
| 31 | 
            -
                      capture_rubocop_stdout(fork_config(path, text, format: false)),
         | 
| 32 | 
            -
                      symbolize_names: true
         | 
| 33 | 
            -
                    )
         | 
| 34 | 
            -
                    if results[:files].empty?
         | 
| 35 | 
            -
                      @logger.puts_once "Ignoring file, per configuration: #{path}"
         | 
| 36 | 
            -
                      []
         | 
| 37 | 
            -
                    else
         | 
| 38 | 
            -
                      results.dig(:files, 0, :offenses)
         | 
| 39 | 
            -
                    end
         | 
| 40 | 
            -
                  end
         | 
| 41 | 
            -
             | 
| 42 | 
            -
                  private
         | 
| 20 | 
            +
                  def offenses(path, text, document_encoding = nil)
         | 
| 21 | 
            +
                    @diagnostic_runner.run(path, text)
         | 
| 43 22 |  | 
| 44 | 
            -
             | 
| 45 | 
            -
             | 
| 46 | 
            -
             | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 51 | 
            -
                    options = if format
         | 
| 52 | 
            -
                      {stdin: text, autocorrect: true, safe_autocorrect: true, formatters: []}
         | 
| 53 | 
            -
                    else
         | 
| 54 | 
            -
                      {stdin: text, autocorrect: false, safe_autocorrect: false, formatters: [["json"]], format: "json"}
         | 
| 23 | 
            +
                    @diagnostic_runner.offenses.map do |offense|
         | 
| 24 | 
            +
                      Diagnostic.new(
         | 
| 25 | 
            +
                        document_encoding,
         | 
| 26 | 
            +
                        offense,
         | 
| 27 | 
            +
                        path,
         | 
| 28 | 
            +
                        @cop_registry[offense.cop_name]&.first
         | 
| 29 | 
            +
                      ).to_lsp_diagnostic(@diagnostic_runner.config_for_working_directory)
         | 
| 55 30 | 
             
                    end
         | 
| 56 | 
            -
                    Standard::Config.new(@config.runner, [path], BASE_OPTIONS.merge(options), @config.rubocop_config_store)
         | 
| 57 | 
            -
                  end
         | 
| 58 | 
            -
             | 
| 59 | 
            -
                  def capture_rubocop_stdout(config)
         | 
| 60 | 
            -
                    redir = StringIO.new
         | 
| 61 | 
            -
                    $stdout = redir
         | 
| 62 | 
            -
                    @rubocop_runner.call(config)
         | 
| 63 | 
            -
                    redir.string
         | 
| 64 | 
            -
                  ensure
         | 
| 65 | 
            -
                    $stdout = STDOUT
         | 
| 66 31 | 
             
                  end
         | 
| 67 32 | 
             
                end
         | 
| 68 33 | 
             
              end
         | 
| @@ -0,0 +1,61 @@ | |
| 1 | 
            +
            module Standard
         | 
| 2 | 
            +
              module Lsp
         | 
| 3 | 
            +
                # Originally lifted from:
         | 
| 4 | 
            +
                # https://github.com/Shopify/ruby-lsp/blob/8d4c17efce4e8ecc8e7c557ab2981db6b22c0b6d/lib/ruby_lsp/requests/support/rubocop_runner.rb#L20
         | 
| 5 | 
            +
                class StdinRubocopRunner < ::RuboCop::Runner
         | 
| 6 | 
            +
                  class ConfigurationError < StandardError; end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  attr_reader :offenses
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  attr_reader :config_for_working_directory
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  DEFAULT_RUBOCOP_OPTIONS = {
         | 
| 13 | 
            +
                    stderr: true,
         | 
| 14 | 
            +
                    force_exclusion: true,
         | 
| 15 | 
            +
                    format: "RuboCop::Formatter::BaseFormatter",
         | 
| 16 | 
            +
                    raise_cop_error: true
         | 
| 17 | 
            +
                  }.freeze
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  def initialize(config)
         | 
| 20 | 
            +
                    @options = {}
         | 
| 21 | 
            +
                    @offenses = []
         | 
| 22 | 
            +
                    @errors = []
         | 
| 23 | 
            +
                    @warnings = []
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                    @config_for_working_directory = config.rubocop_config_store.for_pwd
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                    super(
         | 
| 28 | 
            +
                      config.rubocop_options.merge(DEFAULT_RUBOCOP_OPTIONS),
         | 
| 29 | 
            +
                      config.rubocop_config_store
         | 
| 30 | 
            +
                      )
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  def run(path, contents)
         | 
| 34 | 
            +
                    @errors = []
         | 
| 35 | 
            +
                    @warnings = []
         | 
| 36 | 
            +
                    @offenses = []
         | 
| 37 | 
            +
                    @options[:stdin] = contents
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                    super([path])
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                    raise Interrupt if aborting?
         | 
| 42 | 
            +
                  rescue ::RuboCop::Runner::InfiniteCorrectionLoop => error
         | 
| 43 | 
            +
                    raise RubyLsp::Requests::Formatting::Erro, error.message
         | 
| 44 | 
            +
                  rescue ::RuboCop::ValidationError => error
         | 
| 45 | 
            +
                    raise ConfigurationError, error.message
         | 
| 46 | 
            +
                  rescue => error
         | 
| 47 | 
            +
                    raise ::RubyLsp::Requests::Support::InternalRuboCopError, error
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  def formatted_source
         | 
| 51 | 
            +
                    @options[:stdin]
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                  private
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                  def file_finished(_file, offenses)
         | 
| 57 | 
            +
                    @offenses = offenses
         | 
| 58 | 
            +
                  end
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
              end
         | 
| 61 | 
            +
            end
         | 
    
        data/lib/standard/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: standard
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 1. | 
| 4 | 
            +
              version: 1.39.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Justin Searls
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2024-06- | 
| 11 | 
            +
            date: 2024-06-24 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: rubocop
         | 
| @@ -139,11 +139,13 @@ files: | |
| 139 139 | 
             
            - lib/standard/formatter.rb
         | 
| 140 140 | 
             
            - lib/standard/loads_runner.rb
         | 
| 141 141 | 
             
            - lib/standard/loads_yaml_config.rb
         | 
| 142 | 
            +
            - lib/standard/lsp/diagnostic.rb
         | 
| 142 143 | 
             
            - lib/standard/lsp/kills_server.rb
         | 
| 143 144 | 
             
            - lib/standard/lsp/logger.rb
         | 
| 144 145 | 
             
            - lib/standard/lsp/routes.rb
         | 
| 145 146 | 
             
            - lib/standard/lsp/server.rb
         | 
| 146 147 | 
             
            - lib/standard/lsp/standardizer.rb
         | 
| 148 | 
            +
            - lib/standard/lsp/stdin_rubocop_runner.rb
         | 
| 147 149 | 
             
            - lib/standard/merges_settings.rb
         | 
| 148 150 | 
             
            - lib/standard/plugin.rb
         | 
| 149 151 | 
             
            - lib/standard/plugin/combines_plugin_configs.rb
         |