Linting

Lūn

GREASE employs a variety of linting tools, which can optionally be coordinated via Lūn. We do our best to keep lun.toml up to date, but the ground truth of which linters are run on what files and in what configuration is always supplied by the CI system. To run them all:

lun run

Lūn can run just the formatters, or run the linters in "fix" mode where applicable. See the --help output for more information.

We recommend using this as a pre-commit hook:

cat <<'EOF' > .git/hooks/pre-commit
#!/usr/bin/env bash
lun run --check --staged
EOF
chmod +x .git/hooks/pre-commit

Generic scripts

We have a few Python scripts in scripts/lint/ that perform one-off checks. They generally take some number of paths as arguments, check .github/workflows/lint.yml to see how they are invoked in CI.

Fourmolu

This repo enforces Fourmolu formatting based on the committed configuration in fourmolu.yaml. Installation and usage directions are available here. In short:

cabal install fourmolu-0.19.0.0
fourmolu --mode inplace $(git ls-files '*.hs')

One can configure auto-format on save to avoid formatting issues. The repo is already formatted with fourmolu so new formatting changes should be localized to behavioral changes. Further discussion of the rationale for the enforcement of a fourmolu style and commit hygiene is available in this formatting discussion.

hlint

We treat a small number of hlint warnings as errors in CI. To run hlint locally, try:

hlint grease{,-aarch32,-llvm,-ppc,-x86}/src grease-cli/src grease-exe/{main,src,tests}

mdlynx

We run mdlynx on our Markdown files to check for broken links. To run it locally, try:

git ls-files -z --exclude-standard '*.md' | xargs -0 mdlynx

ruff

We lint and format the Python linting scripts and Ghidra plug-in with ruff.

git ls-files -z --exclude-standard '*.py' | xargs -0 ruff format
git ls-files -z --exclude-standard '*.py' | xargs -0 ruff check

spotless

See the Ghidra batch plugin docs.

tagref

We lint cross-references in code with tagref.

tagref

tagref verifies that every reference refers to an existing tag, and that there are no duplicate tags. The following is the syntax of tags and references:

  • Tags: [tag:snake_case_tag_name]
  • References: [ref:snake_case_tag_name]

tagref can also verify file and directory references (file: and dir:).

We often tag: the documentation for a feature, and then use ref:erences in places in the code that have behavior described in the documentation. This helps us remember to update documentation when we update code, and signals to readers of the code that higher-level documentation that can provide valuable context is available elsewhere.

We highly encourage extensive cross-referencing. It helps us keep documentation and code in sync, and reminds us what needs to be updated in other parts of the codebase when making changes.

ttlint

We lint text files with ttlint.

git ls-files -z --exclude-standard '*.cabal' '*.hs' '*.md' '*.py' '*.scala' | xargs -0 ttlint

typos

We run typos on doc/ to spell-check the documentation. To run it locally, try:

typos doc/