All patches and comments are welcome. Please squash your changes to logical
commits before using git-format-patch and git-send-email to
patches@git.madduck.net.
If you'd read over the Git project's submission guidelines and adhered to them,
I'd be especially grateful.
1 *ale-development.txt* For Vim version 8.0.
5 ALE Development Documentation
7 ===============================================================================
8 CONTENTS *ale-development-contents*
10 1. Introduction.........................|ale-development-introduction|
11 2. Design Goals.........................|ale-design-goals|
12 3. Coding Standards.....................|ale-coding-standards|
13 4. Testing ALE..........................|ale-development-tests|
14 4.1. Writing Linter Tests.............|ale-development-linter-tests|
15 4.2. Writing Fixer Tests..............|ale-development-fixer-tests|
16 4.3. Running Tests in a Windows VM....|ale-development-windows-tests|
17 5. Contributing.........................|ale-development-contributing|
18 5.1. Preparing a Release..............|ale-development-release|
21 ===============================================================================
22 1. Introduction *ale-development-introduction*
24 This document contains helpful information for ALE developers, including
25 design goals, information on how to run the tests, coding standards, and so
26 on. You should read this document if you want to get involved with ALE
30 ===============================================================================
31 2. Design Goals *ale-design-goals*
33 This section lists design goals for ALE, in no particular order. They are as
36 ALE code should be almost 100% VimL. This makes the plugin as portable as
39 ALE should run without needing any other plugins to be installed, to make
40 installation simple. ALE can integrate with other plugins for more advanced
41 functionality, non-essential functionality, or improving on basic first party
44 ALE should check files with as many tools as possible by default, except where
45 they cause security issues or make excessive use of resources on modern
48 ALE should be free of breaking changes to the public API, which is comprised of
49 documented functions and options, until a major version is planned. Breaking
50 changes should be preceded by a deprecation phase complete with warnings.
51 Changes required for security may be an exception.
53 ALE supports Vim 8 and above, and Neovim 0.7.0 or newer. These are the
54 earliest versions of Vim and Neovim which support |+job|, |+timer|,
55 |+closure|, and |+lambda| features. All ALE code should be written so it is
56 compatible with these versions of Vim, or with version checks so particular
57 features can degrade or fail gracefully.
59 Just about everything should be documented and covered with tests.
61 By and large, people shouldn't pay for the functionality they don't use. Care
62 should be taken when adding new features, so supporting new features doesn't
63 degrade the general performance of anything ALE does.
65 LSP support will become more important as time goes on. ALE should provide
66 better support for LSP features as time goes on.
68 When merging pull requests, you should respond with `Cheers! :beers:`, purely
72 ===============================================================================
73 3. Coding Standards *ale-coding-standards*
75 The following general coding standards should be adhered to for Vim code.
77 * Check your Vim code with `Vint` and do everything it says. ALE will check
78 your Vim code with Vint automatically. See: https://github.com/Kuniwak/vint
79 Read ALE's `Dockerfile` to see which version of `Vint` it uses.
80 * Try to write descriptive and concise names for variables and functions.
81 Names shouldn't be too short or too long. Think about others reading your
83 * Use `snake_case` names for variables and arguments, and `PascalCase` names
84 for functions. Prefix every variable name with its scope. (`l:`, `g:`, etc.)
85 * Try to keep lines no longer than 80 characters, but this isn't an absolute
87 * Use 4 spaces for every level of indentation in Vim code.
88 * Add a blank line before every `function`, `if`, `for`, `while`, or `return`,
89 which doesn't start a new level of indentation. This makes the logic in
90 your code easier to follow.
91 * End every file with a trailing newline character, but not with extra blank
92 lines. Remove trailing whitespace from the ends of lines.
93 * Write the full names of commands instead of abbreviations. For example, write
94 `function` instead of `func`, and `endif` instead of `end`.
95 * Write functions with `!`, so files can be reloaded. Use the |abort| keyword
96 for all functions, so functions exit on the first error.
97 * Make sure to credit yourself in files you have authored with `Author:`
98 and `Description:` comments.
100 In addition to the above general guidelines for the style of your code, you
101 should also follow some additional rules designed to prevent mistakes. Some of
102 these are reported with ALE's `custom-linting-rules` script. See
103 |ale-development-tests|.
105 * Don't leave stray `:echo` lines in code. Write `" no-custom-checks` above
106 the line if you must echo something.
107 * For strings use |is#| instead of |==#|, `is?` instead of `==?`, `isnot#`
108 instead of `!=#`, and `isnot?` instead of `!=?`. This is because `'x' ==# 0`
109 returns 1, while `'x' is# 0` returns 0, so you will experience fewer issues
110 when numbers are compared with strings. `is` and `isnot` also do not throw
111 errors when other objects like List or Dictionaries are compared with
113 * Don't use the `getcwd()` function in the ALE codebase. Most of ALE's code
114 runs from asynchronous callback functions, and these functions can execute
115 from essentially random buffers. Therefore, the `getcwd()` output is
116 useless. Use `expand('#' . a:buffer . ':p:h')` instead. Don't use
117 `expand('%...')` for the same reason.
118 * Don't use the `simplify()` function. It doesn't simplify paths enough. Use
119 `ale#path#Simplify()` instead.
120 * Don't use the `shellescape()` function. It doesn't escape arguments properly
121 on Windows. Use `ale#Escape()` instead, which will avoid escaping where it
122 isn't needed, and generally escape arguments better on Windows.
123 * Don't use the `tempname()` function. It doesn't work when `$TMPDIR` isn't
124 set. Use `ale#util#Tempname()` instead, which temporarily sets `$TMPDIR`
125 appropriately where needed.
126 * Use `snake_case` names for linter names, so they can be used as part of
127 variable names. You can define `aliases` for linters, for other names people
128 might try to configure linters with.
129 * Use |v:t_TYPE| variables instead of `type()`, which are more readable.
131 Apply the following guidelines when writing Vader test files.
133 * Use 2 spaces for Vader test files, instead of the 4 spaces for Vim files.
134 * If you write `Before` and `After` blocks, you should typically write them at
135 the top of the file, so they run for all tests. There may be some tests
136 where it make sense to modify the `Before` and `After` code part of the way
138 * If you modify any settings or global variables, reset them in `After`
139 blocks. The Vader `Save` and `Restore` commands can be useful for this
141 * If you load or define linters in tests, write `call ale#linter#Reset()` in
143 * Just write `Execute` blocks for Vader tests, and don't bother writing `Then`
144 blocks. `Then` blocks execute after `After` blocks in older versions, and
145 that can be confusing.
147 Apply the following rules when writing Bash scripts.
149 * Run `shellcheck`, and do everything it says.
150 See: https://github.com/koalaman/shellcheck
151 * Try to write scripts so they will run on Linux, BSD, or Mac OSX.
154 ===============================================================================
155 4. Testing ALE *ale-development-tests* *ale-dev-tests* *ale-tests*
157 ALE is tested with a suite of tests executed via GitHub Actions and AppVeyor.
158 ALE runs tests with the following versions of Vim in the following
161 1. Vim 8.0.0027 on Linux via GitHub Actions.
162 2. Vim 9.0.0297 on Linux via GitHub Actions.
163 3. Neovim 0.7.0 on Linux via GitHub Actions.
164 4. Neovim 0.8.0 on Linux via GitHub Actions.
165 6. Vim 8 (stable builds) on Windows via AppVeyor.
167 If you are developing ALE code on Linux, Mac OSX, or BSD, you can run ALEs
168 tests by installing Docker and running the `run-tests` script. Follow the
169 instructions on the Docker site for installing Docker.
170 See: https://docs.docker.com/install/
172 NOTE: Don't forget to add your user to the `docker` group on Linux, or Docker
173 just won't work. See: https://docs.docker.com/install/linux/linux-postinstall/
175 If you run simply `./run-tests` from the ALE repository root directory, the
176 latest Docker image for tests will be downloaded if needed, and the script
177 will run all of the tests in Vader, Vint checks, and several Bash scripts for
178 finding extra issues. Run `./run-tests --help` to see all of the options the
179 script supports. Note that the script supports selecting particular test files.
181 Once you get used to dealing with Vim and NeoVim compatibility issues, you
182 probably want to use `./run-tests --fast -q` for running tests with only the
183 fastest available Vim version, and with success messages from tests
186 Generally write tests for any changes you make. The following types of tests
187 are recommended for the following types of code.
189 * New/edited error handler callbacks -> Write tests in `test/handler`
190 * New/edited linter definition -> Write tests in `test/linter`
191 * New/edited fixer functions -> Write tests in `test/fixers`
193 Look at existing tests in the codebase for examples of how to write tests.
194 Refer to the Vader documentation for general information on how to write Vader
195 tests: https://github.com/junegunn/vader.vim
197 If you need to add any supporting files for tests, such as empty files present
198 to test searching upwards through paths for configuration files, they can be
199 added to the `test/test-files` directory.
201 See |ale-development-linter-tests| for more information on how to write linter
204 When you add new linters or fixers, make sure to add them into the tables in
205 supported-tools.md and |ale-supported-languages-and-tools.txt|. If you forget to
206 keep them both in sync, you should see an error like the following in the
207 builds run for GitHub Actions.
209 ========================================
210 diff supported-tools.md and doc/ale-supported-languages-and-tools.txt tables
211 ========================================
214 --- /tmp/readme.qLjNhJdB 2018-07-01 16:29:55.590331972 +0100
215 +++ /tmp/doc.dAi8zfVE 2018-07-01 16:29:55.582331877 +0100
220 Make sure to list documentation entries for linters and fixers in individual
221 help files in the table of contents, and to align help tags to the right
222 margin. For example, if you add a heading for an `aardvark` tool to
223 `ale-python.txt` with a badly aligned doc tag, you will see errors like so. >
225 ========================================
226 Look for badly aligned doc tags
227 ========================================
228 Badly aligned tags follow:
230 doc/ale-python.txt:aardvark ...
231 ========================================
232 Look for table of contents issues
233 ========================================
235 Check for bad ToC sorting:
237 Check for mismatched ToC and headings:
239 --- /tmp/table-of-contents.mwCFOgSI 2018-07-01 16:33:25.068811878 +0100
240 +++ /tmp/headings.L4WU0hsO 2018-07-01 16:33:25.076811973 +0100
242 pyrex (cython), ale-pyrex-options
243 cython, ale-pyrex-cython
244 python, ale-python-options
245 + aardvark, ale-python-aardvark
246 autopep8, ale-python-autopep8
247 black, ale-python-black
248 flake8, ale-python-flake8
250 Make sure to make the table of contents match the headings, and to keep the
251 doc tags on the right margin.
254 ===============================================================================
255 4.1 Writing Linter Tests *ale-development-linter-tests*
257 Tests for ALE linters take two forms.
259 1. Tests for handling the output of commands.
260 2. Tests for checking which commands are run, or connections are made.
262 Tests of the first form should go in the `test/handler` directory, and should
263 be written like so. >
266 " Load the file which defines the linter.
267 runtime ale_linters/filetype/linter_name_here.vim
270 " Unload all linters again.
271 call ale#linter#Reset()
273 Execute(The output should be correct):
275 " Test that the right loclist items are parsed from the handler.
281 \ 'text': 'Something went wrong',
284 \ ale_linters#filetype#linter_name#Handle(bufnr(''), [
285 \ '1:Something went wrong',
288 Tests for what ALE runs should go in the `test/linter` directory, and should
289 be written like so. >
292 " Load the linter and set up a series of commands, reset linter variables,
295 " Vader's 'Save' command will be called here for linter variables.
296 call ale#assert#SetUpLinterTest('filetype', 'linter_name')
299 " Reset linters, variables, etc.
301 " Vader's 'Restore' command will be called here.
302 call ale#assert#TearDownLinterTest()
304 Execute(The default command should be correct):
305 " AssertLinter checks the executable and command.
306 " Pass expected_executable, expected_command
307 AssertLinter 'some-command', ale#Escape('some-command') . ' --foo'
309 Execute(Check chained commands):
310 " GivenCommandOutput can be called with 1 or more list for passing output
311 " to chained commands. The output for each callback defaults to an empty
313 GivenCommandOutput ['v2.1.2']
314 " Given a List of commands, check all of them.
315 " Given a String, only the last command in the chain will be checked.
316 AssertLinter 'some-command', [
317 \ ale#Escape('some-command') . ' --version',
318 \ ale#Escape('some-command') . ' --foo',
321 The full list of commands that will be temporarily defined for linter tests
322 given the above setup are as follows.
324 `GivenCommandOutput [...]` - Define output for ale#command#Run.
325 `AssertLinterCwd cwd` - Check the `cwd` for the linter.
326 `AssertLinter executable, command` - Check the executable and command.
327 `AssertLinterNotExecuted` - Check that linters will not be executed.
328 `AssertLSPLanguage language` - Check the language given to an LSP server.
329 `AssertLSPOptions options_dict` - Check the options given to an LSP server.
330 `AssertLSPConfig config_dict` - Check the config given to an LSP server.
331 `AssertLSPProject project_root` - Check the root given to an LSP server.
332 `AssertLSPAddress address` - Check the address to an LSP server.
335 ===============================================================================
336 4.2 Writing Fixer Tests *ale-development-fixer-tests*
338 Tests for ALE fixers should go in the `test/fixers` directory, and should
339 be written like so. >
342 " Load the fixer and set up a series of commands, reset fixer variables,
345 " Vader's 'Save' command will be called here for fixer variables.
346 call ale#assert#SetUpFixerTest('filetype', 'fixer_name')
349 " Reset fixers, variables, etc.
351 " Vader's 'Restore' command will be called here.
352 call ale#assert#TearDownFixerTest()
354 Execute(The default command should be correct):
355 " AssertFixer checks the result of the loaded fixer function.
356 AssertFixer {'command': ale#Escape('some-command') . ' --foo'}
358 Execute(Check chained commands):
359 " Same as above for linter tests.
360 GivenCommandOutput ['v2.1.2']
361 " Given a List of commands, check all of them.
362 " Given anything else, only the last result will be checked.
364 \ ale#Escape('some-command') . ' --version',
365 \ {'command': ale#Escape('some-command') . ' --foo'}
368 The full list of commands that will be temporarily defined for fixer tests
369 given the above setup are as follows.
371 `GivenCommandOutput [...]` - Define output for ale#command#Run.
372 `AssertFixerCwd cwd` - Check the `cwd` for the fixer.
373 `AssertFixer results` - Check the fixer results
374 `AssertFixerNotExecuted` - Check that fixers will not be executed.
377 ===============================================================================
378 4.3 Running Tests in a Windows VM *ale-development-windows-tests*
380 Tests are run for ALE in a build of Vim 8 for Windows via AppVeyor. These
381 tests can frequently break due to minor differences in paths and how escaping
382 is done for commands on Windows. If you are a Linux or Mac user, running these
383 tests locally can be difficult. Here is a process that will make that easier.
385 First, you want to install a Windows image with VirtualBox. Install VirtualBox
386 and grab a VirtualBox image for Windows such as from here:
387 https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/
389 NOTE: If you need to enter a password for the virtual machine at any point,
390 the password is "Passw0rd!" without the double quotes.
392 NOTE: If your trial period for Windows runs out, run the commands like the
393 wallpaper tells you to.
395 Your virtual machine will need to have PowerShell installed. Before you go any
396 further, confirm that PowerShell is installed in your Windows virtual machine.
398 Consult the VirtualBox documentation on how to install "Guest Additions."
399 You probably want to install "Guest Additions" for most things to work
402 After you've loaded your virtual machine image, go into "Settings" for your
403 virtual machine, and "Shared Folders." Add a shared folder with the name
404 "ale", and set the "Folder Path" to the path to your ALE repository, for
405 example: "/home/w0rp/ale"
407 Find out which drive letter "ale" has been mounted as in Windows. We'll use
408 "E:" as the drive letter, for example. Open the command prompt as an
409 administrator by typing in `cmd` in the start menu, right clicking on the
410 command prompt application, and clicking "Run as administrator." Click "Yes"
411 when prompted to ask if you're sure you want to run the command prompt. You
412 should type in the following command to mount the "ale" directory for testing,
413 where "E:" is replaced with your drive letter. >
415 mklink /D C:\testplugin E:
417 Close the administrator Command Prompt, and try running the command
418 `type C:\testplugin\LICENSE` in a new Command Prompt which you are NOT running
419 as administrator. You should see the license for ALE in your terminal. After
420 you have confirmed that you have mounted ALE on your machine, search in the
421 Start Menu for "power shell," run PowerShell as an administrator, and issue
422 the following commands to install the correct Vim and Vader versions for
425 Add-Type -A System.IO.Compression.FileSystem
427 Invoke-WebRequest ftp://ftp.vim.org/pub/vim/pc/vim80-586w32.zip -OutFile C:\vim.zip
428 [IO.Compression.ZipFile]::ExtractToDirectory('C:\vim.zip', 'C:\vim')
431 Invoke-WebRequest ftp://ftp.vim.org/pub/vim/pc/vim80-586rt.zip -OutFile C:\rt.zip
432 [IO.Compression.ZipFile]::ExtractToDirectory('C:\rt.zip', 'C:\vim')
435 Invoke-WebRequest https://github.com/junegunn/vader.vim/archive/c6243dd81c98350df4dec608fa972df98fa2a3af.zip -OutFile C:\vader.zip
436 [IO.Compression.ZipFile]::ExtractToDirectory('C:\vader.zip', 'C:\')
437 mv C:\vader.vim-c6243dd81c98350df4dec608fa972df98fa2a3af C:\vader
440 After you have finished installing everything, you can run all of the tests
441 in Windows by opening a Command Prompt NOT as an administrator by navigating
442 to the directory where you've mounted the ALE code, which must be named
443 `C:\testplugin`, and by running the `run-tests.bat` batch file. >
448 It will probably take several minutes for all of the tests to run. Be patient.
449 You can run a specific test by passing the filename as an argument to the
450 batch file, for example: `run-tests test/test_c_flag_parsing.vader` . This will
451 give you results much more quickly.
454 ===============================================================================
455 5. Contributing *ale-development-contributing*
457 All integration of new code into ALE is done through GitHub pull requests.
458 Using that tool streamlines the process and minimizes the time and effort
459 required to e.g. ensure test suites are run for every change.
461 As for any project hosted by GitHub, the choice of platform demands every
462 contributor to take care to setup an account and configure it accordingly.
464 Due to details of our process, a difference to many other GitHub hosted
465 projects is that contributors who wish to keep the author fields for their
466 commits unaltered need to configure a public email address in their account
467 and profile settings. See: https://docs.github.com/en/account-and-profile/
469 Unless configuring GitHub to expose contact details, commits will be rewritten
470 to appear by `USERNAME <RANDOM_NUMBER+USERNAME@users.noreply.github.com>` .
473 ===============================================================================
474 5.1 Preparing a Release *ale-development-release*
476 ALE offers release packages through GitHub, for two reasons:
478 1. Some users like to target specific release versions rather than simply
479 installing the plugin from `master`. This includes users who create Linux
480 distribution specific packages from GitHub releases.
481 2. The releases provide a nice way to get an overview of what has changed in
484 ALE has no fixed release schedule. Release versions are created whenever the
485 ALE developers feel the need to create one. ALE release versions follow the
486 typical Semantic Versioning scheme. See: https://semver.org/
488 Minor version releases for ALE should be the most common, followed by patch
489 releases. Every minor version release should be followed by a `vA.B.x` branch
490 such as `v2.0.x` for version `2.0.0` and every following patch version before
491 `2.1.0`. The `git` branch strategy for patches is to first merge a bug fix to
492 `master`, and then `git cherry-pick` a patch to a branch for a specific
493 version. ALE developers do not generally support anything but `master` or the
496 Generally ALE releases hit a major version only when there are breaking
497 changes to a public ALE setting or function. A "public" setting or function is
498 defined as any setting or function documented in the `:help` |ale.txt| file.
499 Major ALE versions ought to be so rare that they only come once a year at
500 most. ALE should not typically introduce any breaking changes.
502 If there are ever to be any breaking changes made for ALE, there should first
503 come a minor version release for ALE documenting all of the coming breaking
504 changes to ALE. It should be described how users can prepare for a breaking
505 change that is coming before it is done.
507 To create a release for ALE, you will need sufficient permissions in GitHub.
508 Once you do, follow these steps.
510 1. Create a new release draft, or edit an existing one. It helps to craft
511 drafts ahead of time and write the last commit ID checked for release notes
512 on the last update to a draft.
513 See the releases page: https://github.com/dense-analysis/ale/releases
514 2. Examine `git log` and read changes made between the last ID checked, or the
515 git tag of the previous release, and the current commit in `master`.
516 3. Write updates in separate sections (except where empty) for:
517 3.a. Breaking Changes
518 3.b. Deprecated Features
522 3.f. Linter Enhancements
523 3.g. Fixer Enhancements
525 4. Once you've finished writing the draft for the release, bump
526 `s:current_ale_version` in `autoload/ale.vim` to the current version, and
527 add a line to `test/test_ale_has.vader` to test for the version. See
528 |ale#Has()| documentation for more information.
529 5. Commit the changes after `./run-tests --fast -q` passes.
530 6. Tag the release with `git tag vA.B.C`, replacing `A`, `B`, and `C` with the
531 version numbers. See `git tag --list` for examples.
532 7. Run `git push` and `git push --tags` to push the commit and the tag.
533 8. Edit the release draft in GitHub, select the tag you just pushed, and
535 9. If you're creating a new major or minor version: `git checkout -b vA.B.x`,
536 replacing `A` and `B` with the major and minor versions. `git push` the new
537 branch, and the GitHub branch protection settings should automatically
538 apply to the new release branch.
539 10. You have already completed the last step.
541 Have fun creating ALE releases. Drink responsibly, or not at all, which is the
545 ===============================================================================
546 vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: