standard 1.18.1 → 1.19.1
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|