ruby-lsp 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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