ruby-lsp 0.0.3 → 0.0.4

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.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +6 -0
  3. data/.rubocop.yml +16 -0
  4. data/CHANGELOG.md +13 -0
  5. data/Gemfile +8 -5
  6. data/Gemfile.lock +55 -10
  7. data/README.md +40 -0
  8. data/VERSION +1 -1
  9. data/bin/tapioca +29 -0
  10. data/dev.yml +3 -0
  11. data/exe/ruby-lsp +19 -4
  12. data/lib/internal.rb +7 -0
  13. data/lib/ruby-lsp.rb +1 -0
  14. data/lib/ruby_lsp/cli.rb +12 -5
  15. data/lib/ruby_lsp/document.rb +37 -14
  16. data/lib/ruby_lsp/handler.rb +78 -23
  17. data/lib/ruby_lsp/requests/base_request.rb +11 -0
  18. data/lib/ruby_lsp/requests/code_actions.rb +1 -0
  19. data/lib/ruby_lsp/requests/diagnostics.rb +1 -0
  20. data/lib/ruby_lsp/requests/document_highlight.rb +96 -0
  21. data/lib/ruby_lsp/requests/document_symbol.rb +1 -10
  22. data/lib/ruby_lsp/requests/folding_ranges.rb +3 -2
  23. data/lib/ruby_lsp/requests/formatting.rb +2 -1
  24. data/lib/ruby_lsp/requests/rubocop_request.rb +1 -0
  25. data/lib/ruby_lsp/requests/selection_ranges.rb +1 -0
  26. data/lib/ruby_lsp/requests/semantic_highlighting.rb +17 -3
  27. data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +1 -0
  28. data/lib/ruby_lsp/requests/support/selection_range.rb +1 -0
  29. data/lib/ruby_lsp/requests/support/semantic_token_encoder.rb +12 -1
  30. data/lib/ruby_lsp/requests/support/syntax_error_diagnostic.rb +1 -0
  31. data/lib/ruby_lsp/requests.rb +2 -0
  32. data/lib/ruby_lsp/store.rb +19 -3
  33. data/rakelib/check_docs.rake +4 -1
  34. data/ruby-lsp.gemspec +1 -0
  35. data/sorbet/config +4 -0
  36. data/sorbet/rbi/.rubocop.yml +8 -0
  37. data/sorbet/rbi/gems/ansi@1.5.0.rbi +338 -0
  38. data/sorbet/rbi/gems/ast@2.4.2.rbi +522 -0
  39. data/sorbet/rbi/gems/builder@3.2.4.rbi +418 -0
  40. data/sorbet/rbi/gems/coderay@1.1.3.rbi +8 -0
  41. data/sorbet/rbi/gems/debug@1.5.0.rbi +1273 -0
  42. data/sorbet/rbi/gems/diff-lcs@1.5.0.rbi +867 -0
  43. data/sorbet/rbi/gems/io-console@0.5.11.rbi +8 -0
  44. data/sorbet/rbi/gems/irb@1.4.1.rbi +376 -0
  45. data/sorbet/rbi/gems/language_server-protocol@3.16.0.3.rbi +7325 -0
  46. data/sorbet/rbi/gems/method_source@1.0.0.rbi +8 -0
  47. data/sorbet/rbi/gems/minitest-reporters@1.5.0.rbi +612 -0
  48. data/sorbet/rbi/gems/minitest@5.15.0.rbi +994 -0
  49. data/sorbet/rbi/gems/parallel@1.22.1.rbi +163 -0
  50. data/sorbet/rbi/gems/parser@3.1.2.0.rbi +3968 -0
  51. data/sorbet/rbi/gems/prettier_print@0.1.0.rbi +734 -0
  52. data/sorbet/rbi/gems/pry@0.14.1.rbi +8 -0
  53. data/sorbet/rbi/gems/rainbow@3.1.1.rbi +227 -0
  54. data/sorbet/rbi/gems/rake@13.0.6.rbi +1853 -0
  55. data/sorbet/rbi/gems/rbi@0.0.14.rbi +2337 -0
  56. data/sorbet/rbi/gems/regexp_parser@2.5.0.rbi +1854 -0
  57. data/sorbet/rbi/gems/reline@0.3.1.rbi +1274 -0
  58. data/sorbet/rbi/gems/rexml@3.2.5.rbi +3852 -0
  59. data/sorbet/rbi/gems/rubocop-ast@1.18.0.rbi +4180 -0
  60. data/sorbet/rbi/gems/rubocop-minitest@0.20.0.rbi +1369 -0
  61. data/sorbet/rbi/gems/rubocop-rake@0.6.0.rbi +246 -0
  62. data/sorbet/rbi/gems/rubocop-shopify@2.6.0.rbi +8 -0
  63. data/sorbet/rbi/gems/rubocop-sorbet@0.6.8.rbi +652 -0
  64. data/sorbet/rbi/gems/rubocop@1.30.0.rbi +36729 -0
  65. data/sorbet/rbi/gems/ruby-progressbar@1.11.0.rbi +732 -0
  66. data/sorbet/rbi/gems/spoom@1.1.11.rbi +1600 -0
  67. data/sorbet/rbi/gems/syntax_tree@2.7.1.rbi +6777 -0
  68. data/sorbet/rbi/gems/tapioca@0.8.1.rbi +1972 -0
  69. data/sorbet/rbi/gems/thor@1.2.1.rbi +2921 -0
  70. data/sorbet/rbi/gems/unicode-display_width@2.1.0.rbi +27 -0
  71. data/sorbet/rbi/gems/unparser@0.6.5.rbi +2789 -0
  72. data/sorbet/rbi/gems/webrick@1.7.0.rbi +1779 -0
  73. data/sorbet/rbi/gems/yard-sorbet@0.6.1.rbi +289 -0
  74. data/sorbet/rbi/gems/yard@0.9.27.rbi +13048 -0
  75. data/sorbet/rbi/shims/fiddle.rbi +4 -0
  76. data/sorbet/rbi/shims/hash.rbi +6 -0
  77. data/sorbet/rbi/shims/rdoc.rbi +4 -0
  78. data/sorbet/tapioca/config.yml +13 -0
  79. data/sorbet/tapioca/require.rb +7 -0
  80. metadata +64 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 58ed87185da0a5d1da74b10f1525f1ca1341f1001f3a4cbdf2b086dd93750ad9
