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 +4 -4
- data/CHANGELOG.md +10 -0
- data/Gemfile.lock +7 -5
- data/README.md +21 -1
- data/lib/standard/loads_yaml_config.rb +1 -1
- data/lib/standard/lsp/server.rb +144 -0
- data/lib/standard/lsp/standardizer.rb +53 -0
- data/lib/standard/merges_settings.rb +3 -1
- data/lib/standard/runners/help.rb +3 -2
- data/lib/standard/runners/lsp.rb +12 -0
- data/lib/standard/version.rb +1 -1
- data/standard.gemspec +3 -0
- metadata +24 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bf52e94f737a041479cf2e741613a0e07d54af0b41f32f12309a94d5a2f0416b
|
4
|
+
data.tar.gz: 745dd891033fdc11271fd1331858a11c74d9e4188385eac5cc53580616aa7bbb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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
|
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: ./]
|
data/lib/standard/version.rb
CHANGED
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.
|
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
|
+
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
|
-
|
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.
|
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: []
|