|
1 | 1 | # CONTRIBUTING |
2 | 2 |
|
3 | | -This repository contains three sub-projects: |
4 | | - |
5 | | -- the **language server** (`ruby-lsp`), which exists at the top level of the repository. Most features are implemented here since everything implemented in the server is available to all editors |
6 | | -- the **VS Code extension**, which exists under the `vscode` directory. Any custom VS Code features are implemented here |
7 | | -- the **documentation** website, which exists under the `jekyll` directory. All user facing documentation for both the Ruby LSP and the Rails addon is contained here |
8 | | - |
9 | | -This contributing guide is split by each component. |
10 | | - |
11 | | -## Initial setup |
12 | | - |
13 | | -To start contributing to the Ruby LSP, ensure that all dependencies are installed as follows: |
14 | | - |
15 | | -- `bundle install` on the top level will install Ruby dependencies |
16 | | -- `bundle install` in the `jekyll` directory will install documentation dependencies |
17 | | -- `yarn install` in the `vscode` directory will install Node.js dependencies for the VS Code extension |
18 | | - |
19 | | -## Contributing to the server |
20 | | - |
21 | | -This is the structure of the `ruby-lsp` gem: |
22 | | - |
23 | | -- `lib/ruby_indexer`: the code indexer to extract declarations from the workspace |
24 | | -- `lib/ruby_lsp/*.rb`: foundational pieces of the language server, such as workers, queues, handling requests and so on |
25 | | -- `lib/ruby_lsp/requests`: request implementation. These match one to one with the [language server specification](https://microsoft.github.io/language-server-protocol/specification) |
26 | | -- `lib/ruby_lsp/listeners`: Prism dispatcher listeners. Most of the server's infrastructure relies on a listener pattern to maximize performance while traversing ASTs. Note that a single request may depend on more than one listener |
27 | | - |
28 | | -When adding or changing an existing feature, first identify which request is responsible for it in the |
29 | | -[specification](https://microsoft.github.io/language-server-protocol/specification). Then identify which file in the |
30 | | -server implements that request and start thinking about the implementation. |
31 | | - |
32 | | -> [!NOTE] |
33 | | -> |
34 | | -> When using VS Code, open the `lsp.code-workspace` file instead of just opening the regular folder. It contains |
35 | | -> configurations for working with the sub projects side by side effectively |
36 | | -
|
37 | | -### Debugging |
38 | | - |
39 | | -#### Live debugging the server |
40 | | - |
41 | | -It is possible to live debug the development instance of the language server that is currently running when using VS |
42 | | -Code: |
43 | | - |
44 | | -1. `CMD/CTRL + SHIFT + P` to open the command palette |
45 | | -2. Search for `Debug the Ruby LSP server`. This command will restart the server in debug mode, allowing you to connect |
46 | | -with a debugger. Note that the debug mode applies only until the editor is closed or Ruby LSP restarts |
47 | | -3. After the server has launched in debug mode, attach the debugger by going in `Run and debug`, selecting the `Attach to existing server` task and clicking run |
48 | | -4. You should now be able to put breakpoints in the UI and triggering requests will stop at those breakpoints |
49 | | - |
50 | | -Caveat: since you are debugging the language server instance that is currently running in your own editor, features will |
51 | | -not be available if the execution is currently suspended at a breakpoint. |
52 | | - |
53 | | -#### Understanding Prism ASTs |
54 | | - |
55 | | -The Ruby LSP uses Prism to parse and understand Ruby code. When working on a feature, it's very common to need to |
56 | | -inspect the structure of the Prism AST for a given code snippet, so that you can understand why a request is being |
57 | | -triggered a certain way. |
58 | | - |
59 | | -If you're using VS Code, you can use the [show syntax tree |
60 | | -command](https://shopify.github.io/ruby-lsp/#show-syntax-tree) to inspect the structure of an AST for an entire document |
61 | | -or selection. |
62 | | - |
63 | | -For other editors, using our IRB configurations is the easiest way of achieving the same: |
64 | | - |
65 | | -1. `bundle exec irb` to launch IRB with our configurations. It will require all libraries for you |
66 | | -2. Then parse the Ruby code you'd like to understand better and start inspecting |
67 | | - |
68 | | -```ruby |
69 | | -source = <<~RUBY |
70 | | - class Foo |
71 | | - def bar |
72 | | - end |
73 | | - end |
74 | | -RUBY |
75 | | - |
76 | | -ast = Prism.parse(source).value |
77 | | -``` |
78 | | - |
79 | | -Check the [Prism documentation](https://ruby.github.io/prism/) for more related information. |
80 | | - |
81 | | -#### Tracing LSP requests and responses |
82 | | - |
83 | | -In VS Code, you can verify what's happening in the server by enabling tracing, which allows for different levels of |
84 | | -logging. |
85 | | - |
86 | | -```jsonc |
87 | | -{ |
88 | | - // Your JSON settings |
89 | | - // |
90 | | - // - `off`: no tracing |
91 | | - // - `messages`: display requests and responses notifications |
92 | | - // - `verbose`: display each request and response as JSON |
93 | | - "ruby lsp.trace.server": "messages" |
94 | | -} |
95 | | -``` |
96 | | - |
97 | | -#### Manually testing a change |
98 | | - |
99 | | -After you made a change or added a new feature, you can verify it in the editor by restarting the language server. In VS |
100 | | -Code, this can be achieved by running the command `Ruby LSP: restart`, which will reboot the server and pick up your |
101 | | -changes. |
102 | | - |
103 | | -For other editors, you must manually restart the language server to pick up the latest changes. |
104 | | - |
105 | | -#### Debugging tests |
106 | | - |
107 | | -In VS Code, we recommend: |
108 | | - |
109 | | -1. Setting breakpoints in the UI |
110 | | -2. Opening the test that will hit that breakpoint |
111 | | -3. Clicking the `debug` code lens button on top of examples |
112 | | - |
113 | | -Alternatively (and for other editors), adding a `binding.b` statement in the code and executing the test in the terminal |
114 | | -will also allow you to debug the code. |
115 | | - |
116 | | -### Writing tests |
117 | | - |
118 | | -There are two types of tests in the Ruby LSP. The first type is likely familiar: standard Minitest files with a bunch of |
119 | | -examples inside using the method declaration syntax. |
120 | | - |
121 | | -The second type of test is our fixture/expectation framework. Adding a new fixture under `test/fixtures` will |
122 | | -automatically make the framework run all requests against that fixture. By default, the framework only checks that the |
123 | | -features don't crash when running against the fixture. This is useful for ensuring that critical requests don't break |
124 | | -when using less common Ruby syntax. |
125 | | - |
126 | | -To go beyond checking if the requests break for a fixture, you can add an expectation to `test/expectations/NAME_OF_THE_REQUEST`, which allows you to assert the expected response for a request and fixture combination. |
127 | | - |
128 | | -For example, if we have a `test/fixtures/foo.rb`, then adding a `test/expectations/semantic_highlighting/foo.exp.json` will make the framework verify that when running semantic highlighting in the `foo.rb` fixture, the `foo.exp.json` response is expected. |
129 | | - |
130 | | -Check existing fixture and expectation combinations for examples. |
131 | | - |
132 | | -#### When to use each type of test |
133 | | - |
134 | | -The fixture/expectation framework is intended to be used mostly by full document requests (language server features that |
135 | | -are computed for the entire file every time). |
136 | | - |
137 | | -Requests and features that are position specific or that operate under a different mechanism should just use regular Minitest tests. |
138 | | - |
139 | | -#### Running the test suite |
140 | | - |
141 | | -There are multiple ways to execute tests available. |
142 | | - |
143 | | -```shell |
144 | | -# Run the entire test suite |
145 | | -bundle exec rake |
146 | | - |
147 | | -# Run only indexing tests |
148 | | -bundle exec rake test:indexer |
149 | | - |
150 | | -# Run only language server tests (excluding indexing) |
151 | | -bundle exec rake test |
152 | | - |
153 | | -# Using the custom test framework to run a specific fixture example |
154 | | -# bin/test test/requests/the_request_you_want_to_run_test.rb name_of_fixture |
155 | | -bin/test test/requests/diagnostics_expectations_test.rb def_bad_formatting |
156 | | -``` |
157 | | - |
158 | | -Additionally, we use RuboCop for linting and Sorbet for type checking. |
159 | | - |
160 | | -```shell |
161 | | -# Run linting |
162 | | -bundle exec rubocop |
163 | | - |
164 | | -# Run type checking |
165 | | -bundle exec srb tc |
166 | | -``` |
167 | | - |
168 | | -## Contributing to the VS Code extension |
169 | | - |
170 | | -Before starting on this section, ensure that [dependencies are installed](#initial-setup). |
171 | | - |
172 | | -In addition to what's described here, the [VS Code extension API documentation](https://code.visualstudio.com/api) is a |
173 | | -great place to gather more context about how extensions interact with the editor. |
174 | | - |
175 | | -The VS Code extension currently has the following main parts: |
176 | | - |
177 | | -- Version manager integrations for Ruby environment activation |
178 | | -- A [ruby/debug](https://github.com/ruby/debug) client implementation |
179 | | -- A [test controller](https://code.visualstudio.com/docs/editor/testing) implementation |
180 | | -- A [Copilot chat participant](https://code.visualstudio.com/api/extension-guides/chat) |
181 | | -- A dependencies tree implementation |
182 | | -- The LSP client |
183 | | -- A workspace abstraction to represent each active workspace in the editor |
184 | | - |
185 | | -### Testing changes |
186 | | - |
187 | | -We try to ensure thorough testing as much as possible. However, some tests are difficult to write, in particular those |
188 | | -that interact with VS Code widgets. |
189 | | - |
190 | | -For example, if running the test displays a dialog, the test has no easy way of clicking a button on it to continue |
191 | | -execution. For these situations we use `sinon` to stub expected invocations and responses. |
192 | | - |
193 | | -Note: `client.test.ts` is an integration style test that boots the development version of the `ruby-lsp` gem and runs |
194 | | -requests against it. |
195 | | - |
196 | | -#### Running tests |
197 | | - |
198 | | -The easiest way to run tests is by selecting the `Extension tests` task in `Run and debug` and clicking run. That will |
199 | | -run all tests and the results will appear in VS Code's debug console. |
200 | | - |
201 | | -Alternatively, you can also run the tests through the terminal, which will download a test VS Code version inside the |
202 | | -repository and run tests against it. You can avoid the download by running the tests through the launch task. |
203 | | - |
204 | | -Note: it is not possible to run a single test file or example. |
205 | | - |
206 | | -### Live debugging |
207 | | - |
208 | | -It is possible to live debug the development version of the extension. Detailed information can be found in the [VS Code |
209 | | -extension documentation]((https://code.visualstudio.com/api)), but this section includes a short description. |
210 | | - |
211 | | -Live debugging involves two VS Code windows. The first one is where you will be modifying the code and the second window |
212 | | -will be where the development version of the extension is going to be running. You want to change the code in the first |
213 | | -window, reload and verify the changes in the second window. |
214 | | - |
215 | | -1. Start by launching the extension debugging with the `Run extension` task in the `Run and debug` panel. This will open the second VS Code window where the development version of the extension is running |
216 | | -2. Make the desired changes in the first original VS Code window |
217 | | -3. Click the reload button in the [debug toolbar](https://code.visualstudio.com/Docs/editor/debugging#_user-interface) to load your recent changes into the second VS Code window |
218 | | -4. Perform the actions to verify your changes in the second window |
219 | | - |
220 | | -If you wish to perform step by step debugging, all you have to do is add breakpoints through the UI in the first window |
221 | | -where you are modifying the code - not in the second window where the development version of the extension is running. |
222 | | - |
223 | | -## Contributing to documentation |
224 | | - |
225 | | -The Ruby LSP uses [Jekyll](https://jekyllrb.com/) to generate the documentation, whose source lives under the `/jekyll` |
226 | | -folder. Before making any changes, ensure you [performed initial setup](#initial-setup). |
227 | | - |
228 | | -After that, follow these steps to make and verify your changes: |
229 | | - |
230 | | -1. Make the desired changes |
231 | | -2. Launch jekyll in development |
232 | | -```shell |
233 | | -bundle exec jekyll serve |
234 | | -``` |
235 | | -3. Verify your changes locally by visiting http://localhost:4000/ruby-lsp |
| 3 | +See https://shopify.github.io/ruby-lsp/contributing |
0 commit comments