4
- data.tar.gz: 1210f736e4cd8450cbe1e1d796dbd22a889c244c6ea5902bc6082f3791064ddc
3
+ metadata.gz: ab0e94532c080cf6e443c95d9ca7ccb16f548ec45768dc58e95fd691c907a965
4
+ data.tar.gz: 856df7b413ef111e100ee42da541856843d966184f9dbe1dfe2ee5a50da1e802
5
5
  SHA512:
6
- metadata.gz: a1ed47a3e4d53dbf5250beaa98b3095c89099e67829f2ecac3149b34ecc87ae579c67ed6cd67035ee9930c0fffa0db6c0d4fdc3c3398520196005b180f28ea6f
7
- data.tar.gz: 18d07a7c5426fa8cfad11cfab44dbabf05fd3a1352f1bf9272b04fb35c78f0bb0b4860dd4b7bbfda89efb9cfa99fc3ef77fbb679ff2b21bbd4cffb3c53a14bd5
6
+ metadata.gz: fde4cd9c5e556ff926b22d316d1bfcc5d31c089850d4558ac7d954fe33df4c8d2b8f8c14e55d1dcc2898087d0d29e8b12fc2f768e2b14935fa727f9620ff5c9e
7
+ data.tar.gz: 24fb12213f36edcee13fe65d53a94977737b251566d2503dc857dc276192d6f570f93147f57fc5e3b23c8d90b2c1f96f4cc7e308d5b969a02705d39444676f95
@@ -17,9 +17,15 @@ jobs:
17
17
  with:
18
18
  ruby-version: ${{ matrix.ruby }}
19
19
  bundler-cache: true
20
+
20
21
  - name: Check if documentation is up to date
21
22
  run: bundle exec rake check_docs
