--- /dev/null
+*ale-development.txt* For Vim version 8.0.
+*ale-dev*
+*ale-development*
+
+ALE Development Documentation
+
+===============================================================================
+CONTENTS *ale-development-contents*
+
+ 1. Introduction.........................|ale-development-introduction|
+ 2. Design Goals.........................|ale-design-goals|
+ 3. Coding Standards.....................|ale-coding-standards|
+ 4. Testing ALE..........................|ale-development-tests|
+ 4.1. Writing Linter Tests.............|ale-development-linter-tests|
+ 4.2. Writing Fixer Tests..............|ale-development-fixer-tests|
+ 4.3. Running Tests in a Windows VM....|ale-development-windows-tests|
+ 5. Contributing.........................|ale-development-contributing|
+ 5.1. Preparing a Release..............|ale-development-release|
+
+
+===============================================================================
+1. Introduction *ale-development-introduction*
+
+This document contains helpful information for ALE developers, including
+design goals, information on how to run the tests, coding standards, and so
+on. You should read this document if you want to get involved with ALE
+development.
+
+
+===============================================================================
+2. Design Goals *ale-design-goals*
+
+This section lists design goals for ALE, in no particular order. They are as
+follows.
+
+ALE code should be almost 100% VimL. This makes the plugin as portable as
+possible.
+
+ALE should run without needing any other plugins to be installed, to make
+installation simple. ALE can integrate with other plugins for more advanced
+functionality, non-essential functionality, or improving on basic first party
+functionality.
+
+ALE should check files with as many tools as possible by default, except where
+they cause security issues or make excessive use of resources on modern
+machines.
+
+ALE should be free of breaking changes to the public API, which is comprised of
+documented functions and options, until a major version is planned. Breaking
+changes should be preceded by a deprecation phase complete with warnings.
+Changes required for security may be an exception.
+
+ALE supports Vim 8 and above, and Neovim 0.7.0 or newer. These are the
+earliest versions of Vim and Neovim which support |+job|, |+timer|,
+|+closure|, and |+lambda| features. All ALE code should be written so it is
+compatible with these versions of Vim, or with version checks so particular
+features can degrade or fail gracefully.
+
+Just about everything should be documented and covered with tests.
+
+By and large, people shouldn't pay for the functionality they don't use. Care
+should be taken when adding new features, so supporting new features doesn't
+degrade the general performance of anything ALE does.
+
+LSP support will become more important as time goes on. ALE should provide
+better support for LSP features as time goes on.
+
+When merging pull requests, you should respond with `Cheers! :beers:`, purely
+for comedy value.
+
+
+===============================================================================
+3. Coding Standards *ale-coding-standards*
+
+The following general coding standards should be adhered to for Vim code.
+
+* Check your Vim code with `Vint` and do everything it says. ALE will check
+ your Vim code with Vint automatically. See: https://github.com/Kuniwak/vint
+ Read ALE's `Dockerfile` to see which version of `Vint` it uses.
+* Try to write descriptive and concise names for variables and functions.
+ Names shouldn't be too short or too long. Think about others reading your
+ code later on.
+* Use `snake_case` names for variables and arguments, and `PascalCase` names
+ for functions. Prefix every variable name with its scope. (`l:`, `g:`, etc.)
+* Try to keep lines no longer than 80 characters, but this isn't an absolute
+ requirement.
+* Use 4 spaces for every level of indentation in Vim code.
+* Add a blank line before every `function`, `if`, `for`, `while`, or `return`,
+ which doesn't start a new level of indentation. This makes the logic in
+ your code easier to follow.
+* End every file with a trailing newline character, but not with extra blank
+ lines. Remove trailing whitespace from the ends of lines.
+* Write the full names of commands instead of abbreviations. For example, write
+ `function` instead of `func`, and `endif` instead of `end`.
+* Write functions with `!`, so files can be reloaded. Use the |abort| keyword
+ for all functions, so functions exit on the first error.
+* Make sure to credit yourself in files you have authored with `Author:`
+ and `Description:` comments.
+
+In addition to the above general guidelines for the style of your code, you
+should also follow some additional rules designed to prevent mistakes. Some of
+these are reported with ALE's `custom-linting-rules` script. See
+|ale-development-tests|.
+
+* Don't leave stray `:echo` lines in code. Write `" no-custom-checks` above
+ the line if you must echo something.
+* For strings use |is#| instead of |==#|, `is?` instead of `==?`, `isnot#`
+ instead of `!=#`, and `isnot?` instead of `!=?`. This is because `'x' ==# 0`
+ returns 1, while `'x' is# 0` returns 0, so you will experience fewer issues
+ when numbers are compared with strings. `is` and `isnot` also do not throw
+ errors when other objects like List or Dictionaries are compared with
+ strings.
+* Don't use the `getcwd()` function in the ALE codebase. Most of ALE's code
+ runs from asynchronous callback functions, and these functions can execute
+ from essentially random buffers. Therefore, the `getcwd()` output is
+ useless. Use `expand('#' . a:buffer . ':p:h')` instead. Don't use
+ `expand('%...')` for the same reason.
+* Don't use the `simplify()` function. It doesn't simplify paths enough. Use
+ `ale#path#Simplify()` instead.
+* Don't use the `shellescape()` function. It doesn't escape arguments properly
+ on Windows. Use `ale#Escape()` instead, which will avoid escaping where it
+ isn't needed, and generally escape arguments better on Windows.
+* Don't use the `tempname()` function. It doesn't work when `$TMPDIR` isn't
+ set. Use `ale#util#Tempname()` instead, which temporarily sets `$TMPDIR`
+ appropriately where needed.
+* Use `snake_case` names for linter names, so they can be used as part of
+ variable names. You can define `aliases` for linters, for other names people
+ might try to configure linters with.
+* Use |v:t_TYPE| variables instead of `type()`, which are more readable.
+
+Apply the following guidelines when writing Vader test files.
+
+* Use 2 spaces for Vader test files, instead of the 4 spaces for Vim files.
+* If you write `Before` and `After` blocks, you should typically write them at
+ the top of the file, so they run for all tests. There may be some tests
+ where it make sense to modify the `Before` and `After` code part of the way
+ through the file.
+* If you modify any settings or global variables, reset them in `After`
+ blocks. The Vader `Save` and `Restore` commands can be useful for this
+ purpose.
+* If you load or define linters in tests, write `call ale#linter#Reset()` in
+ an `After` block.
+* Just write `Execute` blocks for Vader tests, and don't bother writing `Then`
+ blocks. `Then` blocks execute after `After` blocks in older versions, and
+ that can be confusing.
+
+Apply the following rules when writing Bash scripts.
+
+* Run `shellcheck`, and do everything it says.
+ See: https://github.com/koalaman/shellcheck
+* Try to write scripts so they will run on Linux, BSD, or Mac OSX.
+
+
+===============================================================================
+4. Testing ALE *ale-development-tests* *ale-dev-tests* *ale-tests*
+
+ALE is tested with a suite of tests executed via GitHub Actions and AppVeyor.
+ALE runs tests with the following versions of Vim in the following
+environments.
+
+1. Vim 8.0.0027 on Linux via GitHub Actions.
+2. Vim 9.0.0297 on Linux via GitHub Actions.
+3. Neovim 0.7.0 on Linux via GitHub Actions.
+4. Neovim 0.8.0 on Linux via GitHub Actions.
+6. Vim 8 (stable builds) on Windows via AppVeyor.
+
+If you are developing ALE code on Linux, Mac OSX, or BSD, you can run ALEs
+tests by installing Docker and running the `run-tests` script. Follow the
+instructions on the Docker site for installing Docker.
+See: https://docs.docker.com/install/
+
+NOTE: Don't forget to add your user to the `docker` group on Linux, or Docker
+just won't work. See: https://docs.docker.com/install/linux/linux-postinstall/
+
+If you run simply `./run-tests` from the ALE repository root directory, the
+latest Docker image for tests will be downloaded if needed, and the script
+will run all of the tests in Vader, Vint checks, and several Bash scripts for
+finding extra issues. Run `./run-tests --help` to see all of the options the
+script supports. Note that the script supports selecting particular test files.
+
+Once you get used to dealing with Vim and NeoVim compatibility issues, you
+probably want to use `./run-tests --fast -q` for running tests with only the
+fastest available Vim version, and with success messages from tests
+suppressed.
+
+Generally write tests for any changes you make. The following types of tests
+are recommended for the following types of code.
+
+* New/edited error handler callbacks -> Write tests in `test/handler`
+* New/edited linter definition -> Write tests in `test/linter`
+* New/edited fixer functions -> Write tests in `test/fixers`
+
+Look at existing tests in the codebase for examples of how to write tests.
+Refer to the Vader documentation for general information on how to write Vader
+tests: https://github.com/junegunn/vader.vim
+
+If you need to add any supporting files for tests, such as empty files present
+to test searching upwards through paths for configuration files, they can be
+added to the `test/test-files` directory.
+
+See |ale-development-linter-tests| for more information on how to write linter
+tests.
+
+When you add new linters or fixers, make sure to add them into the tables in
+supported-tools.md and |ale-supported-languages-and-tools.txt|. If you forget to
+keep them both in sync, you should see an error like the following in the
+builds run for GitHub Actions.
+>
+ ========================================
+ diff supported-tools.md and doc/ale-supported-languages-and-tools.txt tables
+ ========================================
+ Differences follow:
+
+ --- /tmp/readme.qLjNhJdB 2018-07-01 16:29:55.590331972 +0100
+ +++ /tmp/doc.dAi8zfVE 2018-07-01 16:29:55.582331877 +0100
+ @@ -1 +1 @@
+ - ASM: gcc, foobar
+ + ASM: gcc
+<
+Make sure to list documentation entries for linters and fixers in individual
+help files in the table of contents, and to align help tags to the right
+margin. For example, if you add a heading for an `aardvark` tool to
+`ale-python.txt` with a badly aligned doc tag, you will see errors like so. >
+
+ ========================================
+ Look for badly aligned doc tags
+ ========================================
+ Badly aligned tags follow:
+
+ doc/ale-python.txt:aardvark ...
+ ========================================
+ Look for table of contents issues
+ ========================================
+
+ Check for bad ToC sorting:
+
+ Check for mismatched ToC and headings:
+
+ --- /tmp/table-of-contents.mwCFOgSI 2018-07-01 16:33:25.068811878 +0100
+ +++ /tmp/headings.L4WU0hsO 2018-07-01 16:33:25.076811973 +0100
+ @@ -168,6 +168,7 @@
+ pyrex (cython), ale-pyrex-options
+ cython, ale-pyrex-cython
+ python, ale-python-options
+ + aardvark, ale-python-aardvark
+ autopep8, ale-python-autopep8
+ black, ale-python-black
+ flake8, ale-python-flake8
+<
+Make sure to make the table of contents match the headings, and to keep the
+doc tags on the right margin.
+
+
+===============================================================================
+4.1 Writing Linter Tests *ale-development-linter-tests*
+
+Tests for ALE linters take two forms.
+
+1. Tests for handling the output of commands.
+2. Tests for checking which commands are run, or connections are made.
+
+Tests of the first form should go in the `test/handler` directory, and should
+be written like so. >
+
+ Before:
+ " Load the file which defines the linter.
+ runtime ale_linters/filetype/linter_name_here.vim
+
+ After:
+ " Unload all linters again.
+ call ale#linter#Reset()
+
+ Execute(The output should be correct):
+
+ " Test that the right loclist items are parsed from the handler.
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 1,
+ \ 'type': 'E',
+ \ 'text': 'Something went wrong',
+ \ },
+ \ ],
+ \ ale_linters#filetype#linter_name#Handle(bufnr(''), [
+ \ '1:Something went wrong',
+ \ ]
+<
+Tests for what ALE runs should go in the `test/linter` directory, and should
+be written like so. >
+
+ Before:
+ " Load the linter and set up a series of commands, reset linter variables,
+ " clear caches, etc.
+ "
+ " Vader's 'Save' command will be called here for linter variables.
+ call ale#assert#SetUpLinterTest('filetype', 'linter_name')
+
+ After:
+ " Reset linters, variables, etc.
+ "
+ " Vader's 'Restore' command will be called here.
+ call ale#assert#TearDownLinterTest()
+
+ Execute(The default command should be correct):
+ " AssertLinter checks the executable and command.
+ " Pass expected_executable, expected_command
+ AssertLinter 'some-command', ale#Escape('some-command') . ' --foo'
+
+ Execute(Check chained commands):
+ " GivenCommandOutput can be called with 1 or more list for passing output
+ " to chained commands. The output for each callback defaults to an empty
+ " list.
+ GivenCommandOutput ['v2.1.2']
+ " Given a List of commands, check all of them.
+ " Given a String, only the last command in the chain will be checked.
+ AssertLinter 'some-command', [
+ \ ale#Escape('some-command') . ' --version',
+ \ ale#Escape('some-command') . ' --foo',
+ \]
+<
+The full list of commands that will be temporarily defined for linter tests
+given the above setup are as follows.
+
+`GivenCommandOutput [...]` - Define output for ale#command#Run.
+`AssertLinterCwd cwd` - Check the `cwd` for the linter.
+`AssertLinter executable, command` - Check the executable and command.
+`AssertLinterNotExecuted` - Check that linters will not be executed.
+`AssertLSPLanguage language` - Check the language given to an LSP server.
+`AssertLSPOptions options_dict` - Check the options given to an LSP server.
+`AssertLSPConfig config_dict` - Check the config given to an LSP server.
+`AssertLSPProject project_root` - Check the root given to an LSP server.
+`AssertLSPAddress address` - Check the address to an LSP server.
+
+
+===============================================================================
+4.2 Writing Fixer Tests *ale-development-fixer-tests*
+
+Tests for ALE fixers should go in the `test/fixers` directory, and should
+be written like so. >
+
+ Before:
+ " Load the fixer and set up a series of commands, reset fixer variables,
+ " clear caches, etc.
+ "
+ " Vader's 'Save' command will be called here for fixer variables.
+ call ale#assert#SetUpFixerTest('filetype', 'fixer_name')
+
+ After:
+ " Reset fixers, variables, etc.
+ "
+ " Vader's 'Restore' command will be called here.
+ call ale#assert#TearDownFixerTest()
+
+ Execute(The default command should be correct):
+ " AssertFixer checks the result of the loaded fixer function.
+ AssertFixer {'command': ale#Escape('some-command') . ' --foo'}
+
+ Execute(Check chained commands):
+ " Same as above for linter tests.
+ GivenCommandOutput ['v2.1.2']
+ " Given a List of commands, check all of them.
+ " Given anything else, only the last result will be checked.
+ AssertFixer [
+ \ ale#Escape('some-command') . ' --version',
+ \ {'command': ale#Escape('some-command') . ' --foo'}
+ \]
+<
+The full list of commands that will be temporarily defined for fixer tests
+given the above setup are as follows.
+
+`GivenCommandOutput [...]` - Define output for ale#command#Run.
+`AssertFixerCwd cwd` - Check the `cwd` for the fixer.
+`AssertFixer results` - Check the fixer results
+`AssertFixerNotExecuted` - Check that fixers will not be executed.
+
+
+===============================================================================
+4.3 Running Tests in a Windows VM *ale-development-windows-tests*
+
+Tests are run for ALE in a build of Vim 8 for Windows via AppVeyor. These
+tests can frequently break due to minor differences in paths and how escaping
+is done for commands on Windows. If you are a Linux or Mac user, running these
+tests locally can be difficult. Here is a process that will make that easier.
+
+First, you want to install a Windows image with VirtualBox. Install VirtualBox
+and grab a VirtualBox image for Windows such as from here:
+https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/
+
+NOTE: If you need to enter a password for the virtual machine at any point,
+the password is "Passw0rd!" without the double quotes.
+
+NOTE: If your trial period for Windows runs out, run the commands like the
+wallpaper tells you to.
+
+Your virtual machine will need to have PowerShell installed. Before you go any
+further, confirm that PowerShell is installed in your Windows virtual machine.
+
+Consult the VirtualBox documentation on how to install "Guest Additions."
+You probably want to install "Guest Additions" for most things to work
+properly.
+
+After you've loaded your virtual machine image, go into "Settings" for your
+virtual machine, and "Shared Folders." Add a shared folder with the name
+"ale", and set the "Folder Path" to the path to your ALE repository, for
+example: "/home/w0rp/ale"
+
+Find out which drive letter "ale" has been mounted as in Windows. We'll use
+"E:" as the drive letter, for example. Open the command prompt as an
+administrator by typing in `cmd` in the start menu, right clicking on the
+command prompt application, and clicking "Run as administrator." Click "Yes"
+when prompted to ask if you're sure you want to run the command prompt. You
+should type in the following command to mount the "ale" directory for testing,
+where "E:" is replaced with your drive letter. >
+
+ mklink /D C:\testplugin E:
+<
+Close the administrator Command Prompt, and try running the command
+`type C:\testplugin\LICENSE` in a new Command Prompt which you are NOT running
+as administrator. You should see the license for ALE in your terminal. After
+you have confirmed that you have mounted ALE on your machine, search in the
+Start Menu for "power shell," run PowerShell as an administrator, and issue
+the following commands to install the correct Vim and Vader versions for
+running tests. >
+
+ Add-Type -A System.IO.Compression.FileSystem
+
+ Invoke-WebRequest ftp://ftp.vim.org/pub/vim/pc/vim80-586w32.zip -OutFile C:\vim.zip
+ [IO.Compression.ZipFile]::ExtractToDirectory('C:\vim.zip', 'C:\vim')
+ rm C:\vim.zip
+
+ Invoke-WebRequest ftp://ftp.vim.org/pub/vim/pc/vim80-586rt.zip -OutFile C:\rt.zip
+ [IO.Compression.ZipFile]::ExtractToDirectory('C:\rt.zip', 'C:\vim')
+ rm C:\rt.zip
+
+ Invoke-WebRequest https://github.com/junegunn/vader.vim/archive/c6243dd81c98350df4dec608fa972df98fa2a3af.zip -OutFile C:\vader.zip
+ [IO.Compression.ZipFile]::ExtractToDirectory('C:\vader.zip', 'C:\')
+ mv C:\vader.vim-c6243dd81c98350df4dec608fa972df98fa2a3af C:\vader
+ rm C:\vader.zip
+<
+After you have finished installing everything, you can run all of the tests
+in Windows by opening a Command Prompt NOT as an administrator by navigating
+to the directory where you've mounted the ALE code, which must be named
+`C:\testplugin`, and by running the `run-tests.bat` batch file. >
+
+ cd C:\testplugin
+ run-tests
+<
+It will probably take several minutes for all of the tests to run. Be patient.
+You can run a specific test by passing the filename as an argument to the
+batch file, for example: `run-tests test/test_c_flag_parsing.vader` . This will
+give you results much more quickly.
+
+
+===============================================================================
+5. Contributing *ale-development-contributing*
+
+All integration of new code into ALE is done through GitHub pull requests.
+Using that tool streamlines the process and minimizes the time and effort
+required to e.g. ensure test suites are run for every change.
+
+As for any project hosted by GitHub, the choice of platform demands every
+contributor to take care to setup an account and configure it accordingly.
+
+Due to details of our process, a difference to many other GitHub hosted
+projects is that contributors who wish to keep the author fields for their
+commits unaltered need to configure a public email address in their account
+and profile settings. See: https://docs.github.com/en/account-and-profile/
+
+Unless configuring GitHub to expose contact details, commits will be rewritten
+to appear by `USERNAME <RANDOM_NUMBER+USERNAME@users.noreply.github.com>` .
+
+
+===============================================================================
+5.1 Preparing a Release *ale-development-release*
+
+ALE offers release packages through GitHub, for two reasons:
+
+1. Some users like to target specific release versions rather than simply
+ installing the plugin from `master`. This includes users who create Linux
+ distribution specific packages from GitHub releases.
+2. The releases provide a nice way to get an overview of what has changed in
+ ALE over time.
+
+ALE has no fixed release schedule. Release versions are created whenever the
+ALE developers feel the need to create one. ALE release versions follow the
+typical Semantic Versioning scheme. See: https://semver.org/
+
+Minor version releases for ALE should be the most common, followed by patch
+releases. Every minor version release should be followed by a `vA.B.x` branch
+such as `v2.0.x` for version `2.0.0` and every following patch version before
+`2.1.0`. The `git` branch strategy for patches is to first merge a bug fix to
+`master`, and then `git cherry-pick` a patch to a branch for a specific
+version. ALE developers do not generally support anything but `master` or the
+last minor version.
+
+Generally ALE releases hit a major version only when there are breaking
+changes to a public ALE setting or function. A "public" setting or function is
+defined as any setting or function documented in the `:help` |ale.txt| file.
+Major ALE versions ought to be so rare that they only come once a year at
+most. ALE should not typically introduce any breaking changes.
+
+If there are ever to be any breaking changes made for ALE, there should first
+come a minor version release for ALE documenting all of the coming breaking
+changes to ALE. It should be described how users can prepare for a breaking
+change that is coming before it is done.
+
+To create a release for ALE, you will need sufficient permissions in GitHub.
+Once you do, follow these steps.
+
+1. Create a new release draft, or edit an existing one. It helps to craft
+ drafts ahead of time and write the last commit ID checked for release notes
+ on the last update to a draft.
+ See the releases page: https://github.com/dense-analysis/ale/releases
+2. Examine `git log` and read changes made between the last ID checked, or the
+ git tag of the previous release, and the current commit in `master`.
+3. Write updates in separate sections (except where empty) for:
+ 3.a. Breaking Changes
+ 3.b. Deprecated Features
+ 3.c. New Features
+ 3.d. New Linters
+ 3.e. New Fixers
+ 3.f. Linter Enhancements
+ 3.g. Fixer Enhancements
+ 3.h. Bugs Fixed
+4. Once you've finished writing the draft for the release, bump
+ `s:current_ale_version` in `autoload/ale.vim` to the current version, and
+ add a line to `test/test_ale_has.vader` to test for the version. See
+ |ale#Has()| documentation for more information.
+5. Commit the changes after `./run-tests --fast -q` passes.
+6. Tag the release with `git tag vA.B.C`, replacing `A`, `B`, and `C` with the
+ version numbers. See `git tag --list` for examples.
+7. Run `git push` and `git push --tags` to push the commit and the tag.
+8. Edit the release draft in GitHub, select the tag you just pushed, and
+ publish the draft.
+9. If you're creating a new major or minor version: `git checkout -b vA.B.x`,
+ replacing `A` and `B` with the major and minor versions. `git push` the new
+ branch, and the GitHub branch protection settings should automatically
+ apply to the new release branch.
+10. You have already completed the last step.
+
+Have fun creating ALE releases. Drink responsibly, or not at all, which is the
+preference of w0rp.
+
+
+===============================================================================
+ vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: