standard 1.18.1 → 1.19.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 18c18f211f0cdcadb84cc05bbf54f6ea8fc40de394978df75e90ee46b7e5f378
4
- data.tar.gz: aa65d3f56f7d7cb51abe64e9473ceea973316ce1bbfd6f3af8654136b669ffbd
3
+ metadata.gz: bf52e94f737a041479cf2e741613a0e07d54af0b41f32f12309a94d5a2f0416b
4
+ data.tar.gz: 745dd891033fdc11271fd1331858a11c74d9e4188385eac5cc53580616aa7bbb
5
5
  SHA512:
6
- metadata.gz: 27903c69ab28846399bff4716b3bd0894ced1870fe9ebf8ded2178f5b5092f2c260b7a21b835bec214ac318dc3e278d1fbc003777f78788428311a40f9ae9b47
7
- data.tar.gz: 36011dac9b213b11ffd7a924482aef7d12c34171a0e5527cbc0bbac71098fb027fd01a48b7b87089a384d19a950eff9f182c7bb77ac7261cad83e608c73d0600
6
+ metadata.gz: d8eb3f8f27fbfc111270b6d2cbf44aed23de2c51eac64add89e3b8b89631adda6ca2348025c944a022cd51513868fb2f3668f1a099954bd8aea08d4acc12ef51
7
+ data.tar.gz: 17a3f227ef4044914bf12151ee9dfcf822f9c197938caac644601bf5c839895970ab3e6f58ee0079083fc877fc56849bd4f7391744d7a95da0b917545e76fb3b
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.19.1
4
+
5
+ * Loosen dependency on `language_server-protocol`
6
+
7
+ ## 1.19.0
8
+
9
+ * Add a language server protocol (LSP) server via the new `standardrb --lsp`
10
+ command line mode. All credit to [@will](https://github.com/)!
11
+ [#475](https://github.com/testdouble/standard/pull/475)
12
+
3
13
  ## 1.18.1
4
14
 
5
15
  * Update rubocop-performance from 1.15.0 to [1.15.1](https://github.com/rubocop/rubocop-performance/releases/tag/v1.15.1)
data/Gemfile.lock CHANGED
@@ -1,7 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- standard (1.18.1)
4
+ standard (1.19.1)
5
+ language_server-protocol (~> 3.17.0.2)
5
6
  rubocop (= 1.39.0)
6
7
  rubocop-performance (= 1.15.1)
7
8
 
@@ -12,11 +13,12 @@ GEM
12
13
  coderay (1.1.3)
13
14
  docile (1.4.0)
14
15
  gimme (0.5.0)
15
- json (2.6.2)
16
+ json (2.6.3)
17
+ language_server-protocol (3.17.0.2)
16
18
  method_source (1.0.0)
17
19
  minitest (5.16.3)
18
20
  parallel (1.22.1)
19
- parser (3.1.2.1)
21
+ parser (3.1.3.0)
20
22
  ast (~> 2.4.1)
21
23
  pry (0.14.1)
22
24
  coderay (~> 1.1)
@@ -35,7 +37,7 @@ GEM
35
37
  rubocop-ast (>= 1.23.0, < 2.0)
36
38
  ruby-progressbar (~> 1.7)
37
39
  unicode-display_width (>= 1.4.0, < 3.0)
38
- rubocop-ast (1.23.0)
40
+ rubocop-ast (1.24.0)
39
41
  parser (>= 3.1.1.0)
40
42
  rubocop-performance (1.15.1)
41
43
  rubocop (>= 1.7.0, < 2.0)
@@ -63,4 +65,4 @@ DEPENDENCIES
63
65
  standard!
64
66
 
65
67
  BUNDLED WITH
66
- 2.3.4
68
+ 2.3.26
data/README.md CHANGED
@@ -432,12 +432,32 @@ information.
432
432
  ## How do I run Standard in my editor?
433
433
 
434
434
  It can be very handy to know about failures while editing to shorten the
435
- feedback loop. Some editors support asynchronously running linters.
435
+ feedback loop.
436
+
437
+ ### Language Server Protocol support
438
+
439
+ To provide immediate feedback of Standard violations and support autofixing
440
+ of your code while avoiding the performance cost of starting and stopping the
441
+ `standardrb` binary repeatedly, Standard Ruby ships with a built-in [Language
442
+ Server Protocol](https://microsoft.github.io/language-server-protocol/) server,
443
+ which is powered by the [language_server-protocol
444
+ gem](https://github.com/mtsmfm/language_server-protocol-ruby) and can be
445
+ activated from the command line with the `--lsp` flag.
446
+
447
+ Most likely, you'd instantiate this server indirectly in your editor's
448
+ configuration, as can be demonstrated easily with
449
+ [neovim](https://github.com/testdouble/standard/wiki/IDE:-neovim).
450
+ Theoretically, this feature could be leveraged by a purpose-built editor plugin
451
+ to performantly format and fix your code. (If you're looking for a project, we'd
452
+ love to see one created for VS Code!)
453
+
454
+ ### Editor-specific guides
436
455
 
437
456
  - [Atom](https://github.com/testdouble/standard/wiki/IDE:-Atom)
438
457
  - [emacs (via flycheck)](https://github.com/julianrubisch/flycheck-standardrb)
439
458
  - [RubyMine](https://www.jetbrains.com/help/ruby/rubocop.html#disable_rubocop)
440
459
  - [vim (via ALE)](https://github.com/testdouble/standard/wiki/IDE:-vim)
460
+ - [neovim (via LSP)](https://github.com/testdouble/standard/wiki/IDE:-neovim)
441
461
  - [VS Code](https://github.com/testdouble/standard/wiki/IDE:-vscode)
442
462
 
443
463
  ## Why aren't `frozen_string_literal: true` magic comments enforced?
@@ -32,7 +32,7 @@ module Standard
32
32
  default_ignores: standard_yaml.key?("default_ignores") ? !!standard_yaml["default_ignores"] : true,
33
33
  config_root: yaml_path ? Pathname.new(yaml_path).dirname.to_s : nil,
34
34
  todo_file: todo_path,
35
- todo_ignore_files: (todo_yaml["ignore"] || []).map { |f| Hash === f ? f.keys.first : f }
35
+ todo_ignore_files: (todo_yaml["ignore"] || []).map { |f| (Hash === f) ? f.keys.first : f }
36
36
  }
37
37
  end
38
38
 
@@ -0,0 +1,144 @@
1
+ require "language_server-protocol"
2
+ require_relative "standardizer"
3
+
4
+ module Standard
5
+ module LSP
6
+ class Server
7
+ Proto = LanguageServer::Protocol
8
+ SEV = Proto::Constant::DiagnosticSeverity
9
+
10
+ def self.start(standardizer)
11
+ new(standardizer).start
12
+ end
13
+
14
+ attr_accessor :standardizer, :writer, :reader, :logger, :text_cache, :subscribers
15
+
16
+ def initialize(standardizer)
17
+ self.standardizer = standardizer
18
+ self.writer = Proto::Transport::Io::Writer.new($stdout)
19
+ self.reader = Proto::Transport::Io::Reader.new($stdin)
20
+ self.logger = $stderr
21
+ self.text_cache = {}
22
+
23
+ self.subscribers = {
24
+ "initialize" => ->(request) {
25
+ init_result = Proto::Interface::InitializeResult.new(
26
+ capabilities: Proto::Interface::ServerCapabilities.new(
27
+ document_formatting_provider: true,
28
+ diagnostic_provider: true,
29
+ text_document_sync: Proto::Constant::TextDocumentSyncKind::FULL
30
+ )
31
+ )
32
+ writer.write(id: request[:id], result: init_result)
33
+ },
34
+
35
+ "initialized" => ->(request) { logger.puts "standard v#{Standard::VERSION} initialized, pid #{Process.pid}" },
36
+
37
+ "shutdown" => ->(request) {
38
+ logger.puts "asked to shutdown, exiting..."
39
+ exit
40
+ },
41
+
42
+ "textDocument/didChange" => ->(request) {
43
+ params = request[:params]
44
+ result = diagnostic(params[:textDocument][:uri], params[:contentChanges][0][:text])
45
+ writer.write(result)
46
+ },
47
+
48
+ "textDocument/didOpen" => ->(request) {
49
+ td = request[:params][:textDocument]
50
+ result = diagnostic(td[:uri], td[:text])
51
+ writer.write(result)
52
+ },
53
+
54
+ "textDocument/didClose" => ->(request) {
55
+ text_cache.delete(request.dig(:params, :textDocument, :uri))
56
+ },
57
+
58
+ "textDocument/formatting" => ->(request) {
59
+ uri = request[:params][:textDocument][:uri]
60
+ writer.write({id: request[:id], result: format_file(uri)})
61
+ },
62
+
63
+ "textDocument/didSave" => ->(request) {}
64
+ }
65
+ end
66
+
67
+ def start
68
+ reader.read do |request|
69
+ method = request[:method]
70
+ if (subscriber = subscribers[method])
71
+ subscriber.call(request)
72
+ else
73
+ logger.puts "unknown method: #{method}"
74
+ end
75
+ rescue => e
76
+ logger.puts "error #{e.class} #{e.message[0..100]}"
77
+ logger.puts e.backtrace.inspect
78
+ end
79
+ end
80
+
81
+ def format_file(file_uri)
82
+ text = text_cache[file_uri]
83
+ new_text = standardizer.format(text)
84
+
85
+ if new_text == text
86
+ []
87
+ else
88
+ [{
89
+ newText: new_text,
90
+ range: {
91
+ start: {line: 0, character: 0},
92
+ end: {line: text.count("\n") + 1, character: 0}
93
+ }
94
+ }]
95
+ end
96
+ end
97
+
98
+ def diagnostic(file_uri, text)
99
+ text_cache[file_uri] = text
100
+ offenses = standardizer.offenses(text)
101
+
102
+ lsp_diagnostics = offenses.map { |o|
103
+ code = o[:cop_name]
104
+
105
+ msg = o[:message].delete_prefix(code)
106
+ loc = o[:location]
107
+
108
+ severity = case o[:severity]
109
+ when "error", "fatal"
110
+ SEV::ERROR
111
+ when "warning"
112
+ SEV::WARNING
113
+ when "convention"
114
+ SEV::INFORMATION
115
+ when "refactor", "info"
116
+ SEV::HINT
117
+ else # the above cases fully cover what RuboCop sends at this time
118
+ logger.puts "unknown severity: #{severity.inspect}"
119
+ SEV::HINT
120
+ end
121
+
122
+ {
123
+ code: code,
124
+ message: msg,
125
+ range: {
126
+ start: {character: loc[:start_column] - 1, line: loc[:start_line] - 1},
127
+ end: {character: loc[:last_column] - 1, line: loc[:last_line] - 1}
128
+ },
129
+ severity: severity,
130
+ source: "standard"
131
+ }
132
+ }
133
+
134
+ {
135
+ method: "textDocument/publishDiagnostics",
136
+ params: {
137
+ diagnostics: lsp_diagnostics,
138
+ uri: file_uri
139
+ }
140
+ }
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,53 @@
1
+ require_relative "../runners/rubocop"
2
+ require "tempfile"
3
+
4
+ module Standard
5
+ module LSP
6
+ class Standardizer
7
+ def initialize(config)
8
+ @template_options = config
9
+ @runner = Standard::Runners::Rubocop.new
10
+ end
11
+
12
+ def format(text)
13
+ run_standard(text, format: true)
14
+ end
15
+
16
+ def offenses(text)
17
+ results = run_standard(text, format: false)
18
+ JSON.parse(results, symbolize_names: true).dig(:files, 0, :offenses)
19
+ end
20
+
21
+ private
22
+
23
+ BASENAME = ["source", ".rb"].freeze
24
+ def run_standard(text, format:)
25
+ Tempfile.open(BASENAME) do |temp|
26
+ temp.write(text)
27
+ temp.flush
28
+ stdout = capture_rubocop_stdout(make_config(temp.path, format))
29
+ format ? File.read(temp.path) : stdout
30
+ end
31
+ end
32
+
33
+ def make_config(file, format)
34
+ # Can't make frozen versions of this hash because RuboCop mutates it
35
+ o = if format
36
+ {autocorrect: true, formatters: [["Standard::Formatter", nil]], parallel: true, todo_file: nil, todo_ignore_files: [], safe_autocorrect: true}
37
+ else
38
+ {autocorrect: false, formatters: [["json"]], parallel: true, todo_file: nil, todo_ignore_files: [], format: "json"}
39
+ end
40
+ Standard::Config.new(@template_options.runner, [file], o, @template_options.rubocop_config_store)
41
+ end
42
+
43
+ def capture_rubocop_stdout(config)
44
+ redir = StringIO.new
45
+ $stdout = redir
46
+ @runner.call(config)
47
+ redir.string
48
+ ensure
49
+ $stdout = STDOUT
50
+ end
51
+ end
52
+ end
53
+ end
@@ -20,7 +20,7 @@ module Standard
20
20
 
21
21
  def separate_argv(argv)
22
22
  argv.partition do |flag|
23
- ["--generate-todo", "--fix", "--no-fix", "--version", "-v", "--help", "-h"].include?(flag)
23
+ ["--generate-todo", "--fix", "--no-fix", "--version", "-v", "--help", "-h", "--lsp"].include?(flag)
24
24
  end
25
25
  end
26
26
 
@@ -41,6 +41,8 @@ module Standard
41
41
  :version
42
42
  elsif (argv & ["--generate-todo"]).any?
43
43
  :genignore
44
+ elsif (argv & ["--lsp"]).any?
45
+ :lsp
44
46
  else
45
47
  :rubocop
46
48
  end
@@ -4,8 +4,8 @@ module Standard
4
4
  module Runners
5
5
  class Help
6
6
  def call(config)
7
- puts <<-MESSAGE.gsub(/^ {10}/, "")
8
- Usage: standardrb [--fix] [-vh] [--format <name>] [--] [FILE]...
7
+ puts <<~MESSAGE
8
+ Usage: standardrb [--fix] [--lsp] [-vh] [--format <name>] [--] [FILE]...
9
9
 
10
10
  Options:
11
11
 
@@ -13,6 +13,7 @@ module Standard
13
13
  --no-fix Do not automatically fix failures
14
14
  --format <name> Format output with any RuboCop formatter (e.g. "json")
15
15
  --generate-todo Create a .standard_todo.yml that lists all the files that contain errors
16
+ --lsp Start a LSP server listening on STDIN
16
17
  -v, --version Print the version of Standard
17
18
  -h, --help Print this message
18
19
  FILE Files to lint [default: ./]
@@ -0,0 +1,12 @@
1
+ require_relative "../lsp/server"
2
+
3
+ module Standard
4
+ module Runners
5
+ class Lsp
6
+ def call(config)
7
+ standardizer = Standard::LSP::Standardizer.new(config)
8
+ Standard::LSP::Server.start(standardizer)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -1,3 +1,3 @@
1
1
  module Standard
2
- VERSION = Gem::Version.new("1.18.1")
2
+ VERSION = Gem::Version.new("1.19.1")
3
3
  end
data/standard.gemspec CHANGED
@@ -21,4 +21,7 @@ Gem::Specification.new do |spec|
21
21
 
22
22
  spec.add_dependency "rubocop", "1.39.0"
23
23
  spec.add_dependency "rubocop-performance", "1.15.1"
24
+
25
+ # not semver: first three are lsp protocol version, last is patch
26
+ spec.add_dependency "language_server-protocol", "~> 3.17.0.2"
24
27
  end
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.18.1
4
+ version: 1.19.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Searls
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-11-21 00:00:00.000000000 Z
11
+ date: 2022-12-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
@@ -38,7 +38,21 @@ dependencies:
38
38
  - - '='
39
39
  - !ruby/object:Gem::Version
40
40
  version: 1.15.1
41
- description:
41
+ - !ruby/object:Gem::Dependency
42
+ name: language_server-protocol
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 3.17.0.2
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 3.17.0.2
55
+ description:
42
56
  email:
43
57
  - searls@gmail.com
44
58
  executables:
@@ -87,6 +101,8 @@ files:
87
101
  - lib/standard/formatter.rb
88
102
  - lib/standard/loads_runner.rb
89
103
  - lib/standard/loads_yaml_config.rb
104
+ - lib/standard/lsp/server.rb
105
+ - lib/standard/lsp/standardizer.rb
90
106
  - lib/standard/merges_settings.rb
91
107
  - lib/standard/parses_cli_option.rb
92
108
  - lib/standard/railtie.rb
@@ -94,6 +110,7 @@ files:
94
110
  - lib/standard/rubocop/ext.rb
95
111
  - lib/standard/runners/genignore.rb
96
112
  - lib/standard/runners/help.rb
113
+ - lib/standard/runners/lsp.rb
97
114
  - lib/standard/runners/rubocop.rb
98
115
  - lib/standard/runners/version.rb
99
116
  - lib/standard/version.rb
@@ -101,7 +118,7 @@ files:
101
118
  homepage: https://github.com/testdouble/standard
102
119
  licenses: []
103
120
  metadata: {}
104
- post_install_message:
121
+ post_install_message:
105
122
  rdoc_options: []
106
123
  require_paths:
107
124
  - lib
@@ -116,8 +133,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
116
133
  - !ruby/object:Gem::Version
117
134
  version: '0'
118
135
  requirements: []
119
- rubygems_version: 3.1.6
120
- signing_key:
136
+ rubygems_version: 3.3.20
137
+ signing_key:
121
138
  specification_version: 4
122
139
  summary: Ruby Style Guide, with linter & automatic code fixer
123
140
  test_files: []