23
+
24
+ - name: Typecheck
25
+ run: bundle exec srb tc
26
+
22
27
  - name: Lint Ruby files
23
28
  run: bin/rubocop
29
+
24
30
  - name: Run tests
25
31
  run: bin/test
data/.rubocop.yml CHANGED
@@ -1,6 +1,11 @@
1
1
  inherit_gem:
2
2
  rubocop-shopify: rubocop.yml
3
3
 
4
+ require:
5
+ - rubocop-sorbet
6
+ - rubocop-minitest
7
+ - rubocop-rake
8
+
4
9
  AllCops:
5
10
  NewCops: disable
6
11
  SuggestExtensions: false
@@ -8,7 +13,18 @@ AllCops:
8
13
  Exclude:
9
14
  - "vendor/**/*"
10
15
  - "features/**/*"
16
+ - "test/fixtures/**/*"
11
17
 
12
18
  Naming/FileName:
13
19
  Exclude:
14
20
  - "lib/ruby-lsp.rb"
21
+
22
+ Sorbet/FalseSigil:
23
+ Enabled: false
24
+
25
+ Sorbet/TrueSigil:
26
+ Enabled: true
27
+ Include:
28
+ - "**/*.rb"
29
+ Exclude:
30
+ - "**/*.rake"
data/CHANGELOG.md CHANGED
@@ -6,6 +6,19 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.0.4]
10
+
11
+ - Add basic document highlight (https://github.com/Shopify/ruby-lsp/pull/91)
12
+ - Add error telemetry (https://github.com/Shopify/ruby-lsp/pull/100)
13
+ - Always push telemetry events from the server (https://github.com/Shopify/ruby-lsp/pull/109)
14
+ - Fix multibyte character handling (https://github.com/Shopify/ruby-lsp/pull/122)
15
+ - Add Sorbet to the Ruby LSP (https://github.com/Shopify/ruby-lsp/pull/119, https://github.com/Shopify/ruby-lsp/pull/123)
16
+
17
+ ## [0.0.3]
18
+
19
+ - Fixed code actions return hanging
20
+ - Moved to incremental text synchronization
21
+ - Added syntax error resiliency
9
22
 
10
23
  ## [0.0.2]
11
24
 
data/Gemfile CHANGED
@@ -4,11 +4,14 @@ source "https://rubygems.org"
4
4
 
5
5
  gemspec
6
6
 
7
- gem "debug", "~> 1.5"
7
+ gem "debug", "~> 1.5", require: false
8
8
  gem "minitest", "~> 5.15"
9
9
  gem "minitest-reporters", "~> 1.5"
10
10
  gem "rake", "~> 13.0"
11
- gem "rubocop-shopify", "~> 2.6"
12
- gem "rubocop-minitest", "~> 0.19.1"
13
- gem "rubocop-rake", "~> 0.6.0"
14
- gem "yard", "~> 0.9"
11
+ gem "rubocop-shopify", "~> 2.7", require: false
12
+ gem "rubocop-minitest", "~> 0.20.0", require: false
13
+ gem "rubocop-rake", "~> 0.6.0", require: false
14
+ gem "rubocop-sorbet", "~> 0.6", require: false
15
+ gem "sorbet-static-and-runtime"
16
+ gem "tapioca", "~> 0.8", require: false
17
+ gem "yard", "~> 0.9", require: false
data/Gemfile.lock CHANGED
@@ -1,9 +1,10 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ruby-lsp (0.0.3)
4
+ ruby-lsp (0.0.4)
5
5
  language_server-protocol
6
6
  rubocop (>= 1.0)
7
+ sorbet-runtime
7
8
  syntax_tree (>= 2.3)
8
9
 
9
10
  GEM
@@ -12,13 +13,16 @@ GEM
12
13
  ansi (1.5.0)
13
14
  ast (2.4.2)
14
15
  builder (3.2.4)
16
+ coderay (1.1.3)
15
17
  debug (1.5.0)
16
18
  irb (>= 1.3.6)
17
19
  reline (>= 0.2.7)
20
+ diff-lcs (1.5.0)
18
21
  io-console (0.5.11)
19
22
  irb (1.4.1)
20
23
  reline (>= 0.3.0)
21
24
  language_server-protocol (3.16.0.3)
25
+ method_source (1.0.0)
22
26
  minitest (5.15.0)
23
27
  minitest-reporters (1.5.0)
24
28
  ansi
@@ -29,36 +33,74 @@ GEM
29
33
  parser (3.1.2.0)
30
34
  ast (~> 2.4.1)
31
35
  prettier_print (0.1.0)
36
+ pry (0.14.1)
37
+ coderay (~> 1.1)
38
+ method_source (~> 1.0)
32
39
  rainbow (3.1.1)
33
40
  rake (13.0.6)
34
- regexp_parser (2.4.0)
41
+ rbi (0.0.14)
42
+ ast
43
+ parser (>= 2.6.4.0)
44
+ sorbet-runtime (>= 0.5.9204)
45
+ unparser
46
+ regexp_parser (2.5.0)
35
47
  reline (0.3.1)
36
48
  io-console (~> 0.5)
37
49
  rexml (3.2.5)
38
- rubocop (1.29.1)
50
+ rubocop (1.30.0)
39
51
  parallel (~> 1.10)
40
52
  parser (>= 3.1.0.0)
41
53
  rainbow (>= 2.2.2, < 4.0)
42
54
  regexp_parser (>= 1.8, < 3.0)
43
55
  rexml (>= 3.2.5, < 4.0)
44
- rubocop-ast (>= 1.17.0, < 2.0)
56
+ rubocop-ast (>= 1.18.0, < 2.0)
45
57
  ruby-progressbar (~> 1.7)
46
58
  unicode-display_width (>= 1.4.0, < 3.0)
47
59
  rubocop-ast (1.18.0)
48
60
  parser (>= 3.1.1.0)
49
- rubocop-minitest (0.19.1)
61
+ rubocop-minitest (0.20.0)
50
62
  rubocop (>= 0.90, < 2.0)
51
63
  rubocop-rake (0.6.0)
52
64
  rubocop (~> 1.0)
53
- rubocop-shopify (2.6.0)
54
- rubocop (~> 1.29)
65
+ rubocop-shopify (2.7.0)
66
+ rubocop (~> 1.30)
67
+ rubocop-sorbet (0.6.8)
68
+ rubocop (>= 0.90.0)
55
69
  ruby-progressbar (1.11.0)
70
+ sorbet (0.5.10073)
71
+ sorbet-static (= 0.5.10073)
72
+ sorbet-runtime (0.5.10073)
73
+ sorbet-static (0.5.10073-universal-darwin-21)
74
+ sorbet-static (0.5.10073-x86_64-linux)
75
+ sorbet-static-and-runtime (0.5.10073)
76
+ sorbet (= 0.5.10073)
77
+ sorbet-runtime (= 0.5.10073)
78
+ spoom (1.1.11)
79
+ sorbet (>= 0.5.9204)
80
+ sorbet-runtime (>= 0.5.9204)
81
+ thor (>= 0.19.2)
56
82
  syntax_tree (2.7.1)
57
83
  prettier_print
84
+ tapioca (0.8.1)
85
+ bundler (>= 1.17.3)
86
+ parallel (>= 1.21.0)
87
+ pry (>= 0.12.2)
88
+ rbi (~> 0.0.0, >= 0.0.14)
89
+ sorbet-static-and-runtime (>= 0.5.9204)
90
+ spoom (~> 1.1.0, >= 1.1.11)
91
+ thor (>= 1.2.0)
92
+ yard-sorbet
93
+ thor (1.2.1)
58
94
  unicode-display_width (2.1.0)
95
+ unparser (0.6.5)
96
+ diff-lcs (~> 1.3)
97
+ parser (>= 3.1.0)
59
98
  webrick (1.7.0)
60
- yard (0.9.27)
99
+ yard (0.9.28)
61
100
  webrick (~> 1.7.0)
101
+ yard-sorbet (0.6.1)
102
+ sorbet-runtime (>= 0.5)
103
+ yard (>= 0.9)
62
104
 
63
105
  PLATFORMS
64
106
  arm64-darwin-21
@@ -69,10 +111,13 @@ DEPENDENCIES
69
111
  minitest (~> 5.15)
70
112
  minitest-reporters (~> 1.5)
71
113
  rake (~> 13.0)
72
- rubocop-minitest (~> 0.19.1)
114
+ rubocop-minitest (~> 0.20.0)
73
115
  rubocop-rake (~> 0.6.0)
74
- rubocop-shopify (~> 2.6)
116
+ rubocop-shopify (~> 2.7)
117
+ rubocop-sorbet (~> 0.6)
75
118
  ruby-lsp!
119
+ sorbet-static-and-runtime
120
+ tapioca (~> 0.8)
76
121
  yard (~> 0.9)
77
122
 
78
123
  BUNDLED WITH
data/README.md CHANGED
@@ -17,6 +17,8 @@ end
17
17
  If using VS Code, install the [Ruby LSP plugin](https://github.com/Shopify/vscode-ruby-lsp) to get the extra features in
18
18
  the editor.
19
19
 
20
+ See the [documentation](https://shopify.github.io/ruby-lsp) for supported features.
21
+
20
22
  ## Contributing
21
23
 
22
24
  Bug reports and pull requests are welcome on GitHub at https://github.com/Shopify/ruby-lsp.
@@ -25,6 +27,44 @@ are expected to adhere to the
25
27
  [Contributor Covenant](https://github.com/Shopify/ruby-lsp/blob/main/CODE_OF_CONDUCT.md)
26
28
  code of conduct.
27
29
 
30
+ ### Expectation testing
31
+
32
+ To simplify the way we run tests over different pieces of Ruby code, we use a custom expectations test framework against a set of Ruby fixtures.
33
+
34
+ To add a new fixture to the expectations test suite:
35
+
36
+ 1. Add a new fixture `my_fixture.rb` file under `test/fixtures`
37
+ 2. (optional) Add new expectations under `test/expectations/$HANDLER` for the request handlers you're concerned by
38
+ 3. Profit by running `bin/test test/requests/$HANDLER_expectations_test my_fixture`
39
+ * Handlers for which you added expectations will be checked with `assert_expectations`
40
+ * Handlers without expectations will be ran against your new test to check that nothing breaks
41
+
42
+ To add a new expectations test runner for a new request handler:
43
+
44
+ 1. Add a new file under `test/requests/$HANDLER_expectations_test.rb` that subclasses `ExpectationsTestRunner` and calls `expectations_tests $HANDLER, "$EXPECTATIONS_DIR"` where: `$HANDLER` is the fully qualified name or your handler class and `$EXPECTATIONS_DIR` is the directory name where you want to store the expectation files.
45
+
46
+ ```rb
47
+ # frozen_string_literal: true
48
+
49
+ require "test_helper"
50
+ require "expectations/expectations_test_runner"
51
+
52
+ class $HANDLERExpectationsTest < ExpectationsTestRunner
53
+ expectations_tests RubyLsp::Requests::$HANDLER, "$EXPECTATIONS_DIR"
54
+ end
55
+ ```
56
+
57
+ 2. (optional) Override the `run_expectations` and `assert_expectations` methods if needed. See the different request handler expectations runners under `test/requests/*_expectations_test.rb` for examples.
58
+
59
+ 4. (optional) Add new fixtures for your handler under `test/fixtures`
60
+
61
+ 5. (optional) Add new expectations under `test/expectations/$HANDLER`
62
+ * No need to write the expectations by hand, just run the test with an empty expectation file and copy from the output.
63
+
64
+ 7. Profit by running, `bin/test test/expectations_test $HANDLER`
65
+ * Tests with expectations will be checked with `assert_expectations`
66
+ * Tests without expectations will be ran against your new $HANDLER to check that nothing breaks
67
+
28
68
  ## Debugging
29
69
 
30
70
  ### Tracing LSP requests and responses
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.3
1
+ 0.0.4
data/bin/tapioca ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'tapioca' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("tapioca", "tapioca")
data/dev.yml CHANGED
@@ -10,6 +10,9 @@ up:
10
10
  commands:
11
11
  server: exe/ruby-lsp
12
12
  style: bin/rubocop
13
+ typecheck:
14
+ aliases: ["tc"]
15
+ run: "bundle exec srb tc"
13
16
  test:
14
17
  syntax:
15
18
  argument: file
data/exe/ruby-lsp CHANGED
@@ -1,8 +1,23 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require "syntax_tree"
5
- require "ruby-lsp"
6
- require "ruby_lsp/cli"
4
+ require "sorbet-runtime"
7
5
 
8
- RubyLsp::Cli.start(ARGV)
6
+ begin
7
+ T::Configuration.default_checked_level = :never
8
+ # Suppresses call validation errors
9
+ T::Configuration.call_validation_error_handler = ->(*) {}
10
+ # Suppresses errors caused by T.cast, T.let, T.must, etc.
11
+ T::Configuration.inline_type_error_handler = ->(*) {}
12
+ # Suppresses errors caused by incorrect parameter ordering
13
+ T::Configuration.sig_validation_error_handler = ->(*) {}
14
+ rescue
15
+ # Need this rescue so that if another gem has
16
+ # already set the checked level by the time we
17
+ # get to it, we don't fail outright.
18
+ nil
19
+ end
20
+
21
+ require_relative "../lib/internal"
22
+
23
+ RubyLsp::Cli.start
data/lib/internal.rb ADDED
@@ -0,0 +1,7 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+ require "syntax_tree"
6
+ require "ruby-lsp"
7
+ require "ruby_lsp/cli"
data/lib/ruby-lsp.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module RubyLsp
data/lib/ruby_lsp/cli.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  require "language_server-protocol"
@@ -6,7 +7,10 @@ require_relative "handler"
6
7
 
7
8
  module RubyLsp
8
9
  module Cli
9
- def self.start(_argv)
10
+ extend T::Sig
11
+
12
+ sig { void }
13
+ def self.start
10
14
  handler = RubyLsp::Handler.new
11
15
 
12
16
  handler.config do
@@ -14,7 +18,6 @@ module RubyLsp
14
18
  store.clear
15
19
  initialization_options = request.dig(:params, :initializationOptions)
16
20
 
17
- configure_options(initialization_options)
18
21
  respond_with_capabilities(initialization_options.fetch(:enabledFeatures, []))
19
22
  end
20
23
 
@@ -23,7 +26,7 @@ module RubyLsp
23
26
  store.push_edits(uri, request.dig(:params, :contentChanges))
24
27
 
25
28
  send_diagnostics(uri)
26
- nil
29
+ RubyLsp::Handler::VOID
27
30
  end
28
31
 
29
32
  on("textDocument/didOpen") do |request|
@@ -32,14 +35,14 @@ module RubyLsp
32
35
  store.set(uri, text)
33
36
 
34
37
  send_diagnostics(uri)
35
- nil
38
+ RubyLsp::Handler::VOID
36
39
  end
37
40
 
38
41
  on("textDocument/didClose") do |request|
39
42
  uri = request.dig(:params, :textDocument, :uri)
40
43
  store.delete(uri)
41
44
 
42
- nil
45
+ RubyLsp::Handler::VOID
43
46
  end
44
47
 
45
48
  on("textDocument/documentSymbol") do |request|
@@ -65,6 +68,10 @@ module RubyLsp
65
68
  respond_with_formatting(request.dig(:params, :textDocument, :uri))
66
69
  end
67
70
 
71
+ on("textDocument/documentHighlight") do |request|
72
+ respond_with_document_highlight(request.dig(:params, :textDocument, :uri), request.dig(:params, :position))
73
+ end
74
+
68
75
  on("textDocument/codeAction") do |request|
69
76
  range = request.dig(:params, :range)
70
77
  start_line = range.dig(:start, :line)
@@ -1,32 +1,48 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
- require "strscan"
4
-
5
4
  module RubyLsp
6
5
  class Document
7
- attr_reader :tree, :source, :syntax_error_edits
6
+ extend T::Sig
7
+
8
+ PositionShape = T.type_alias { { line: Integer, character: Integer } }
9
+ RangeShape = T.type_alias { { start: PositionShape, end: PositionShape } }
10
+ EditShape = T.type_alias { { range: RangeShape, text: String } }
11
+
12
+ sig { returns(SyntaxTree::Node) }
13
+ attr_reader :tree
8
14
 
15
+ sig { returns(String) }
16
+ attr_reader :source
17
+
18
+ sig { returns(T::Array[EditShape]) }
19
+ attr_reader :syntax_error_edits
20
+
21
+ sig { params(source: String).void }
9
22
  def initialize(source)
10
- @tree = SyntaxTree.parse(source)
11
- @cache = {}
12
- @syntax_error_edits = []
23
+ @tree = T.let(SyntaxTree.parse(source), SyntaxTree::Node)
24
+ @cache = T.let({}, T::Hash[Symbol, T.untyped])
25
+ @syntax_error_edits = T.let([], T::Array[EditShape])
13
26
  @source = source
14
- @parsable_source = source.dup
27
+ @parsable_source = T.let(source.dup, String)
15
28
  end
16
29
 
30
+ sig { params(other: Document).returns(T::Boolean) }
17
31
  def ==(other)
18
32
  @source == other.source
19
33
  end
20
34
 
21
- def cache_fetch(request_name)
35
+ sig { params(request_name: Symbol, block: T.proc.params(document: Document).returns(T.untyped)).returns(T.untyped) }
36
+ def cache_fetch(request_name, &block)
22
37
  cached = @cache[request_name]
23
38
  return cached if cached
24
39
 
25
- result = yield(self)
40
+ result = block.call(self)
26
41
  @cache[request_name] = result
27
42
  result
28
43
  end
29
44
 
45
+ sig { params(edits: T::Array[EditShape]).void }
30
46
  def push_edits(edits)
31
47
  # Apply the edits on the real source
32
48
  edits.each { |edit| apply_edit(@source, edit[:range], edit[:text]) }
@@ -40,12 +56,14 @@ module RubyLsp
40
56
  update_parsable_source(edits)
41
57
  end
42
58
 
59
+ sig { returns(T::Boolean) }
43
60
  def syntax_errors?
44
61
  @syntax_error_edits.any?
45
62
  end
46
63
 
47
64
  private
48
65
 
66
+ sig { params(edits: T::Array[EditShape]).void }
49
67
  def update_parsable_source(edits)
50
68
  # If the new edits caused a syntax error, make all edits blank spaces and line breaks to adjust the line and
51
69
  # column numbers. This is attempt to make the document parsable while partial edits are being applied
@@ -61,6 +79,7 @@ module RubyLsp
61
79
  # If we can't parse the source even after emptying the edits, then just fallback to the previous source
62
80
  end
63
81
 
82
+ sig { params(source: String, range: RangeShape, text: String).void }
64
83
  def apply_edit(source, range, text)
65
84
  scanner = Scanner.new(source)
66
85
  start_position = scanner.find_position(range[:start])
@@ -70,20 +89,24 @@ module RubyLsp
70
89
  end
71
90
 
72
91
  class Scanner
92
+ extend T::Sig
93
+
94
+ sig { params(source: String).void }
73
95
  def initialize(source)
96
+ @current_line = T.let(0, Integer)
97
+ @pos = T.let(0, Integer)
74
98
  @source = source
75
- @scanner = StringScanner.new(source)
76
- @current_line = 0
77
99
  end
78
100
 
101
+ sig { params(position: PositionShape).returns(Integer) }
79
102
  def find_position(position)
80
- # Move the string scanner counting line breaks until we reach the right line
81
103
  until @current_line == position[:line]
82
- @scanner.scan_until(/\R/)
104
+ @pos += 1 until /\R/.match?(@source[@pos])
105
+ @pos += 1
83
106
  @current_line += 1
84
107
  end
85
108
 
86
- @scanner.pos + position[:character]
109
+ @pos + position[:character]
87
110
  end
88
111
  end
89
112
  end