Repository: rstcheck/rstcheck (language: python)

Issue:
[Bug] v6.0.0a1 - WARNING: while setting up extension sphinx.addnodes: node class '...' is already registered, its visitors will be overridden
We're using `rstcheck` as a pre-commit hook in several of our repos, integrated with https://pre-commit.ci and the `v6.0.0a1`  release has bumped the version of the hooks, and seems to be breaking the pre-commit.ci runs, see [this pre-commit.ci autoupdate PR](https://github.com/catalyst-cooperative/intake-sqlite/pull/8).

In our `.pre-commit.yaml` the `rstcheck` section looks like:
```yaml
- repo: https://github.com/myint/rstcheck
  rev: v6.0.0a1
  hooks:
  - id: rstcheck
    additional_dependencies: [sphinx]
    args: ['--config', 'tox.ini']
```

The configuration in `tox.ini` is:
```ini
[rstcheck]
report = warning
ignore_roles =
    pr,
    issue,
    user
ignore_messages = (Hyperlink target ".*" is not referenced\.$)
ignore_directives =
    bibliography,
```

Running the pre-commit hook at the command line like this succeeds just fine:
```sh
pre-commit run --all-files rstcheck
```

But running `rstcheck` directly like this (in a Python environment with the `sphinx` dependencies installed as well):
```sh
rstcheck --recursive --config tox.ini ./
```

Results in [the same failure that is showing up on pre-commit.ci](https://results.pre-commit.ci/run/github/490949616/1652735390.TMfYgMsWT8K89tOj07toFQ):
```txt
WARNING: while setting up extension sphinx.addnodes: node class 'toctree' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'desc' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'desc_signature' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'desc_signature_line' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'desc_content' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'desc_inline' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'desc_name' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'desc_addname' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'desc_type' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'desc_returns' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'desc_parameterlist' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'desc_parameter' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'desc_optional' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'desc_annotation' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'desc_sig_space' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'desc_sig_name' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'desc_sig_operator' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'desc_sig_punctuation' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'desc_sig_keyword' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'desc_sig_keyword_type' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'desc_sig_literal_number' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'desc_sig_literal_string' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'desc_sig_literal_char' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'versionmodified' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'seealso' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'productionlist' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'production' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'index' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'centered' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'acks' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'hlist' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'hlistcol' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'compact_paragraph' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'glossary' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'only' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'start_of_file' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'highlightlang' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'tabular_col_spec' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'pending_xref' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'number_reference' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'download_reference' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'literal_emphasis' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'literal_strong' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'manpage' is already registered, its visitors will be overridden
WARNING: while setting up extension sphinx.addnodes: node class 'meta' is already registered, its visitors will be overridden
Success! No issues detected.
```

Downgrading with `pip install rstcheck[sphinx]==5.0.0` and re-running the above command results in no output at all.

Is this an expected behavior?

_Originally posted by @zaneselvans in https://github.com/myint/rstcheck/issues/104#issuecomment-1128195986_


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml
new file mode 100644
index 00000000..6dfe28e0
--- /dev/null
+++ b/.github/workflows/documentation.yaml
@@ -0,0 +1,62 @@
+---
+name: Test documentation
+
+env:
+  CI_FORCE_COLORS_POETRY: --ansi
+  CI_FORCE_COLORS_SPHINX: --color
+
+on: # yamllint disable-line rule:truthy
+  workflow_dispatch:
+
+  push:
+    tags:
+      - "!*"
+    branches:
+      - master
+      - "test-me-*"
+
+  pull_request:
+    branches:
+      - "**"
+
+jobs:
+  build:
+    name: Tests on ${{ matrix.os }} with default python
+    if: >
+      github.event_name == 'workflow_dispatch' ||
+      github.event_name == 'pull_request' ||
+      (github.event_name == 'push' &&
+      contains(toJson(github.event.head_commit.message), '[skip ci]') == false)
+    runs-on: ${{ matrix.os }}
+    strategy:
+      fail-fast: false
+      matrix:
+        os: ["ubuntu-latest", "windows-latest", "macos-latest"]
+    steps:
+      - uses: actions/checkout@v3
+        with:
+          fetch-depth: 0
+
+      - name: Set up Python
+        uses: actions/setup-python@v3
+
+      - name: Display Python version
+        run: python --version
+
+      - name: Install dependencies
+        run: |
+          python -m pip install --upgrade pip
+          python -m pip install tox
+
+      - name: Set up Homebrew
+        if: runner.os == 'macOS'
+        uses: Homebrew/actions/setup-homebrew@master
+
+      - name: Install enchant on macOS
+        if: runner.os == 'macOS'
+        run: |
+          brew update
+          brew install enchant
+
+      - name: Run tests with tox
+        run: tox -n docs
diff --git a/.github/workflows/qa.yaml b/.github/workflows/qa.yaml
index ac222e52..26ed64c9 100644
--- a/.github/workflows/qa.yaml
+++ b/.github/workflows/qa.yaml
@@ -44,4 +44,4 @@ jobs:
           python -m pip install tox poetry
 
       - name: Run pre-commit with tox
-        run: tox -e pre-commit
+        run: tox -e pre-commit-run
diff --git a/.markdownlint-cli2.jsonc b/.markdownlint-cli2.jsonc
new file mode 100644
index 00000000..4498738e
--- /dev/null
+++ b/.markdownlint-cli2.jsonc
@@ -0,0 +1,35 @@
+// Rules: https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md
+{
+  "config": {
+    "MD003": "atx", // heading-style
+    "MD004": {
+      // ul-style
+      "style": "dash"
+    },
+    "MD013": {
+      // line-length
+      "line_length": 100
+    },
+    "MD014": false, // commands-show-output
+    "MD024": {
+      // no-duplicate-heading
+      "siblings_only": true
+    },
+    "MD035": {
+      // hr-style
+      "style": "---"
+    },
+    "MD048": {
+      // code-fence-style
+      "style": "backtick"
+    },
+    "MD049": {
+      // emphasis-style
+      "style": "underscore"
+    },
+    "MD050": {
+      // strong-style
+      "style": "asterisk"
+    }
+  }
+}
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index f0bd6b9f..cadc1aeb 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -55,7 +55,7 @@ repos:
 
   # pyupgrade - upgrade old syntax to new
   - repo: https://github.com/asottile/pyupgrade
-    rev: 256bd84aa5a17edbd3dcfaaa4f30f870168d2838 # frozen: v2.32.0
+    rev: 4d35c00c9ff5a51a853a89137db5fdd2bdf0ca95 # frozen: v2.32.1
     hooks:
       - id: pyupgrade
         args: ["--py37-plus"]
@@ -157,7 +157,7 @@ repos:
 
   # flakeheaven - wrapper for flake8
   - repo: https://github.com/flakeheaven/flakeheaven
-    rev: "3f0afc179dbd0907230fb3123f2938b0b63d3b7f" # frozen: 0.11.0
+    rev: "20f94457744c47d965d4520d3b22def538b0cc49" # frozen: 0.11.1
     hooks:
       - id: flakeheaven
         types: [python]
@@ -191,7 +191,7 @@ repos:
 
   # poetry - python dependency maJSONnagement
   - repo: https://github.com/python-poetry/poetry
-    rev: dca6ff2699a06c0217ed6d5a278fa3146e4136ff # frozen: 1.2.0b1
+    rev: 1492f0efa8aae73843f7c68ae06b74d2ac78bdd7 # frozen: 1.2.0b1
     hooks:
       - id: poetry-check
 
@@ -211,13 +211,23 @@ repos:
 
   # rstcheck - rst file checker
   - repo: https://github.com/myint/rstcheck
-    rev: 209a4a9850083ba9922f3094a579c4009927906d # frozen: v5.0.0
+    rev: 3a9ecb0f07517895f612cd04a8194390ce5c7b83 # frozen: v6.0.0a2
     hooks:
       - id: rstcheck
         additional_dependencies: [sphinx]
         exclude: testing
         args: ["--config", ".rstcheck.project.cfg"]
 
+  # ----------------------------------------------
+  # Markdown
+  # ----------------------------------------------
+
+  # markdownlint - md file checker
+  - repo: https://github.com/DavidAnson/markdownlint-cli2
+    rev: 79c5e552066e7ad28aca449e7f2eed692a603abf # frozen: v0.4.0
+    hooks:
+      - id: markdownlint-cli2
+
   # ----------------------------------------------
   # TOML / YAML
   # ----------------------------------------------
@@ -240,6 +250,6 @@ repos:
   # ----------------------------------------------
 
   - repo: https://github.com/pre-commit/pre-commit
-    rev: 0276e25f713ddfd66482f358d238186ca47a6eb4 # frozen: v2.18.1
+    rev: cc9d950601cd3eba27e8395a7edcd455262705d9 # frozen: v2.19.0
     hooks:
       - id: validate_manifest
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
new file mode 100644
index 00000000..13d74c76
--- /dev/null
+++ b/.readthedocs.yaml
@@ -0,0 +1,22 @@
+# .readthedocs.yml
+# Read the Docs configuration file
+# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
+---
+version: 2
+
+formats:
+  - htmlzip
+
+python:
+  version: "3.8"
+  system_packages: false
+  install:
+    - method: pip
+      path: .
+      extra_requirements:
+        - docs
+
+sphinx:
+  configuration: docs/source/conf.py
+  fail_on_warning: true
+  builder: dirhtml
diff --git a/.rstcheck.project.cfg b/.rstcheck.project.cfg
index 7db86d06..d276458f 100644
--- a/.rstcheck.project.cfg
+++ b/.rstcheck.project.cfg
@@ -1,2 +1,6 @@
 [rstcheck]
-ignore_messages = Duplicate implicit target name: "breaking changes"|Hyperlink target "beaking-changes-v\d+?((a|b|rc)?\d+?)?" is not referenced.
+ignore_directives =
+    automodule,
+    click,
+    mdinclude,
+    spelling,
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 00000000..67391618
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,344 @@
+# Changelog
+
+This is the changelog of `rstcheck`. Releases and their respective
+changes are listed here. The order of releases is time and **not** version based!
+For a list of all available releases see the
+[tags section on Github](https://github.com/myint/rstcheck/tags).
+Links on the versions point to PyPI.
+
+<!-- Valid subcategories
+### BREAKING CHANGES
+### New features
+### Bugfixes
+### Documentation
+### Miscellaneous
+-->
+
+## Unreleased
+
+[diff v6.0.0a2...master](https://github.com/myint/rstcheck/compare/v6.0.0a2...master)
+
+### New features
+
+- Add more thorough documentation ([#112](https://github.com/myint/rstcheck/pull/112))
+- Add `--log-level` option to CLI ([#108](https://github.com/myint/rstcheck/pull/108))
+- Add `--warn-unknown-settings` flag to CLI ([#118](https://github.com/myint/rstcheck/pull/118))
+- Setup logging to console for CLI ([#108](https://github.com/myint/rstcheck/pull/108))
+- Setup logging to console for library (deactivated by default) ([#108](https://github.com/myint/rstcheck/pull/108))
+
+### BREAKING CHANGES
+
+- `find_ignored_languages` no longer throws exception but logs warning ([#108](https://github.com/myint/rstcheck/pull/108))
+
+## [v6.0.0a2 (2022-05-20)](https://pypi.org/project/rstcheck/6.0.0a2/)
+
+[diff v6.0.0a1...v6.0.0a2](https://github.com/myint/rstcheck/compare/v6.0.0a1...v6.0.0a2)
+
+- Add support for INI multi-line string back ([#116](https://github.com/myint/rstcheck/pull/116))
+- Fix bug #113 - sphinx print warnings for overwriting registered nodes ([#117](https://github.com/myint/rstcheck/pull/117))
+
+### BREAKING CHANGES
+
+- String lists for `ignore_*` configs are white-space cleaned at string start and end.
+  Restores behavior of pre v6. ([#116](https://github.com/myint/rstcheck/pull/116))
+
+## [v6.0.0a1 (2022-05-13)](https://pypi.org/project/rstcheck/6.0.0a1/)
+
+[diff v5.0.0...v6.0.0a1](https://github.com/myint/rstcheck/compare/v5.0.0...v6.0.0a1)
+
+- Fix inability to ignore `code`, `code-block` and `sourcecode` directives ([#79](https://github.com/myint/rstcheck/issues/79))
+- Fix `code-block` options recognition ([#62](https://github.com/myint/rstcheck/issues/62))
+- Add section with `Known limitations / FAQ` to the README ([#97](https://github.com/myint/rstcheck/issues/97))
+- Accumulate all errors in rst source instead of only one ([#83](https://github.com/myint/rstcheck/issues/83))
+- Fix Malformed tables because of substitutions ([#82](https://github.com/myint/rstcheck/pull/82))
+- Fix: remove `include` directive from ignore list when sphinx is active ([#70](https://github.com/myint/rstcheck/issues/70))
+- Allow errors in code blocks to be ignored via ignore_messages ([#100](https://github.com/myint/rstcheck/pull/100))
+- Add support for TOML config files ([#84](https://github.com/myint/rstcheck/pull/84))
+
+### BREAKING CHANGES
+
+- Full restructuring of the code base ([#100](https://github.com/myint/rstcheck/pull/100))
+- Rewrite of CLI with `typer` ([#100](https://github.com/myint/rstcheck/pull/100))
+- Renamed config `report` to `report_level` ([#100](https://github.com/myint/rstcheck/pull/100))
+- Renamed config `ignore_language` to `ignore_languages` ([#100](https://github.com/myint/rstcheck/pull/100))
+- Renamed CLI option `--report` to `--report-level` ([#100](https://github.com/myint/rstcheck/pull/100))
+- Renamed CLI option `--ignore-language` to `--ignore-languages` ([#100](https://github.com/myint/rstcheck/pull/100))
+- Drop CLI option `--ignore` as alias to `--ignore-languages` ([#100](https://github.com/myint/rstcheck/pull/100))
+- Drop CLI option `--debug` ([#100](https://github.com/myint/rstcheck/pull/100))
+- Drop CLI option `--version`; may be added back later ([#100](https://github.com/myint/rstcheck/pull/100))
+- Don't support multi-line strings in INI files ([#100](https://github.com/myint/rstcheck/pull/100))
+- Prohibit numbers as report level ([#100](https://github.com/myint/rstcheck/pull/100))
+- Non-existing files are skipped; `rstcheck non-existing-file.rst` exits 0; may be changed later ([#100](https://github.com/myint/rstcheck/pull/100))
+- Drop support for sphinx < 2.0
+- Drop default values for directives and roles for sphinx ([#65](https://github.com/myint/rstcheck/issues/65))
+- CLI options now take precedence over config file options ([#96](https://github.com/myint/rstcheck/issues/96))
+
+## [v5.0.0 (2022-04-17)](https://pypi.org/project/rstcheck/5.0.0/)
+
+[diff v4.1.0...v5.0.0](https://github.com/myint/rstcheck/compare/v4.1.0...v5.0.0)
+
+- Add examples/ to sdist
+- Add `Development` section to README and update `Testing` section
+- Add `Mega-Linter` section to README
+- Add `BREAKING CHANGES` sections to changelog
+
+### BREAKING CHANGES
+
+- Rewrite test.bash script in pytest test cases and run them on Linux in CI
+- Rewrite old test suite in pytest and AAA style
+
+## [v4.1.0 (2022-04-16)](https://pypi.org/project/rstcheck/4.1.0/)
+
+[diff v4.0.0...v4.1.0](https://github.com/myint/rstcheck/compare/v4.0.0...v4.1.0)
+
+- Fix shebangs and scripts to use `python3` instead of `python` ([#78](https://github.com/myint/rstcheck/pull/78))
+- Improve the gcc checker functions by removing restrictions and
+  using environment variable flags ([#88](https://github.com/myint/rstcheck/pull/88))
+- Fix pool size on windows by setting max to 61 ([#86](https://github.com/myint/rstcheck/pull/86))
+- Update test.bash script and makefile with new file location
+
+## [v4.0.0 (2022-04-15)](https://pypi.org/project/rstcheck/4.0.0/)
+
+[diff v3.5.0...v4.0.0](https://github.com/myint/rstcheck/compare/v3.5.0...v4.0.0)
+
+- Add inline type annotations
+- Add `sphinx` as extra
+- Update build process and set up `poetry`
+- Add `pre-commit` and `tox` for automated testing, linting and formatting
+- Move from travis to github actions
+- Activate dependabot
+
+### BREAKING CHANGES
+
+- Drop support for python versions prior 3.7
+
+## [v3.5.0 (2022-04-14)](https://pypi.org/project/rstcheck/3.5.0/)
+
+[diff v3.4.0...v3.5.0](https://github.com/myint/rstcheck/compare/v3.4.0...v3.5.0)
+
+- Deprecate python versions prior 3.7
+
+## [v3.4.0 (2022-04-12)](https://pypi.org/project/rstcheck/3.4.0/)
+
+[diff v3.3.1...v3.4.0](https://github.com/myint/rstcheck/compare/v3.3.1...v3.4.0)
+
+- Add `--config` option to change the location of the config file.
+- Add `pre-commit` hooks config.
+
+## [v3.3.1 (2018-11-09)](https://pypi.org/project/rstcheck/3.3.1/)
+
+[diff v3.3...v3.3.1](https://github.com/myint/rstcheck/compare/v3.3...v3.3.1)
+
+- Make compatible with Sphinx >= 1.8.
+
+## [v3.3 (2018-03-17)](https://pypi.org/project/rstcheck/3.3/)
+
+[diff v3.2...v3.3](https://github.com/myint/rstcheck/compare/v3.2...v3.3)
+
+- Parse more options from configuration file (thanks to Santos Gallegos).
+- Allow ignoring specific (info/warning/error) messages via
+  `--ignore-messages` (thanks to Santos Gallegos).
+
+## [v3.2 (2018-02-17)](https://pypi.org/project/rstcheck/3.2/)
+
+[diff v3.1...v3.2](https://github.com/myint/rstcheck/compare/v3.1...v3.2)
+
+- Check for invalid Markdown-style links (thanks to biscuitsnake).
+- Allow configuration to be stored in `setup.cfg` (thanks to Maël Pedretti).
+- Add `--recursive` option to recursively drill down directories to check for
+  all `*.rst` files.
+
+## [v3.1 (2017-03-08)](https://pypi.org/project/rstcheck/3.1/)
+
+[diff v3.0.1...v3.1](https://github.com/myint/rstcheck/compare/v3.0.1...v3.1)
+
+- Add support for checking XML code blocks (thanks to Sameer Singh).
+
+## [v3.0.1 (2017-03-02)](https://pypi.org/project/rstcheck/3.0.1/)
+
+[diff v3.0...v3.0.1](https://github.com/myint/rstcheck/compare/v3.0...v3.0.1)
+
+- Support UTF-8 byte order marks (BOM). Previously, `docutils` would
+  interpret the BOM as a visible character, which would lead to false positives
+  about underlines being too short.
+
+## [v3.0 (2016-12-19)](https://pypi.org/project/rstcheck/3.0/)
+
+[diff v2.2...v3.0](https://github.com/myint/rstcheck/compare/v2.2...v3.0)
+
+- Optionally support Sphinx 1.5. Sphinx support will be enabled if Sphinx is
+  installed.
+
+## [v2.2 (2016-10-11)](https://pypi.org/project/rstcheck/2.2/)
+
+[diff v2.1...v2.2](https://github.com/myint/rstcheck/compare/v2.1...v2.2)
+
+- Unknown
+
+## [v2.1 (2016-10-11)](https://pypi.org/project/rstcheck/2.1/)
+
+[diff v2.0...v2.1](https://github.com/myint/rstcheck/compare/v2.0...v2.1)
+
+- Unknown
+
+## [v2.0 (2016-07-27)](https://pypi.org/project/rstcheck/2.0/)
+
+[diff v1.5.1...v2.0](https://github.com/myint/rstcheck/compare/v1.5.1...v2.0)
+
+- Support loading settings from configuration files.
+
+## [v1.5.1 (2016-05-29)](https://pypi.org/project/rstcheck/1.5.1/)
+
+[diff v1.5...v1.5.1](https://github.com/myint/rstcheck/compare/v1.5...v1.5.1)
+
+- Unknown
+
+## [v1.5 (2016-02-03)](https://pypi.org/project/rstcheck/1.5/)
+
+[diff v1.4.2...v1.5](https://github.com/myint/rstcheck/compare/v1.4.2...v1.5)
+
+- Unknown
+
+## [v1.4.2 (2015-12-16)](https://pypi.org/project/rstcheck/1.4.2/)
+
+[diff v1.4.1...v1.4.2](https://github.com/myint/rstcheck/compare/v1.4.1...v1.4.2)
+
+- Unknown
+
+## [v1.4.1 (2015-08-16)](https://pypi.org/project/rstcheck/1.4.1/)
+
+[diff v1.4...v1.4.1](https://github.com/myint/rstcheck/compare/v1.4...v1.4.1)
+
+- Unknown
+
+## [v1.4 (2015-06-26)](https://pypi.org/project/rstcheck/1.4/)
+
+[diff v1.3.1...v1.4](https://github.com/myint/rstcheck/compare/v1.3.1...v1.4)
+
+- Unknown
+
+## [v1.3.1 (2015-04-14)](https://pypi.org/project/rstcheck/1.3.1/)
+
+[diff v1.3...v1.3.1](https://github.com/myint/rstcheck/compare/v1.3...v1.3.1)
+
+- Unknown
+
+## [v1.3 (2015-04-11)](https://pypi.org/project/rstcheck/1.3/)
+
+[diff v1.2.1...v1.3](https://github.com/myint/rstcheck/compare/v1.2.1...v1.3)
+
+- Unknown
+
+## [v1.2.1 (2015-04-11)](https://pypi.org/project/rstcheck/1.2.1/)
+
+[diff v1.2...v1.2.1](https://github.com/myint/rstcheck/compare/v1.2...v1.2.1)
+
+- Unknown
+
+## [v1.2 (2015-04-11)](https://pypi.org/project/rstcheck/1.2/)
+
+[diff v1.1.1...v1.2](https://github.com/myint/rstcheck/compare/v1.1.1...v1.2)
+
+- Unknown
+
+## [v1.1.1 (2015-04-05)](https://pypi.org/project/rstcheck/1.1.1/)
+
+[diff v1.1...v1.1.1](https://github.com/myint/rstcheck/compare/v1.1...v1.1.1)
+
+- Unknown
+
+## [v1.1 (2015-04-03)](https://pypi.org/project/rstcheck/1.1/)
+
+[diff v1.0...v1.1](https://github.com/myint/rstcheck/compare/v1.0...v1.1)
+
+- Unknown
+
+## [v1.0 (2015-03-14)](https://pypi.org/project/rstcheck/1.0/)
+
+[diff v0.6...v1.0](https://github.com/myint/rstcheck/compare/v0.6...v1.0)
+
+- Add Sphinx support.
+
+## [v0.6 (2014-09-25)](https://pypi.org/project/rstcheck/0.6/)
+
+[diff v0.5.1...v0.6](https://github.com/myint/rstcheck/compare/v0.5.1...v0.6)
+
+- Unknown
+
+## [v0.5.1 (2014-08-23)](https://pypi.org/project/rstcheck/0.5.1/)
+
+[diff v0.5...v0.5.1](https://github.com/myint/rstcheck/compare/v0.5...v0.5.1)
+
+- Unknown
+
+## [v0.5 (2014-06-01)](https://pypi.org/project/rstcheck/0.5/)
+
+[diff v0.4.1...v0.5](https://github.com/myint/rstcheck/compare/v0.4.1...v0.5)
+
+- Unknown
+
+## [v0.4.1 (2014-05-31)](https://pypi.org/project/rstcheck/0.4.1/)
+
+[diff v0.4...v0.4.1](https://github.com/myint/rstcheck/compare/v0.4...v0.4.1)
+
+- Unknown
+
+## [v0.4 (2014-05-24)](https://pypi.org/project/rstcheck/0.4/)
+
+[diff v0.3.6...v0.4](https://github.com/myint/rstcheck/compare/v0.3.6...v0.4)
+
+- Unknown
+
+## [v0.3.6 (2014-04-12)](https://pypi.org/project/rstcheck/0.3.6/)
+
+[diff v0.3.5...v0.3.6](https://github.com/myint/rstcheck/compare/v0.3.5...v0.3.6)
+
+- Unknown
+
+## [v0.3.5 (2014-01-25)](https://pypi.org/project/rstcheck/0.3.5/)
+
+[diff v0.3.4...v0.3.5](https://github.com/myint/rstcheck/compare/v0.3.4...v0.3.5)
+
+- Unknown
+
+## [v0.3.4 (2013-12-29)](https://pypi.org/project/rstcheck/0.3.4/)
+
+[diff v0.3.3...v0.3.4](https://github.com/myint/rstcheck/compare/v0.3.3...v0.3.4)
+
+- Unknown
+
+## [v0.3.3 (2013-12-28)](https://pypi.org/project/rstcheck/0.3.3/)
+
+[diff v0.3.2...v0.3.3](https://github.com/myint/rstcheck/compare/v0.3.2...v0.3.3)
+
+- Unknown
+
+## [v0.3.2 (2013-12-27)](https://pypi.org/project/rstcheck/0.3.2/)
+
+[diff v0.3.1...v0.3.2](https://github.com/myint/rstcheck/compare/v0.3.1...v0.3.2)
+
+- Unknown
+
+## v0.3.1
+
+[diff v0.2...v0.3.1](https://github.com/myint/rstcheck/compare/v0.2...v0.3.1)
+
+- Unknown
+
+## v0.2
+
+[diff v0.1.1...v0.2](https://github.com/myint/rstcheck/compare/v0.1.1...v0.2)
+
+- Unknown
+
+## v0.1.1
+
+[diff v0.1...v0.1.1](https://github.com/myint/rstcheck/compare/v0.1...v0.1.1)
+
+- Unknown
+
+## v0.1 (2013-12-02)
+
+[diff a146c93...v0.1](https://github.com/myint/rstcheck/compare/a146c93...v0.1)
+
+- Initial version.
diff --git a/README.rst b/README.rst
index 110355b7..8a56250f 100644
--- a/README.rst
+++ b/README.rst
@@ -2,24 +2,24 @@
 rstcheck
 ========
 
-.. image:: https://github.com/myint/rstcheck/workflows/Test%20code/badge.svg?branch=master
-    :target: https://github.com/myint/rstcheck/actions/workflows/test.yaml
-    :alt: Test status
++-------------------+---------------------------------------------------------------------------------------------+
+| **General**       | |maintenance_y| |license| |semver|                                                          |
+|                   +---------------------------------------------------------------------------------------------+
+|                   | |gha_tests| |gha_docu| |gha_qa|                                                             |
++-------------------+---------------------------------------------------------------------------------------------+
+| **PyPI**          | |pypi_release| |pypi_py_versions| |pypi_implementations|                                    |
+|                   +---------------------------------------------------------------------------------------------+
+|                   | |pypi_format| |pypi_downloads|                                                              |
++-------------------+---------------------------------------------------------------------------------------------+
+| **Github**        | |gh_tag| |gh_last_commit|                                                                   |
+|                   +---------------------------------------------------------------------------------------------+
+|                   | |gh_stars| |gh_forks| |gh_contributors| |gh_watchers|                                       |
++-------------------+---------------------------------------------------------------------------------------------+
 
-.. image:: https://github.com/myint/rstcheck/workflows/QA/badge.svg?branch=master
-    :target: https://github.com/myint/rstcheck/actions/workflows/qa.yaml
-    :alt: QA status
-
-.. image:: https://img.shields.io/pypi/dm/rstcheck?color=brightgreen&logo=pypi&logoColor=yellow
-    :target: https://pypi.org/project/rstcheck/
-    :alt: Downloads PyPI
 
 Checks syntax of reStructuredText and code blocks nested within it.
 
 
-***Documentation will be updated soon.***
-
-
 .. contents::
 
 
@@ -36,6 +36,11 @@ To use pyproject.toml for configuration::
 
     $ pip install rstcheck[toml]
 
+To add sphinx support::
+
+    $ pip install rstcheck[sphinx]
+
+
 Supported languages in code blocks
 ==================================
 
@@ -52,6 +57,8 @@ Supported languages in code blocks
 Examples
 ========
 
+.. rstcheck: ignore-languages=cpp,python,rst
+
 With bad Python syntax:
 
 .. code:: rst
@@ -103,508 +110,83 @@ With bad syntax in the reStructuredText document itself:
     bad_rst.rst:1: (SEVERE/4) Title overline & underline mismatch.
 
 
-Options
-=======
-
-If ``sphinx`` and ``tomli`` are installed:
-
-.. code:: text
-
-    Usage: rstcheck [OPTIONS] FILES...
-
-    CLI of rstcheck.
-
-    Enabled features: ['Sphinx', 'Toml']
-
-    Arguments:
-    FILES...  RST files to check. Can be files or directories if --recursive is
-                passed too.  [required]
-
-    Options:
-    --config PATH                Config file to load. Can be a INI or TOML file
-                                or directory. If a directory is passed it will
-                                be searched for .rstcheck.cfg | pyproject.toml
-                                | setup.cfg.
-    -r, --recursive              Recursively search passed directories for RST
-                                files to check.
-    --report-level LEVEL         The report level of the linting issues found.
-                                Valid levels are: INFO | WARNING | ERROR |
-                                SEVERE | NONE. Defauls to INFO. Can be set in
-                                config file.
-    --log-level LEVEL            The log level of the application for
-                                information that is not a linting issue. Valid
-                                levels are: DEBUG | INFO | WARNING | ERROR |
-                                CRITICAL. Defauls to WARNING.  [default:
-                                WARNING]
-    --ignore-directives TEXT     Comma-separated-list of directives to add to
-                                the ignore list. Can be set in config file.
-    --ignore-roles TEXT          Comma-separated-list of roles to add to the
-                                ignore list. Can be set in config file.
-    --ignore-substitutions TEXT  Comma-separated-list of substitutions to add to
-                                the ignore list. Can be set in config file.
-    --ignore-languages TEXT      Comma-separated-list of languages for code-
-                                blocks to add to the ignore list. The code in
-                                ignored code-blocks will not be checked for
-                                errors. Can be set in config file.
-    --ignore-messages REGEX      A regular expression to match linting issue
-                                messages against to ignore. Can be set in
-                                config file.
-    --install-completion         Install completion for the current shell.
-    --show-completion            Show completion for the current shell, to copy
-                                it or customize the installation.
-    --help                       Show this message and exit.
-
-
-Ignore specific languages
-=========================
-
-You can ignore checking of nested code blocks by language. Either use the
-command-line option ``--ignore-languages`` or put a comment in the document:
-
-.. code:: rst
-
-    .. rstcheck: ignore-languages=cpp,python,rst
-
-
-Ignore specific errors
-======================
-
-Since docutils doesn't categorize their error messages beyond the high-level
-categories of: info, warning, error, and severe; we need filter them out at a
-textual level. This is done by passing a Python regex. As example you can pass
-a regex like this to ignore several errors
-
-.. code:: text
-
-    (Title underline too short.*|Duplicate implicit target.*')
-
-
-Configuration file
-==================
-
-You can use the same arguments from the command line as options in the
-local configuration file of the project (just replace ``-`` for ``_``).
-``rstcheck`` looks for a file ``.rstcheck.cfg``, ``setup.cfg``, or
-``pyproject.toml`` in the directory or ancestor directories of the file it is
-checking.
-
-``.rstcheck.cfg`` takes precedence over ``setup.cfg``.
-
-Settings in the config file are overwritten by CLI options.
-
-For example, consider a project with the following directory structure
-
-.. code:: text
-
-    foo
-    ├── docs
-    │   └── bar.rst
-    ├── index.rst
-    └── .rstcheck.cfg
-
-``.rstcheck.cfg`` contains:
-
-.. code:: ini
-
-    [rstcheck]
-    ignore_directives=one,two,three
-    ignore_roles=src,RFC
-    ignore_messages=(Document or section may not begin with a transition\.$)
-    report_level=warning
-
-``bar.rst`` contains:
-
-.. code:: rst
-
-    Bar
-    ===
-
-    :src:`hello_world.py`
-    :RFC:`793`
-
-    .. one::
-
-       Hello
-
-``rstcheck`` will make use of the ``.rstcheck.cfg``
-
-.. code:: shell
-
-    $ rstcheck foo/docs/bar.rst
-
-
-For a Python project, you should put the configuration settings for
-``rstcheck`` inside the general ``setup.cfg`` `distutils configuration file`_,
-in the project root.
-
-For a PEP-517/PEP-518 project, you should put the configuration settings for
-``rstcheck`` inside the ``pyproject.toml`` configuration file in the project
-root.  These should be placed in a ``[tool.rstcheck]`` section.  Keep in mind
-backslashes need to be escaped, so to ignore the message
-``"(Document or section may not begin with a transition\.$)"`` you'll need to
-escape the backslash in ``pyproject.toml`` like this
-``"(Document or section may not begin with a transition\\.$)"``.  See the
-``pyproject.toml`` file in ``examples/with_configuration``.
-
-You can override the location of the config file with the ``--config`` argument
-
-.. code:: shell
-
-    $ rstcheck --config $HOME/.rstcheck.ini foo/docs/bar.rst
-
-will use the file ``.rstcheck.ini`` in your home directory. If the argument to
-``--config`` is a directory, ``rstcheck`` will search that directory and any
-any of its ancestors for a file ``.rstcheck.cfg`` or ``setup.cfg``
-
-.. code:: shell
-
-   $ rstcheck --config foo /tmp/bar.rst
-
-would use the project configuration in ``./foo/.rstcheck.cfg`` to check the
-unrelated file ``/tmp/bar.rst``.
-
-.. _distutils configuration file: https://docs.python.org/3/distutils/configfile.html
-
-
-Sphinx
-======
-
-To enable Sphinx
-
-.. code:: shell
-
-    $ pip install rstcheck[sphinx]
-
-    # or
-
-    $ pip install sphinx
-
-With version 4.0 ``rstcheck`` added Sphinx as an optional extra where the version's lower
-constraint is >=4.0 because of Sphinx's open upper constraints on jinja2 and markupsafe,
-which result in import errors if not pinned below version 3 and 2 respectively. This happend
-in Sphinx version 4.0.
-
-You can also add Sphinx by yourself but the installed Sphinx version must be at least 2.0.
-
-To check that Sphinx support is enabled
-
-.. code:: shell
-
-    $ rstcheck -h | grep 'Sphinx is enabled'
-
-
-Usage in Vim
-============
-
-
-Using with Syntastic_:
-----------------------
-
-.. code:: vim
-
-    let g:syntastic_rst_checkers = ['rstcheck']
-
-
-Using with ALE_:
-----------------
-
-Just install ``rstcheck`` and make sure is on your path.
-
-.. _Syntastic: https://github.com/scrooloose/syntastic
-.. _ALE: https://github.com/w0rp/ale
-
-
-Use as a module
-===============
-
-``rstcheck.check()`` yields a series of tuples. The first value of each tuple
-is the line number (not the line index). The second value is the error message.
-
->>> import rstcheck
->>> list(rstcheck.check('Example\n==='))
-[(2, '(INFO/1) Possible title underline, too short for the title.')]
-
-Note that this does not load any configuration as that would mutate the
-``docutils`` registries.
-
-
-Use as a pre-commit hook
-========================
+.. General
 
-Add this to your ``.pre-commit-config.yaml``
+.. |maintenance_n| image:: https://img.shields.io/badge/Maintenance%20Intended-✖-red.svg?style=flat-square
+    :target: http://unmaintained.tech/
+    :alt: Maintenance - not intended
 
-.. code:: yaml
+.. |maintenance_y| image:: https://img.shields.io/badge/Maintenance%20Intended-✔-green.svg?style=flat-square
+    :target: http://unmaintained.tech/
+    :alt: Maintenance - intended
 
-    -   repo: https://github.com/myint/rstcheck
-        rev: ''  # Use the sha / tag you want to point at
-        hooks:
-        -   id: rstcheck
+.. |license| image:: https://img.shields.io/github/license/myint/rstcheck.svg?style=flat-square&label=License
+    :target: https://github.com/myint/rstcheck/blob/main/LICENSE
+    :alt: License
 
+.. |semver| image:: https://img.shields.io/badge/Semantic%20Versioning-2.0.0-brightgreen.svg?style=flat-square
+    :target: https://semver.org/
+    :alt: Semantic Versioning - 2.0.0
 
-Use with Mega-Linter:
-=====================
-
-Just install `Mega-Linter <https://nvuillam.github.io/mega-linter/>`__ in your repository,
-`rstcheck <https://nvuillam.github.io/mega-linter/descriptors/rst_rstcheck/>`__
-is part of the 70 linters activated out of the box.
-
-
-Development
-===========
-
-This project relies on `poetry`_ as its management tool for dependencies, building and venvs.
-You do not need to have `poetry`_ installed globally, but it is recommended to.
-
-For development venv creation run
-
-.. code:: shell
-
-    $ poetry install
-
-    # or without global `poetry`
-
-    $ python3 -m venv .venv
-    $ source .venv/bin/activate
-    $ pip install poetry
-
-With global `poetry`_ you do not need to activate the venv. `poetry`_ will run
-commands inside the venv if you call them like this
-
-.. code:: shell
-
-    $ poetry run COMMAND
-
-.. _poetry: https://python-poetry.org/
-
-
-Testing
--------
-
-Unit tests are in ``tests/test_rstcheck.py``.
-System tests are in ``tests/test_as_cli_tool.py``.
-
-System tests are composed of example good/bad input. The test inputs are
-contained in the ``testing/examples`` directory. For basic tests, adding a test should
-just be a matter of adding files to ``examples/good`` or ``examples/bad``.
-
-To run all the tests you have three options
-
-.. code:: shell
-
-    # With global `poetry` or with active development venv:
-    $ poetry run tox
-
-    # With active development venv:
-    $ tox
-
-    # Without `poetry` and development venv:
-    $ python3 -m venv .venv
-    $ source .venv/bin/activate
-    $ pip install tox
-    $ tox
-
-
-Known limitations / FAQ
-=======================
-
-There are inherent limitations to what ``rstcheck`` can and cannot do. The reason for this is that
-``rstcheck`` itself does not parse the rst source but gives it to ``docutils`` and gets the errors
-back. Therefore rstcheck in the sense of rst source is more an error accumulation tool. The same
-goes for the source code in supported code blocks.
-
-
-History
-=======
-
-
-(next version)
---------------
-
-- Add ``--log-level`` option to CLI (#108)
-- Setup logging to console for CLI (#108)
-- Setup logging to console for library (deactivated by default) (#108)
-- Add ``--warn-unknown-settings`` flag to CLI (#115)
-
-
-.. _beaking_changes_v6:
-
-BREAKING CHANGES
-~~~~~~~~~~~~~~~~
-
-- ``find_ignored_languages`` no longer throws exception but loggs warning (#108)
-
-
-6.0.0a2 (2022-05-20)
---------------------
-
-- Add support for INI multi-line string back (#116)
-- Fix bug #113 - sphinx print warnings for overwriting registered nodes (#117)
-
-
-.. _beaking_changes_v6a2:
-
-BREAKING CHANGES
-~~~~~~~~~~~~~~~~
-
-- String lists for ``ignore_*`` configs are whitespace cleaned at string start and end.
-  Restores behavior of pre v6. (#116)
-
-
-6.0.0a1 (2022-05-13)
---------------------
-
-- Fix inability to ignore ``code``, ``code-block`` and ``sourcecode`` directives (#79)
-- Fix ``code-block`` options recognition (#62)
-- Add section with ``Known limitations / FAQ`` to the README (#97)
-- Accumulate all errors in rst source instead of only one (#83)
-- Fix Malformed tables because of substitutions (#82)
-- Fix: remove ``include`` directive from ignore list when sphinx is active (#70)
-- Allow errors in code blocks to be ignored via ignore_messages (#100)
-
-
-.. _beaking_changes_v6a1:
-
-BREAKING CHANGES
-~~~~~~~~~~~~~~~~
-
-- Full restructuring of the code base (#100)
-- Rewrite of CLI with ``typer`` (#100)
-- Renamed config ``report`` to ``report_level`` (#100)
-- Renamed config ``ignore_language`` to ``ignore_languages`` (#100)
-- Renamed CLI option ``--report`` to ``--report-level`` (#100)
-- Renamed CLI option ``--ignore-language`` to ``--ignore-languages`` (#100)
-- Drop CLI option ``--ignore`` as alias to ``--ignore-languages`` (#100)
-- Drop CLI option ``--debug`` (#100)
-- Drop CLI option ``--version``; may be readded later (#100)
-- Don't support multiline strings in INI files (#100)
-- Allow a string or list of strings for ``ignore_messages`` in TOML config files (#100)
-- Prohibit numbers as report level (#100)
-- Non-existing files are skipped; ``rstcheck non-existing-file.rst`` exits 0; may be changed later (#100)
-- Drop support for sphinx < 2.0
-- Drop default values for directves and roles for sphinx (#65)
-- CLI options now take precedence over config file options (#96)
-
-
-5.0.0 (2022-04-17)
-------------------
-
-- Add examples/ to sdist
-- Add ``Development`` section to README and update ``Testing`` section
-- Add ``Mega-Linter`` section to README
-- Add ``BREAKING CHANGES`` sections to changelog
-
-
-.. _beaking_changes_v5:
-
-BREAKING CHANGES
-~~~~~~~~~~~~~~~~
-
-- Rewrite test.bash script in pytest test cases adn run them on linux in CI
-- Rewrite old test suite in pytest and AAA style
-
-
-4.1.0 (2022-04-16)
-------------------
-
-- Fix shebangs and scripts to use ``python3`` instead of ``python`` (#78)
-- Improve the gcc checker functions by removing restrictions and
-  using environment variable flags (#88)
-- Fix pool size on windows by setting max to 61 (#86)
-- Update test.bash script and makefile with new file location
-
-
-4.0.0 (2022-04-15)
-------------------
-
-- Add inline type annotations
-- Add ``sphinx`` as extra
-- Update build process and set up ``poetry``
-- Add ``pre-commit`` and ``tox`` for automated testing, linting and formatting
-- Move from travis to github actions
-- Activate dependabot
-
-
-.. _beaking_changes_v4:
-
-BREAKING CHANGES
-~~~~~~~~~~~~~~~~
-
-- Drop support for python versions prior 3.7
-
-
-3.5.0 (2022-04-14)
-------------------
-
-- Deprecate python versions prior 3.7
-
-
-3.4.0 (2022-04-12)
-------------------
-
-- Add ``--config`` option to change the location of the config file.
-- Add ``pre-commit`` hooks config.
-
-
-3.3.1 (2018-10-09)
-------------------
-
-- Make compatible with Sphinx >= 1.8.
-
-
-3.3 (2018-03-17)
-----------------
-
-- Parse more options from configuration file (thanks to Santos Gallegos).
-- Allow ignoring specific (info/warning/error) messages via
-  ``--ignore-messages`` (thanks to Santos Gallegos).
-
-
-3.2 (2018-02-17)
-----------------
-
-- Check for invalid Markdown-style links (thanks to biscuitsnake).
-- Allow configuration to be stored in ``setup.cfg`` (thanks to Maël Pedretti).
-- Add ``--recursive`` option to recursively drill down directories to check for
-  all ``*.rst`` files.
-
-
-3.1 (2017-03-08)
-----------------
+.. |gha_tests| image:: https://img.shields.io/github/workflow/status/myint/rstcheck/Test%20code/master?style=flat-square&logo=github&label=Test%20code
+    :target: https://github.com/myint/rstcheck/actions/workflows/test.yaml
+    :alt: Test status
 
-- Add support for checking XML code blocks (thanks to Sameer Singh).
+.. |gha_docu| image:: https://img.shields.io/github/workflow/status/myint/rstcheck/Test%20documentation/master?style=flat-square&logo=github&label=Test%20documentation
+    :target: https://github.com/myint/rstcheck/actions/workflows/test.yaml
+    :alt: Test status
 
+.. |gha_qa| image:: https://img.shields.io/github/workflow/status/myint/rstcheck/QA/master?style=flat-square&logo=github&label=QA
+    :target: https://github.com/myint/rstcheck/actions/workflows/qa.yaml
+    :alt: QA status
 
-3.0.1 (2017-03-01)
-------------------
 
-- Support UTF-8 byte order marks (BOM). Previously, ``docutils`` would
-  interpret the BOM as a visible character, which would lead to false positives
-  about underlines being too short.
+.. PyPI
 
+.. |pypi_release| image:: https://img.shields.io/pypi/v/rstcheck.svg?style=flat-square&logo=pypi&logoColor=FBE072
+    :target: https://pypi.org/project/rstcheck/
+    :alt: PyPI - Package latest release
 
-3.0 (2016-12-19)
-----------------
+.. |pypi_py_versions| image:: https://img.shields.io/pypi/pyversions/rstcheck.svg?style=flat-square&logo=python&logoColor=FBE072
+    :target: https://pypi.org/project/rstcheck/
+    :alt: PyPI - Supported Python Versions
 
-- Optionally support Sphinx 1.5. Sphinx support will be enabled if Sphinx is
-  installed.
+.. |pypi_implementations| image:: https://img.shields.io/pypi/implementation/rstcheck.svg?style=flat-square&logo=python&logoColor=FBE072
+    :target: https://pypi.org/project/rstcheck/
+    :alt: PyPI - Supported Implementations
 
+.. |pypi_format| image:: https://img.shields.io/pypi/format/rstcheck.svg?style=flat-square&logo=pypi&logoColor=FBE072
+    :target: https://pypi.org/project/rstcheck/
+    :alt: PyPI - Format
 
-2.0 (2015-07-27)
-----------------
+.. |pypi_downloads| image:: https://img.shields.io/pypi/dm/rstcheck.svg?style=flat-square&logo=pypi&logoColor=FBE072
+    :target: https://pypi.org/project/rstcheck/
+    :alt: PyPI - Monthly downloads
 
-- Support loading settings from configuration files.
 
 
-1.0 (2015-03-14)
-----------------
+.. GitHub
 
-- Add Sphinx support.
+.. |gh_tag| image:: https://img.shields.io/github/v/tag/myint/rstcheck.svg?sort=semver&style=flat-square&logo=github
+    :target: https://github.com/myint/rstcheck/tags
+    :alt: Github - Latest Release
 
+.. |gh_last_commit| image:: https://img.shields.io/github/last-commit/myint/rstcheck.svg?style=flat-square&logo=github
+    :target: https://github.com/myint/rstcheck/commits/main
+    :alt: GitHub - Last Commit
 
-0.1 (2013-12-02)
-----------------
+.. |gh_stars| image:: https://img.shields.io/github/stars/myint/rstcheck.svg?style=flat-square&logo=github
+    :target: https://github.com/myint/rstcheck/stargazers
+    :alt: Github - Stars
 
-- Initial version.
+.. |gh_forks| image:: https://img.shields.io/github/forks/myint/rstcheck.svg?style=flat-square&logo=github
+    :target: https://github.com/myint/rstcheck/network/members
+    :alt: Github - Forks
 
+.. |gh_contributors| image:: https://img.shields.io/github/contributors/myint/rstcheck.svg?style=flat-square&logo=github
+    :target: https://github.com/myint/rstcheck/graphs/contributors
+    :alt: Github - Contributors
 
-.. rstcheck: ignore-languages=cpp,python,rst
+.. |gh_watchers| image:: https://img.shields.io/github/watchers/myint/rstcheck.svg?style=flat-square&logo=github
+    :target: https://github.com/myint/rstcheck/watchers/
+    :alt: Github - Watchers
diff --git a/docs/source/_apidoc_templates/module.rst_t b/docs/source/_apidoc_templates/module.rst_t
new file mode 100644
index 00000000..49cca84b
--- /dev/null
+++ b/docs/source/_apidoc_templates/module.rst_t
@@ -0,0 +1,8 @@
+{%- if show_headings %}
+{{- [basename, "module"] | join(' ') | e | heading }}
+
+{% endif -%}
+.. automodule:: {{ qualname }}
+{%- for option in automodule_options %}
+   :{{ option }}:
+{%- endfor %}
diff --git a/docs/source/_apidoc_templates/package.rst_t b/docs/source/_apidoc_templates/package.rst_t
new file mode 100644
index 00000000..b7380e8a
--- /dev/null
+++ b/docs/source/_apidoc_templates/package.rst_t
@@ -0,0 +1,53 @@
+{%- macro automodule(modname, options) -%}
+.. automodule:: {{ modname }}
+{%- for option in options %}
+   :{{ option }}:
+{%- endfor %}
+{%- endmacro %}
+
+{%- macro toctree(docnames) -%}
+.. toctree::
+   :maxdepth: {{ maxdepth }}
+{% for docname in docnames %}
+   {{ docname }}
+{%- endfor %}
+{%- endmacro %}
+
+{%- if is_namespace %}
+{{- [pkgname, "namespace"] | join(" ") | e | heading }}
+{% else %}
+{{- [pkgname, "package"] | join(" ") | e | heading }}
+{% endif %}
+
+{%- if modulefirst and not is_namespace %}
+{{ automodule(pkgname, automodule_options) }}
+{% endif %}
+
+{%- if subpackages %}
+Subpackages
+-----------
+
+{{ toctree(subpackages) }}
+{% endif %}
+
+{%- if submodules %}
+Submodules
+----------
+{% if separatemodules %}
+{{ toctree(submodules) }}
+{% else %}
+{%- for submodule in submodules %}
+{% if show_headings %}
+{{- [submodule, "module"] | join(" ") | e | heading(2) }}
+{% endif %}
+{{ automodule(submodule, automodule_options) }}
+{% endfor %}
+{%- endif %}
+{%- endif %}
+
+{%- if not modulefirst and not is_namespace %}
+Module contents
+---------------
+
+{{ automodule(pkgname, automodule_options) }}
+{% endif %}
diff --git a/docs/source/_apidoc_templates/toc.rst_t b/docs/source/_apidoc_templates/toc.rst_t
new file mode 100644
index 00000000..878540ce
--- /dev/null
+++ b/docs/source/_apidoc_templates/toc.rst_t
@@ -0,0 +1,7 @@
+{{ header | heading }}
+
+.. toctree::
+   :maxdepth: {{ maxdepth }}
+{% for docname in docnames %}
+   {{ docname }}
+{%- endfor %}
diff --git a/docs/source/_badges.rst b/docs/source/_badges.rst
new file mode 100644
index 00000000..26bc21f9
--- /dev/null
+++ b/docs/source/_badges.rst
@@ -0,0 +1,99 @@
++-------------------+---------------------------------------------------------------------------------------------+
+| **General**       | |maintenance_y| |license| |semver|                                                          |
+|                   +---------------------------------------------------------------------------------------------+
+|                   | |gha_tests| |gha_docu| |gha_qa|                                                             |
++-------------------+---------------------------------------------------------------------------------------------+
+| **PyPI**          | |pypi_release| |pypi_py_versions| |pypi_implementations|                                    |
+|                   +---------------------------------------------------------------------------------------------+
+|                   | |pypi_format| |pypi_downloads|                                                              |
++-------------------+---------------------------------------------------------------------------------------------+
+| **Github**        | |gh_tag| |gh_last_commit|                                                                   |
+|                   +---------------------------------------------------------------------------------------------+
+|                   | |gh_stars| |gh_forks| |gh_contributors| |gh_watchers|                                       |
++-------------------+---------------------------------------------------------------------------------------------+
+
+
+.. Change badges in README also
+
+.. General
+
+.. Change maintenance status in README also
+
+.. |maintenance_n| image:: https://img.shields.io/badge/Maintenance%20Intended-✖-red.svg?style=flat-square
+    :target: http://unmaintained.tech/
+    :alt: Maintenance - not intended
+
+.. |maintenance_y| image:: https://img.shields.io/badge/Maintenance%20Intended-✔-green.svg?style=flat-square
+    :target: http://unmaintained.tech/
+    :alt: Maintenance - intended
+
+.. |license| image:: https://img.shields.io/github/license/myint/rstcheck.svg?style=flat-square&label=License
+    :target: https://github.com/myint/rstcheck/blob/master/LICENSE
+    :alt: License
+
+.. |semver| image:: https://img.shields.io/badge/Semantic%20Versioning-2.0.0-brightgreen.svg?style=flat-square
+    :target: https://semver.org/
+    :alt: Semantic Versioning - 2.0.0
+
+.. |gha_tests| image:: https://img.shields.io/github/workflow/status/myint/rstcheck/Test%20code/master?style=flat-square&logo=github&label=Test%20code
+    :target: https://github.com/myint/rstcheck/actions/workflows/test.yaml
+    :alt: Test status
+
+.. |gha_docu| image:: https://img.shields.io/github/workflow/status/myint/rstcheck/Test%20documentation/master?style=flat-square&logo=github&label=Test%20documentation
+    :target: https://github.com/myint/rstcheck/actions/workflows/test.yaml
+    :alt: Test status
+
+.. |gha_qa| image:: https://img.shields.io/github/workflow/status/myint/rstcheck/QA/master?style=flat-square&logo=github&label=QA
+    :target: https://github.com/myint/rstcheck/actions/workflows/qa.yaml
+    :alt: QA status
+
+
+.. PyPI
+
+.. |pypi_release| image:: https://img.shields.io/pypi/v/rstcheck.svg?style=flat-square&logo=pypi&logoColor=FBE072
+    :target: https://pypi.org/project/rstcheck/
+    :alt: PyPI - Package latest release
+
+.. |pypi_py_versions| image:: https://img.shields.io/pypi/pyversions/rstcheck.svg?style=flat-square&logo=python&logoColor=FBE072
+    :target: https://pypi.org/project/rstcheck/
+    :alt: PyPI - Supported Python Versions
+
+.. |pypi_implementations| image:: https://img.shields.io/pypi/implementation/rstcheck.svg?style=flat-square&logo=python&logoColor=FBE072
+    :target: https://pypi.org/project/rstcheck/
+    :alt: PyPI - Supported Implementations
+
+.. |pypi_format| image:: https://img.shields.io/pypi/format/rstcheck.svg?style=flat-square&logo=pypi&logoColor=FBE072
+    :target: https://pypi.org/project/rstcheck/
+    :alt: PyPI - Format
+
+.. |pypi_downloads| image:: https://img.shields.io/pypi/dm/rstcheck.svg?style=flat-square&logo=pypi&logoColor=FBE072
+    :target: https://pypi.org/project/rstcheck/
+    :alt: PyPI - Monthly downloads
+
+
+
+.. GitHub
+
+.. |gh_tag| image:: https://img.shields.io/github/v/tag/myint/rstcheck.svg?sort=semver&style=flat-square&logo=github
+    :target: https://github.com/myint/rstcheck/tags
+    :alt: Github - Latest Release
+
+.. |gh_last_commit| image:: https://img.shields.io/github/last-commit/myint/rstcheck.svg?style=flat-square&logo=github
+    :target: https://github.com/myint/rstcheck/commits/master
+    :alt: GitHub - Last Commit
+
+.. |gh_stars| image:: https://img.shields.io/github/stars/myint/rstcheck.svg?style=flat-square&logo=github
+    :target: https://github.com/myint/rstcheck/stargazers
+    :alt: Github - Stars
+
+.. |gh_forks| image:: https://img.shields.io/github/forks/myint/rstcheck.svg?style=flat-square&logo=github
+    :target: https://github.com/myint/rstcheck/network/members
+    :alt: Github - Forks
+
+.. |gh_contributors| image:: https://img.shields.io/github/contributors/myint/rstcheck.svg?style=flat-square&logo=github
+    :target: https://github.com/myint/rstcheck/graphs/contributors
+    :alt: Github - Contributors
+
+.. |gh_watchers| image:: https://img.shields.io/github/watchers/myint/rstcheck.svg?style=flat-square&logo=github
+    :target: https://github.com/myint/rstcheck/watchers/
+    :alt: Github - Watchers
diff --git a/docs/source/api.rst b/docs/source/api.rst
new file mode 100644
index 00000000..c2bda787
--- /dev/null
+++ b/docs/source/api.rst
@@ -0,0 +1,20 @@
+===
+API
+===
+
+.. spelling::
+
+    apidoc
+    autoapidoc
+    sphinxcontrib
+
+This part of the documentation covers the open API of ``rstcheck`` and is auto
+generated by sphinx-apidoc via sphinxcontrib-apidoc.
+
+rst-source links (top right) do not work here, as auto generated api documentation files
+are discarded after build.
+
+.. toctree::
+   :maxdepth: 4
+
+   autoapidoc/rstcheck
diff --git a/docs/source/authors.rst b/docs/source/authors.rst
new file mode 100644
index 00000000..e9799a91
--- /dev/null
+++ b/docs/source/authors.rst
@@ -0,0 +1,4 @@
+Authors
+=======
+
+.. include:: ../../AUTHORS.rst
diff --git a/docs/source/autoapidoc/rstcheck.rst b/docs/source/autoapidoc/rstcheck.rst
new file mode 100644
index 00000000..b40c558c
--- /dev/null
+++ b/docs/source/autoapidoc/rstcheck.rst
@@ -0,0 +1,50 @@
+rstcheck package
+================
+
+.. automodule:: rstcheck
+   :members:
+   :undoc-members:
+   :show-inheritance:
+
+Submodules
+----------
+
+rstcheck.checker module
+-----------------------
+
+.. automodule:: rstcheck.checker
+   :members:
+   :undoc-members:
+   :show-inheritance:
+
+rstcheck.config module
+----------------------
+
+.. automodule:: rstcheck.config
+   :members:
+   :undoc-members:
+   :show-inheritance:
+
+rstcheck.inline\_config module
+------------------------------
+
+.. automodule:: rstcheck.inline_config
+   :members:
+   :undoc-members:
+   :show-inheritance:
+
+rstcheck.runner module
+----------------------
+
+.. automodule:: rstcheck.runner
+   :members:
+   :undoc-members:
+   :show-inheritance:
+
+rstcheck.types module
+---------------------
+
+.. automodule:: rstcheck.types
+   :members:
+   :undoc-members:
+   :show-inheritance:
diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst
new file mode 100644
index 00000000..ab37940f
--- /dev/null
+++ b/docs/source/changelog.rst
@@ -0,0 +1,1 @@
+.. mdinclude:: ../../CHANGELOG.md
diff --git a/docs/source/conf.py b/docs/source/conf.py
new file mode 100644
index 00000000..47698819
--- /dev/null
+++ b/docs/source/conf.py
@@ -0,0 +1,202 @@
+"""Configuration file for the Sphinx documentation builder."""
+# pylint: disable=C0103
+import os
+import re
+import shutil
+from datetime import date
+from importlib.util import find_spec
+from pathlib import Path
+from typing import List
+
+import sphinx_rtd_theme  # type: ignore[import]
+from sphinx.application import Sphinx
+
+
+try:
+    from importlib.metadata import metadata  # pylint: disable=ungrouped-imports
+except ModuleNotFoundError:  # pragma: py-gte-38
+    from importlib_metadata import metadata
+
+
+needs_sphinx = "3.1"  #: Minimum Sphinx version to build the docs
+
+
+#: -- GLOB VARS ------------------------------------------------------------------------
+NOT_LOADED_MSGS = []
+
+
+#: -- PROJECT INFORMATION --------------------------------------------------------------
+project = "rstcheck"
+author = "Steven Myint <git@stevenmyint.com>"
+GH_REPO_LINK = "https://github.com/myint/rstcheck"
+CREATION_YEAR = 2013
+CURRENT_YEAR = f"{date.today().year}"
+copyright = (  # noqa: VNE003 # pylint: disable=W0622
+    f"{CREATION_YEAR}{('-' + CURRENT_YEAR) if CURRENT_YEAR != CREATION_YEAR else ''}, "
+    + f"{author} and AUTHORS"
+)
+RSTCHECK_VERSION = metadata(project)["Version"]
+release = RSTCHECK_VERSION  #: The full version, including alpha/beta/rc tags
+version_parts = re.search(r"^v?(?P<version>\d+\.\d+)\.\d+[-.]?(?P<tag>[a-z]*)[\.]?\d*", release)
+#: Major + Minor version like (X.Y)
+version = None if not version_parts else version_parts.group("version")
+#: only tags like alpha/beta/rc
+RELEASE_LEVEL = None if not version_parts else version_parts.group("tag")
+
+
+#: -- GENERAL CONFIG -------------------------------------------------------------------
+extensions: List[str] = []
+today_fmt = "%Y-%m-%d"
+exclude_patterns: List[str] = []  #: Files to exclude for source of doc
+
+#: Added dirs for static and template files if they exist
+html_static_path = ["_static"] if Path("_static").exists() else []
+templates_path = ["_templates"] if Path("_templates").exists() else []
+
+rst_prolog = """
+.. ifconfig:: RELEASE_LEVEL in ('alpha', 'beta', 'rc')
+
+   .. warning::
+      The here documented release |release| is a prerelease.
+      Keep in mind that breaking changes can occur till the final release.
+
+      You may want to use the latest stable release instead.
+"""
+
+rst_epilog = """
+.. |br| raw:: html
+
+    <br/>
+"""
+
+tls_cacerts = os.getenv("SSL_CERT_FILE")
+
+
+#: -- M2R2 -----------------------------------------------------------------------------
+extensions.append("m2r2")
+source_suffix = [".rst", ".md"]
+
+
+#: -- LINKCHECK CONFIG -----------------------------------------------------------------
+#: 1 Worker 5 Retries to fix 429 error
+linkcheck_workers = 1
+linkcheck_retries = 5
+linkcheck_timeout = 30
+
+
+#: -- DEFAULT EXTENSIONS ---------------------------------------------------------------
+#: Global
+extensions.append("sphinx.ext.duration")
+extensions.append("sphinx.ext.coverage")  #: sphinx-build -b coverage ...
+coverage_write_headline = False
+coverage_show_missing_items = True
+extensions.append("sphinx.ext.doctest")  #: sphinx-build -b doctest ...
+
+#: ReStructuredText
+extensions.append("sphinx.ext.autosectionlabel")
+autosectionlabel_prefix_document = True
+autosectionlabel_maxdepth = 2
+extensions.append("sphinx.ext.ifconfig")
+extensions.append("sphinx.ext.viewcode")
+
+#: Links
+extensions.append("sphinx.ext.intersphinx")
+# NOTE: to inspect .inv files: https://github.com/bskinn/sphobjinv
+intersphinx_mapping = {
+    "python": ("https://docs.python.org/3/", None),
+    "pattern": ("https://docs.python.org/3/library/", "objects.pattern.inv"),
+    "pydantic": ("https://pydantic-docs.helpmanual.io/usage/", "objects.pydantic.inv"),
+}
+
+extensions.append("sphinx.ext.extlinks")
+extlinks = {
+    "repo": (f"{GH_REPO_LINK}/%s", "Repo's "),
+    "issue": (f"{GH_REPO_LINK}/issues/%s", "#"),
+    "pull": (f"{GH_REPO_LINK}/pull/%s", "pr"),
+    "user": ("https://github.com/%s", "@"),
+}
+
+
+#: -- APIDOC ---------------------------------------------------------------------------
+apidoc_module_dir = f"../../src/{project}/"
+apidoc_output_dir = "autoapidoc"
+apidoc_toc_file = False
+apidoc_separate_modules = False
+apidoc_module_first = True
+apidoc_extra_args = []
+if Path("_apidoc_templates").is_dir():
+    apidoc_extra_args += ["--templatedir", "apidoc_templates"]
+autoclass_content = "both"
+
+
+if find_spec("sphinxcontrib.apidoc") is not None:
+    extensions.append("sphinxcontrib.apidoc")
+    if Path(apidoc_output_dir).is_dir():
+        shutil.rmtree(apidoc_output_dir)
+else:
+    NOT_LOADED_MSGS.append("## 'sphinxcontrib-apidoc' extension not loaded - not installed")
+
+
+#: -- AUTODOC --------------------------------------------------------------------------
+extensions.append("sphinx.ext.autodoc")
+autodoc_typehints = "description"
+autodoc_member_order = "bysource"
+autodoc_mock_imports: List[str] = []
+autodoc_default_options = {"members": True}
+
+
+def _remove_module_docstring(  # pylint: disable=R0913
+    app, what, name, obj, options, lines  # pylint: disable=W0613 # noqa: ANN001
+) -> None:
+    """Remove module docstring."""
+    if what == "module":
+        del lines[:]
+
+
+if find_spec("sphinx_autodoc_typehints") is not None:
+    extensions.append("sphinx_autodoc_typehints")
+else:
+    NOT_LOADED_MSGS.append("## 'sphinx-autodoc-typehints' extension not loaded - not installed")
+
+
+#: -- CLICK ----------------------------------------------------------------------------
+extensions.append("sphinx_click.ext")
+
+
+#: -- SPELLING -------------------------------------------------------------------------
+spelling_word_list_filename = "spelling_dict.txt"
+spelling_show_suggestions = True
+spelling_exclude_patterns = ["autoapi/**", "autoapidoc/**"]
+
+if find_spec("sphinxcontrib.spelling") is not None:
+    extensions.append("sphinxcontrib.spelling")
+else:
+    NOT_LOADED_MSGS.append("## 'sphinxcontrib-spelling' extension not loaded - not installed")
+
+
+#: -- HTML THEME -----------------------------------------------------------------------
+#: needs install: "sphinx-rtd-theme"
+extensions.append("sphinx_rtd_theme")
+html_theme = "sphinx_rtd_theme"
+html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
+html_theme_options = {"style_external_links": True, "navigation_depth": 5}
+
+extensions.append("sphinx_rtd_dark_mode")
+default_dark_mode = False
+
+
+#: -- HTML OUTPUT ----------------------------------------------------------------------
+html_last_updated_fmt = today_fmt
+html_show_sourcelink = True  #: Add links to *.rst source files on HTML pages
+
+
+#: -- FINAL SETUP ----------------------------------------------------------------------
+def setup(app: Sphinx) -> None:
+    """Connect custom func to sphinx events."""
+    app.connect("autodoc-process-docstring", _remove_module_docstring)
+
+    app.add_config_value("RELEASE_LEVEL", "", "env")
+
+
+for msg in NOT_LOADED_MSGS:
+    print(msg)
diff --git a/docs/source/faq.rst b/docs/source/faq.rst
new file mode 100644
index 00000000..9015d693
--- /dev/null
+++ b/docs/source/faq.rst
@@ -0,0 +1,8 @@
+FAQ / Known limitations
+=======================
+
+There are inherent limitations to what ``rstcheck`` can and cannot do. The reason for this is that
+``rstcheck`` itself relies on external tools for parsing and error reporting.
+The rst source e.g. is given to ``docutils`` which then parses it and returns the errors.
+Therefore rstcheck is more like an error accumulation tool. The same goes for the source
+code in supported code blocks.
diff --git a/docs/source/index.rst b/docs/source/index.rst
new file mode 100644
index 00000000..415e0681
--- /dev/null
+++ b/docs/source/index.rst
@@ -0,0 +1,35 @@
+Welcome to rstcheck's documentation!
+====================================
+
+.. include:: _badges.rst
+
+
+This a the documentation of ``rstcheck``. A library and CLI application for checking
+the syntax of reStructuredText and code blocks nested within it.
+
+
+.. toctree::
+   :maxdepth: 2
+   :caption: Contents:
+
+   installation
+   usage/index
+   workflows/index
+
+
+.. toctree::
+   :maxdepth: 2
+   :caption: API Reference:
+
+   api
+
+
+.. toctree::
+   :maxdepth: 2
+   :caption: Miscellaneous:
+
+   faq
+   migrations
+   changelog
+   authors
+   license
diff --git a/docs/source/installation.rst b/docs/source/installation.rst
new file mode 100644
index 00000000..9ff6d756
--- /dev/null
+++ b/docs/source/installation.rst
@@ -0,0 +1,59 @@
+.. highlight:: console
+
+Installation
+============
+
+This part of the documentation covers how to install the package.
+It is recommended to install the package in a virtual environment.
+
+
+Create virtual environment
+--------------------------
+
+There are several packages/modules for creating python virtual environments.
+Here is a
+`manual <https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/>`__
+by the PyPA.
+
+
+Installation from PyPI
+----------------------
+
+You can simply install the package from PyPI::
+
+    $ pip install rstcheck
+
+
+Extras
+~~~~~~
+
+``rstcheck`` has extras which can be installed to activate optional functionality:
+
+- ``sphinx`` - To activate support for rst documents using the sphinx builder.
+- ``toml`` - To activate support for TOML files as configuration files.
+
+To install an extra simply add it in brackets like so::
+
+    $ pip install rstcheck[sphinx,toml]
+
+
+Installation from source
+------------------------
+
+You can install ``rstcheck`` directly from a Git repository clone.
+This can be done either by cloning the repository and installing from the local clone::
+
+    $ git clone https://github.com/Cielquan/rstcheck.git
+    $ cd rstcheck
+    $ pip install .
+
+
+Or installing directly via git::
+
+    $ pip install git+https://github.com/myint/rstcheck
+
+
+You can also download the current version as `tar.gz` or `zip` file, extract it and
+install it with pip like above.
+
+.. highlight:: default
diff --git a/docs/source/license.rst b/docs/source/license.rst
new file mode 100644
index 00000000..42611002
--- /dev/null
+++ b/docs/source/license.rst
@@ -0,0 +1,4 @@
+License
+=======
+
+.. literalinclude:: ../../LICENSE
diff --git a/docs/source/migrations.rst b/docs/source/migrations.rst
new file mode 100644
index 00000000..a10fa48a
--- /dev/null
+++ b/docs/source/migrations.rst
@@ -0,0 +1,89 @@
+.. highlight:: console
+
+Migration-Guides
+================
+
+Only breaking changes are mentioned here. New features or fixes are only mentioned if they
+somehow correspond to a breaking change.
+
+
+.. contents::
+
+
+Version 5 to 6 (alpha2)
+-----------------------
+
+**Subject to change till final release**
+
+With version 6 the whole code base was restructured and with it the whole open library API
+has changed. A simple migration is not possible. Please see the :ref:`api:API` section or
+open an issue if you have open questions.
+
+The new logging system may help you find issues while migrating to v6.
+You may then want to turn it on on the lowest level ``--log-level DEBUG``.
+
+
+Configuration file
+~~~~~~~~~~~~~~~~~~
+
+CLI options now overwrite settings in configuration files. Update your setup accordingly.
+
+The following configuration keys changed:
+
+- ``report`` renamed to ``report_level``
+- ``ignore_language`` renamed to ``ignore_languages``
+
+Set the ``--warn-unknown-settings`` CLI flag for warnings on unknown settings in
+configuration files.
+
+
+CLI
+~~~
+
+CLI options now overwrite settings in configuration files. Update your setup accordingly.
+
+Non existing files are silently ignored.
+
+The following CLI options changed:
+
+- ``--report`` renamed to ``--report-level`` and no longer accepts integers
+- ``--ignore-language`` renamed to ``--ignore-languages``
+- ``--ignore`` dropped -> use ``--ignore-languages``
+- ``--debug`` replaced with new ``--log-level`` -> use ``--log-level DEBUG``
+- ``--version`` dropped without replacement
+
+
+Sphinx features
+~~~~~~~~~~~~~~~
+
+Support for sphinx prior version 2.0 was dropped.
+
+Hard-coded default values for roles and directives coming from ``sphinx`` were dropped.
+If you encounter a lot of unknown roles and directives this may be the reason
+(`Example issue <https://github.com/myint/rstcheck/issues/109>`__).
+
+To fix this simply add sphinx to the environment from where you run ``rstcheck``::
+
+   $ pip install sphinx  # directly
+
+   $ pip install rstcheck[sphinx]  # or via extra
+
+To check if sphinx support is activate run::
+
+   $ rstcheck --help | grep Sphinx
+
+
+Version 4 to 5
+--------------
+
+Nothing to do if you don't need the test suit of ``rstcheck``.
+
+Use ``tox`` to run test suite.
+
+
+Version 3 to 4
+--------------
+
+Use python 3.7 or newer to run ``rstcheck``.
+
+.. highlight:: default
diff --git a/docs/source/objects.pattern.inv b/docs/source/objects.pattern.inv
new file mode 100644
index 00000000..13ae09f7
Binary files /dev/null and b/docs/source/objects.pattern.inv differ
diff --git a/docs/source/objects.pydantic.inv b/docs/source/objects.pydantic.inv
new file mode 100644
index 00000000..4382daed
Binary files /dev/null and b/docs/source/objects.pydantic.inv differ
diff --git a/docs/source/spelling_dict.txt b/docs/source/spelling_dict.txt
new file mode 100644
index 00000000..821e7ea7
--- /dev/null
+++ b/docs/source/spelling_dict.txt
@@ -0,0 +1,95 @@
+api
+arg
+args
+attr
+bool
+boolean
+bugfixes
+cfg
+changelog
+cielquan
+cli
+cmd
+compat
+conf
+config
+configs
+csv
+dependabot
+deleter
+dev
+dir
+dirs
+docstring
+docstrings
+doctest
+dotenv
+env
+envs
+envvar
+exe
+executable
+executables
+expr
+fmt
+formatter
+formatters
+func
+gcc
+getter
+github
+html
+importlib
+ini
+init
+inv
+kwarg
+kwargs
+linter
+linters
+makefile
+monkypatch
+monkypatched
+nd
+noqa
+nosec
+nox
+nox's
+noxfile
+num
+opensource
+os
+parametrize
+pragma
+pre
+py
+pyproject
+pytest
+rc
+rd
+redef
+repo
+reStructuredText
+riedel
+rst
+rstcheck
+rtd
+sdist
+setter
+st
+stdin
+submodule
+submodules
+temp
+testcleanup
+testsetup
+tmp
+toml
+toctree
+tokenize
+tox
+travis
+txt
+venv
+virtualenv
+xml
diff --git a/docs/source/usage/cli.rst b/docs/source/usage/cli.rst
new file mode 100644
index 00000000..dfc5c39c
--- /dev/null
+++ b/docs/source/usage/cli.rst
@@ -0,0 +1,24 @@
+CLI
+===
+
+This part of the documentation covers the CLI interface and
+is auto-generated by sphinx-click extension.
+
+.. warning::
+
+   The CLI interface differs depending on the available opt-in extensions:
+
+   - Sphinx
+   - Toml
+
+   The documentation shown here uses all opt-in features.
+
+.. note::
+
+   More information about the single configuration options can be found in the
+   :ref:`usage/config:Configuration` section
+
+
+.. click:: rstcheck._cli:typer_click_object
+   :prog: rstcheck
+   :show-nested:
diff --git a/docs/source/usage/config.rst b/docs/source/usage/config.rst
new file mode 100644
index 00000000..383aee0c
--- /dev/null
+++ b/docs/source/usage/config.rst
@@ -0,0 +1,223 @@
+Configuration
+=============
+
+``rstcheck``'s configuration system knows three sources and they apply in the following order:
+
+#. Inline configuration comments
+#. CLI options
+#. Configuration files
+
+This means that e.g. a configuration via CLI overwrites configuration from a file.
+
+
+Configuration options
+---------------------
+
+
+Configuration file
+~~~~~~~~~~~~~~~~~~
+
+A configuration file can only be set via the ``--config`` CLI option.
+After the option you must specify a path. The path may be relative or absolute.
+
+When the path points to a file, this concrete file is read and searched for a configuration
+section for ``rstcheck``. If no section is found a warning is printed and no file configuration
+is used. If the file is not found an error is raised.
+
+When the path is a directory, this directory is search for the following configuration files in this
+order:
+
+#. .rstcheck.cfg
+#. pyproject.toml
+#. setup.cfg
+
+If one files does not exist or contain a configuration section for ``rstcheck`` the next is tried.
+If ``.rstcheck.cfg`` does not contain a valid section a warning is printed.
+
+INI style files are searched for a ``[rstcheck]`` section.
+
+TOML files are searched for a ``[tool.rstcheck]`` section.
+
+.. note::
+
+    ``pyproject.toml`` and TOML files in general are only supported if ``tomli`` is importable.
+    ``tomli`` can be installed via the ``toml`` extra. See the :ref:`installation:Installation`
+    section for more information.
+
+When ``--config`` is not set two things happen implicitly:
+
+1. The current working directory is searched for one of the above configuration files,
+   as if ``--config .`` was set.
+2. The directory of each rst file which is checked is also searched for the above configuration
+   files. These files may contain configuration specific to the files in this directory.
+   If the file's directory does not contain a valid configuration file the parent directories
+   are searched up the directory tree until the root.
+
+
+Recursive resolution
+~~~~~~~~~~~~~~~~~~~~
+
+By default only files passed to the CLI application are checked and directories are ignored.
+When this flag is set, passed directories are searched recursively for rst source files.
+
+Can only be activated with the ``--recursive`` or ``-r`` CLI flag.
+
+
+Report level
+~~~~~~~~~~~~
+
+The level at which linting issues should be printed. The following levels are supported:
+
+- INFO (default)
+- WARNING
+- ERROR
+- SEVERE
+- NONE
+
+This currently only applies to issues with rst source.
+Issues in code blocks are on ERROR level and always printed,
+even if the level is set to SEVERE or NONE.
+
+Can be set via the CLI option ``--report-level`` or
+in a configuration file with the ``report_level`` key.
+The level can be set case insensitive.
+
+
+Logging level
+~~~~~~~~~~~~~
+
+The level at which additional information besides linting issues should be printed.
+The following levels are supported:
+
+- DEBUG
+- INFO
+- WARNING (default)
+- ERROR
+- CRITICAL
+
+Can only be set via the ``--log-level`` CLI option.
+The level can be set case insensitive.
+
+
+Ignore directives
+~~~~~~~~~~~~~~~~~
+
+A list of directives to ignore while checking rst source.
+
+Can be set via the CLI option ``--ignore-directives`` or
+in a configuration file with the ``ignore_directives`` key.
+On CLI and in INI format a comma separated list is expected.
+In TOML format a list of strings is expected.
+
+
+Ignore roles
+~~~~~~~~~~~~
+
+A list of roles to ignore while checking rst source.
+
+Can be set via the CLI option ``--ignore-roles`` or
+in a configuration file with the ``ignore_roles`` key.
+On CLI and in INI format a comma separated list is expected.
+In TOML format a list of strings is expected.
+
+
+Ignore substitutions
+~~~~~~~~~~~~~~~~~~~~
+
+A list of substitutions to ignore while checking rst source.
+
+Can be set via the CLI option ``--ignore-substitutions`` or
+in a configuration file with the ``ignore_substitutions`` key.
+On CLI and in INI format a comma separated list is expected.
+In TOML format a list of strings is expected.
+
+
+Ignore specific code-block languages
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A list of languages to ignore for code blocks in rst source.
+Unsupported languages are ignored automatically.
+
+Supported languages are:
+
+- Bash
+- Doctest
+- C (C99)
+- C++ (C++11)
+- JSON
+- XML
+- Python
+- reStructuredText
+
+Can be set via the CLI option ``--ignore-languages`` or
+in a configuration file with the ``ignore_languages`` key
+or as an inline configuration comment with the ``ignore-languages`` key.
+On CLI, in INI format and as inline configuration comment a comma separated list is expected.
+In TOML format a list of strings is expected.
+
+
+Ignore specific error messages
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A list of linting issue messages to ignore while checking rst source and code blocks.
+
+Can be set via the CLI option ``--ignore-messages`` or
+in a configuration file with the ``ignore_messages`` key.
+On CLI and in INI format a regular expression string is expected.
+In TOML format a single string or a list of strings is expected. The list's entries will be
+concatenated and the OR operator "|" will be set between each entry.
+
+
+Configuration Examples
+----------------------
+
+Inline configuration comment
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Inline configuration is passed after a ``rstcheck:`` in a rst comment.
+
+.. code-block:: rst
+
+    Example
+    =======
+
+    .. code-block:: python
+
+        print("Hello world")
+
+    .. rstcheck: ignore-languages=python
+
+
+INI Configuration file
+~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: ini
+
+    [rstcheck]
+    report_level=warning
+    ignore_directives =
+        one,
+        two,
+        three,
+    ignore_roles=src,RFC
+    ignore_substitutions=image_link
+    ignore_languages=python,cpp
+    ignore_messages=(Document or section may not begin with a transition\.$)
+
+
+TOML Configuration file
+~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: toml
+
+    [tool.rstcheck]
+    report_level = "WARNING"
+    ignore_directives = [
+        "one",
+        "two",
+        "three",
+    ]
+    ignore_roles = ["src", "RFC"]
+    ignore_substitutions = ["image_link"]
+    ignore_languages = ["python", "cpp"]
+    ignore_messages = "(Document or section may not begin with a transition\.$)"
diff --git a/docs/source/usage/index.rst b/docs/source/usage/index.rst
new file mode 100644
index 00000000..2dfa85f1
--- /dev/null
+++ b/docs/source/usage/index.rst
@@ -0,0 +1,13 @@
+Usage
+=====
+
+``rstcheck`` is a library at heart but comes packed with a CLI application.
+Documentation for the open API of the library can be found in the :ref:`api:API` section.
+
+.. toctree::
+   :maxdepth: 1
+   :caption: Contents:
+
+   cli
+   config
+   integration
diff --git a/docs/source/usage/integration.rst b/docs/source/usage/integration.rst
new file mode 100644
index 00000000..2d3fa9ac
--- /dev/null
+++ b/docs/source/usage/integration.rst
@@ -0,0 +1,46 @@
+Integration
+===========
+
+``rstcheck`` can be integrated and used with other tools.
+
+
+Usage in Vim
+------------
+
+
+Using with Syntastic_:
+~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: vim
+
+    let g:syntastic_rst_checkers = ['rstcheck']
+
+
+Using with ALE_:
+~~~~~~~~~~~~~~~~
+
+Just install ``rstcheck`` and make sure is on your path.
+
+.. _Syntastic: https://github.com/vim-syntastic/syntastic
+.. _ALE: https://github.com/dense-analysis/ale
+
+
+Use as a pre-commit hook
+------------------------
+
+Add this to your ``.pre-commit-config.yaml``
+
+.. code:: yaml
+
+    -   repo: https://github.com/myint/rstcheck
+        rev: ''  # Use the sha / tag you want to point at
+        hooks:
+        -   id: rstcheck
+
+
+Use with Mega-Linter
+--------------------
+
+Just install `Mega-Linter <https://megalinter.github.io/latest//>`__ in your repository,
+`rstcheck <https://megalinter.github.io/latest/descriptors/rst_rstcheck//>`__
+is part of the 70 linters activated out of the box.
diff --git a/docs/source/workflows/development.rst b/docs/source/workflows/development.rst
new file mode 100644
index 00000000..eed37431
--- /dev/null
+++ b/docs/source/workflows/development.rst
@@ -0,0 +1,95 @@
+.. highlight:: console
+
+Development
+===========
+
+``rstcheck`` uses `Semantic Versioning <https://semver.org/>`__.
+
+``rstcheck`` uses ``master`` as its single development branch. Therefore releases are
+made from this branch. Only the current release is supported and bugfixes are released
+with a patch release for the current minor release.
+
+
+Tooling
+-------
+
+For development the following tools are used:
+
+- ``poetry`` for dependency management, package metadata, building and publishing.
+- ``tox`` for automated and isolated testing.
+- ``pre-commit`` for automated QA checks via different linters and formatters.
+
+
+Set up Local Development Environment
+------------------------------------
+
+The setup of a local development environment is pretty easy. The only tool you need is
+`poetry <https://python-poetry.org/docs/>`__. You can install it via the
+`recommended way <https://python-poetry.org/docs/#installation>`__, which installs it
+globally on your system or you can install it via ``pip`` in a self-created virtualenv
+(`virtualenv manual <https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/>`__).
+
+With ``poetry`` set up and ready we can create our development environment in just one
+step::
+
+    $ poetry install
+
+This will install ``rstcheck`` along its main and development dependencies.
+
+
+Working with the Local Development Environment
+----------------------------------------------
+
+poetry
+~~~~~~
+
+is used for dependency management, building and publishing ``rstcheck``.
+
+
+Testing with tox
+~~~~~~~~~~~~~~~~
+
+To run all available tests and check simply run::
+
+    $ tox
+
+This will run:
+
+- formatters and linters via ``pre-commit``.
+- the full test suite with ``pytest``.
+- a test coverage report.
+- tests for the documentation.
+
+Different environment lists are available and can be selected with ``tox -n <ENVLIST>``:
+
+- test: run full test suite with ``pytest`` and report coverage.
+- py3.7 - py3.10 run full test suite with specific python version and report coverage.
+- docs: run all documentation tests.
+
+
+pre-commit
+~~~~~~~~~~
+
+can be used directly from within the development environment or you can use
+``tox`` to run it pre-configured.
+
+There are 3 available ``tox`` envs with all use the same virtualenv:
+
+- ``pre-commit``:
+  For running any ``pre-commit`` command like ``tox -e pre-commit -- autoupdate --freeze``.
+- ``pre-commit-run``:
+  For running all hooks against the code base.
+  A single hook's id can be passed as argument to run this hook only like
+  ``tox -e pre-commit-run -- black``.
+- ``pre-commit-install``: For installing pre-commit hooks as git hooks, to automatically run
+  them before every commit.
+
+
+IDE integration
+~~~~~~~~~~~~~~~
+
+The development environment has ``flakeheaven`` (a ``flake8`` wrapper), ``pylint`` and ``mypy``
+installed to allow IDEs to use them for inline error messages. Their config is in
+``pyproject.toml``. To run them actively use ``pre-commit`` and/or ``tox``.
+
+.. highlight:: default
diff --git a/docs/source/workflows/index.rst b/docs/source/workflows/index.rst
new file mode 100644
index 00000000..e0d06bc1
--- /dev/null
+++ b/docs/source/workflows/index.rst
@@ -0,0 +1,11 @@
+Workflows
+=========
+
+Here is the documentation about different workflows for ``rstcheck``.
+
+.. toctree::
+   :maxdepth: 1
+   :caption: Contents:
+
+   development
+   releases
diff --git a/docs/source/workflows/releases.rst b/docs/source/workflows/releases.rst
new file mode 100644
index 00000000..4041bcff
--- /dev/null
+++ b/docs/source/workflows/releases.rst
@@ -0,0 +1,47 @@
+.. highlight:: console
+
+Releases
+========
+
+Release workflow
+----------------
+
+When enough changes and additions or time important fixes have accumulated on the
+``master`` branch its time for a new release. The exact time is subject to the
+judgment of the maintainer(s).
+
+
+.. note::
+
+  Before starting the process of creating a new release make sure that all CI pipelines
+  are green for the current commit.
+
+#. Check if the ``CHANGELOG.md`` is up-to-date and all changes are noted.
+
+#. Run ``prep_release.py`` script to bump version, finalize ``CHANGELOG.md``,
+   commit the changes and create a new git tag::
+
+      $ python3 prep_release.py --increase-type <TYPE>
+
+   For the increase type there are three options:
+
+     - ``patch`` / ``bugfix``:
+       for changes that **do not** add new functionality and are backwards compatible
+     - ``minor`` / ``feature``:
+       for changes that **do** add new functionality and are backwards compatible
+     - ``major`` / ``breaking``:
+       for changes that are **not** backwards compatible
+
+#. Build the sdist and wheel::
+
+    $ poetry build
+
+#. Publish package::
+
+   $ poetry publish
+
+#. Push the commit and tag to github::
+
+    $ git push --follow-tags
+
+.. highlight:: default
diff --git a/prep_release.py b/prep_release.py
new file mode 100644
index 00000000..7179bef3
--- /dev/null
+++ b/prep_release.py
@@ -0,0 +1,221 @@
+"""Script for preparing the repo for a new release."""
+import argparse
+import re
+import subprocess  # noqa: S404
+import sys
+from datetime import date
+
+
+if sys.version_info[0:2] <= (3, 6):
+    raise RuntimeError("Script runs only with python 3.7 or newer.")
+
+
+PATCH = ("patch", "bugfix")
+MINOR = ("minor", "feature")
+MAJOR = ("major", "breaking")
+
+REPO_URL = "https://github.com/myint/rstcheck"
+
+
+#: -- UTILS ----------------------------------------------------------------------------
+class PyprojectError(Exception):
+    """Exception for lookup errors in pyproject.toml file."""
+
+
+def _get_config_value(section: str, key: str) -> str:  # noqa: CCR001
+    """Extract a config value from pyproject.toml file.
+
+    :return: config value
+    """
+    with open("pyproject.toml", encoding="utf8") as pyproject_file:
+        pyproject = pyproject_file.read().split("\n")
+
+    start = False
+    for line in pyproject:
+        if not start and line.strip().startswith(section):
+            start = True
+            continue
+
+        if start and line.strip().startswith("["):
+            break
+
+        if start and line.strip().startswith(key):
+            match = re.match(r"\s*" + key + r"""\s?=\s?["']{1}([^"']*)["']{1}.*""", line)
+            if match:
+                return match.group(1)
+            raise PyprojectError(
+                f"No value for key '{key}' in {section} section could be extracted."
+            )
+
+    raise PyprojectError(f"No '{key}' found in {section} section.")
+
+
+def _set_config_value(section: str, key: str, value: str) -> None:
+    """Set a config value in pyproject.toml file."""
+    with open("pyproject.toml", encoding="utf8") as pyproject_file:
+        pyproject = pyproject_file.read().split("\n")
+
+    start = False
+    for idx, line in enumerate(pyproject):
+        if not start and line.strip().startswith(section):
+            start = True
+            continue
+
+        if start and line.strip().startswith("["):
+            raise PyprojectError(f"No '{key}' found in {section} section.")
+
+        if start and line.strip().startswith(key):
+            match = re.sub(
+                r"(\s*" + key + r"""\s?=\s?["']{1})[^"']*(["']{1}.*)""",
+                f"\\g<1>{value}\\g<2>",
+                line,
+            )
+            pyproject[idx] = match
+            break
+
+    with open("pyproject.toml", "w", encoding="utf8") as pyproject_file:
+        pyproject_file.write("\n".join(pyproject))
+
+
+#: -- MAIN -----------------------------------------------------------------------------
+def bump_version(release_type: str = "patch") -> str:
+    """Bump the current version for the next release.
+
+    :param release_type: type of release;
+        allowed values are: patch | minor/feature | major/breaking;
+        defaults to "patch"
+    :raises ValueError: when an invalid release_type is given.
+    :raises ValueError: when the version string from pyproject.toml is not parsable.
+    :return: new version string
+    """
+    if release_type not in PATCH + MINOR + MAJOR:
+        raise ValueError(f"Invalid version increase type: {release_type}")
+
+    current_version = _get_config_value("[tool.poetry]", "version")
+
+    version_parts = re.match(r"(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)", current_version)
+    if not version_parts:
+        raise ValueError(f"Unparsable version: {current_version}")
+
+    if release_type in MAJOR:
+        version = f"{int(version_parts.group('major')) + 1}.0.0"
+    elif release_type in MINOR:
+        version = f"{version_parts.group('major')}" f".{int(version_parts.group('minor')) + 1}.0"
+    elif release_type in PATCH:
+        version = (
+            f"{version_parts.group('major')}"
+            f".{version_parts.group('minor')}"
+            f".{int(version_parts.group('patch')) + 1}"
+        )
+    else:
+        print("Given `RELEASE TYPE` is invalid.")
+        sys.exit(1)
+
+    _set_config_value("[tool.poetry]", "version", version)
+    return version
+
+
+def update_changelog(new_version: str, last_version: str, first_release: bool) -> None:
+    """Update CHANGELOG.md to be release ready.
+
+    :param new_version: new version string
+    :param last_version: current version string
+    :first_release: if this is the first release
+    """
+    with open("CHANGELOG.md", encoding="utf8") as changelog_file:
+        changelog_lines = changelog_file.read().split("\n")
+
+    release_line = 0
+
+    for idx, line in enumerate(changelog_lines):
+        if line.startswith("## Unreleased"):
+            release_line = idx
+
+    if release_line:
+        today = date.today().isoformat()
+        compare = f"{'' if first_release else 'v'}{last_version}...v{new_version}"
+        changelog_lines[release_line] = (
+            "## Unreleased\n"
+            "\n"
+            f"[diff v{new_version}...master]"
+            f"({REPO_URL}/compare/v{new_version}...main)\n"
+            "\n"
+            f"## [{new_version}]({REPO_URL}/releases/v{new_version}) ({today})\n"
+            f"[diff {compare}]({REPO_URL}/compare/{compare})"
+        )
+
+    #: Remove [diff ...] link line
+    if len(changelog_lines) - 1 >= release_line + 1:
+        changelog_lines.pop(release_line + 1)
+
+    with open("CHANGELOG.md", "w", encoding="utf8") as changelog_file:
+        changelog_file.write("\n".join(changelog_lines))
+
+
+def commit_and_tag(version: str) -> None:
+    """Git commit and tag the new release."""
+    subprocess.run(  # noqa: S603,S607
+        [
+            "git",
+            "commit",
+            "--no-verify",
+            f"--message=release v{version} [skip ci]",
+            "--include",
+            "pyproject.toml",
+            "CHANGELOG.md",
+        ],
+        check=True,
+    )
+    subprocess.run(  # noqa: S603,S607
+        ["git", "tag", "-am", f"'v{version}'", f"v{version}"], check=True
+    )
+
+
+def _parser() -> argparse.Namespace:
+    """Create parser and return parsed args."""
+    parser = argparse.ArgumentParser()
+    parser.add_argument(
+        "increase_type",
+        metavar="RELEASE TYPE",
+        default="patch",
+        nargs="?",
+        help=(
+            "Release type: patch/bugfix | minor/feature | major/breaking; "
+            "gets ignored on `--first-release`; "
+            "defaults to patch"
+        ),
+    )
+    parser.add_argument(
+        "--first-release",
+        action="store_true",
+        help="Flag for first release to prevent version bumping.",
+    )
+    return parser.parse_args()
+
+
+def _main() -> int:
+    """Prepare release main routine."""
+    args = _parser()
+
+    if args.first_release:
+        release_version = _get_config_value("[tool.poetry]", "version")
+        #: Get first commit
+        current_version = subprocess.run(  # noqa: S603,S607
+            ["git", "rev-list", "--max-parents=0", "HEAD"],
+            check=True,
+            capture_output=True,
+        ).stdout.decode()[0:7]
+    else:
+        current_version = _get_config_value("[tool.poetry]", "version")
+        release_version = bump_version(args.increase_type)
+    update_changelog(
+        release_version,
+        current_version,
+        args.first_release,
+    )
+    commit_and_tag(release_version)
+    return 0
+
+
+if __name__ == "__main__":
+    sys.exit(_main())
diff --git a/pyproject.toml b/pyproject.toml
index ca9b8721..3d10fef4 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -21,7 +21,7 @@ packages = [
 include = ["testing"]
 
 [tool.poetry.scripts]
-rstcheck = "rstcheck.cli:main"
+rstcheck = "rstcheck._cli:main"
 
 [tool.poetry.dependencies]
 python = "^3.7"
@@ -40,6 +40,16 @@ pytest-sugar = { git = "https://github.com/Teemu/pytest-sugar.git", rev = "ee02a
 pytest-randomly = { version = ">=3.0", optional = true }
 pytest-mock = {version = ">=3.7", optional = true}
 mock = {version = ">=4.0", optional = true}
+# EXTRA docs
+sphinx-autobuild = { version = "2021.3.14", optional = true }
+m2r2 = { version = ">=0.3.2", optional = true }
+# TODO:#i# wait for fix: https://github.com/MrDogeBro/sphinx_rtd_dark_mode/issues/28
+sphinx-rtd-theme = { version = "<1", optional = true }
+sphinx-rtd-dark-mode = {version = "^1.2.4", optional = true}
+sphinx-autodoc-typehints = { version = ">=1.15", optional = true }
+sphinxcontrib-apidoc = { version = ">=0.3", optional = true }
+sphinxcontrib-spelling = { version = ">=7.3", optional = true }
+sphinx-click = "^4.0.3"
 # MAIN DEPENDENCIES
 importlib-metadata = {version = ">=1.6, <5.0", python = "<3.8"}
 typing-extensions = {version = ">=3.7.4, <5.0", python = "<3.8"}
@@ -55,6 +65,8 @@ my-flake8-plugins = { git = "https://github.com/cielquan/my-flake8-plugins.git",
 pylint = ">=2.12"
 mypy = ">=0.931"
 pytest = ">=6.0"
+sphinx = ">=4.0"
+sphinx-rtd-theme = "*"
 
 [tool.poetry.extras]
 sphinx = ["sphinx"]
@@ -69,6 +81,17 @@ testing = [
   "pytest-mock",
   "mock",
 ]
+docs = [
+  "sphinx",
+  "sphinx-autobuild",
+  "m2r2",
+  "sphinx-rtd-theme",
+  "sphinx-rtd-dark-mode",
+  "sphinx-autodoc-typehints",
+  "sphinxcontrib-apidoc",
+  "sphinxcontrib-spelling",
+  "sphinx-click",
+]
 
 
 # -- BLACK CONFIG ---------------------------------------------------------------------
diff --git a/src/rstcheck/cli.py b/src/rstcheck/_cli.py
similarity index 93%
rename from src/rstcheck/cli.py
rename to src/rstcheck/_cli.py
index 161d29a5..c9863733 100644
--- a/src/rstcheck/cli.py
+++ b/src/rstcheck/_cli.py
@@ -10,7 +10,6 @@
 
 ValidReportLevels = _compat.Literal["INFO", "WARNING", "ERROR", "SEVERE", "NONE"]
 
-HELP_FILES = "RST files to check. Can be files or directories if --recursive is passed too."
 HELP_CONFIG = """Config file to load. Can be a INI file or directory.
 If a directory is passed it will be searched for .rstcheck.cfg | setup.cfg.
 """
@@ -23,12 +22,12 @@
 HELP_RECURSIVE = "Recursively search passed directories for RST files to check."
 HELP_REPORT_LEVEL = f"""The report level of the linting issues found.
 Valid levels are: INFO | WARNING | ERROR | SEVERE | NONE.
-Defauls to {config_mod.DEFAULT_REPORT_LEVEL.name}.
+Defaults to {config_mod.DEFAULT_REPORT_LEVEL.name}.
 Can be set in config file.
 """
 HELP_LOG_LEVEL = """The log level of the application for information that is not a linting issue.
 Valid levels are: DEBUG | INFO | WARNING | ERROR | CRITICAL.
-Defauls to WARNING.
+Defaults to WARNING.
 """
 HELP_IGNORE_DIRECTIVES = """Comma-separated-list of directives to add to the ignore list.
 Can be set in config file.
@@ -63,7 +62,7 @@ def setup_logger(loglevel: str) -> None:
 
 def cli(  # pylint: disable=too-many-arguments
     files: t.List[pathlib.Path] = typer.Argument(  # noqa: M511,B008
-        ..., help=HELP_FILES, allow_dash=True
+        ..., allow_dash=True, hidden=True
     ),
     config: t.Optional[pathlib.Path] = typer.Option(  # noqa: M511,B008
         None, "--config", help=HELP_CONFIG
@@ -135,9 +134,18 @@ def cli(  # pylint: disable=too-many-arguments
 cli.__doc__ = f"""CLI of rstcheck.
 
 Enabled features: {enabled_features}
+
+Pass one ore more rst FILES to check.
+Can be files or directories if --recursive is passed too.
+Pass "-" if you want to read from stdin.
 """
 
 
+app = typer.Typer()
+app.command()(cli)
+typer_click_object = typer.main.get_command(app)
+
+
 def main() -> None:  # pragma: no cover
     """Run CLI."""
     typer.run(cli)
diff --git a/src/rstcheck/_docutils.py b/src/rstcheck/_docutils.py
index 7c145729..eb6e57d5 100644
--- a/src/rstcheck/_docutils.py
+++ b/src/rstcheck/_docutils.py
@@ -42,8 +42,8 @@ def clean_docutils_directives_and_roles_cache() -> None:  # pragma: no cover
     """Clean docutils' directives and roles cache by reloading their modules.
 
     Reloads:
-    - docutils.parsers.rst.directives
-    - docutils.parsers.rst.roles
+    - :py:mod:`docutils.parsers.rst.directives`
+    - :py:mod:`docutils.parsers.rst.roles`
     """
     logger.info("Reload module docutils.parsers.rst.directives/roles")
     importlib.reload(docutils.parsers.rst.directives)
@@ -94,11 +94,11 @@ def register_code_directive(
     """Optionally register code directives.
 
     :param ignore_code_directive: If "code" directive should be ignored,
-        so that the code block will not be checked; defaults to False
+        so that the code block will not be checked; defaults to :py:obj:`False`
     :param ignore_codeblock_directive: If "code-block" directive should be ignored,
-        so that the code block will not be checked; defaults to False
+        so that the code block will not be checked; defaults to :py:obj:`False`
     :param ignore_sourcecode_directive: If "sourcecode" directive should be ignored,
-        so that the code block will not be checked; defaults to False
+        so that the code block will not be checked; defaults to :py:obj:`False`
     """
     if not _extras.SPHINX_INSTALLED:
         if ignore_code_directive is False:
diff --git a/src/rstcheck/_extras.py b/src/rstcheck/_extras.py
index a91f4cc6..414475e7 100644
--- a/src/rstcheck/_extras.py
+++ b/src/rstcheck/_extras.py
@@ -1,7 +1,7 @@
 """Central place for install-checker and guards for 'extras' dependencies.
 
 The ``*_INSTALLED`` constansts reveal wether the dependency is installed with a supported version.
-The ``install_guard`` guard function is intended for use inside functions which need specific
+The :py:func:`install_guard` guard function is intended for use inside functions which need specific
 extra packages installed.
 
 Example usage:
@@ -75,7 +75,7 @@ def is_installed_with_supported_version(package: ExtraDependencies) -> bool:
 
 
 def install_guard(package: ExtraDependencies) -> None:
-    """Guard code that needs the ``package`` installed and throw ModuleNotFoundError.
+    """Guard code that needs the ``package`` installed and throw :py:exc:`ModuleNotFoundError`.
 
     See example in module docstring.
 
diff --git a/src/rstcheck/checker.py b/src/rstcheck/checker.py
index ef7e7c4d..210b4f92 100644
--- a/src/rstcheck/checker.py
+++ b/src/rstcheck/checker.py
@@ -45,7 +45,7 @@ def check_file(
     :param rstcheck_config: Main configuration of the application
     :param overwrite_with_file_config: If the loaded file config should overwrite the
         ``rstcheck_config``;
-        defaults to True
+        defaults to :py:obj:`True`
     :return: A list of found issues
     """
     logger.info(f"Check file'{source_file}'")
@@ -84,7 +84,7 @@ def _load_run_config(
     :param source_file_dir: Directory of the current file to check
     :param rstcheck_config: Main configuration of the application
     :param overwrite_config: If the loaded config should overwrite the ``rstcheck_config``;
-        defaults to True
+        defaults to :py:obj:`True`
     :return: Merged config
     """
     if rstcheck_config.config_path is not None:
@@ -131,10 +131,10 @@ def _replace_ignored_substitutions(source: str, ignore_substitutions: t.List[str
 
 
 def _create_ignore_dict_from_config(rstcheck_config: config.RstcheckConfig) -> types.IgnoreDict:
-    """Extract ignore settings from config and create a ``IgnoreDict``.
+    """Extract ignore settings from config and create a :py:class:`rstcheck.types.IgnoreDict`.
 
     :param rstcheck_config: Config to extract ignore settings from
-    :return: ``IgnoreDict``
+    :return: :py:class:`rstcheck.types.IgnoreDict`
     """
     return types.IgnoreDict(
         messages=rstcheck_config.ignore_messages,
@@ -154,10 +154,10 @@ def check_source(
     """Check the given rst source for issues.
 
     :param source_file: Path to file the source comes from if it comes from a file;
-        defaults to None
-    :param ignores: Ignore information; defaults to None
-    :param report_level: Report level; defaults to config.DEFAULT_REPORT_LEVEL
-    :return: None
+        defaults to :py:obj:`None`
+    :param ignores: Ignore information; defaults to :py:obj:`None`
+    :param report_level: Report level; defaults to :py:data:`rstcheck.config.DEFAULT_REPORT_LEVEL`
+    :return: :py:obj:`None`
     :yield: Found issues
     """
     source_origin: types.SourceFileOrString = source_file or "<string>"
@@ -221,13 +221,13 @@ def _run_code_checker_and_filter_errors(
     # NOTE: Pattern type-arg errors pydanic: https://github.com/samuelcolvin/pydantic/issues/2636
     ignore_messages: t.Optional[t.Pattern] = None,  # type: ignore[type-arg]
 ) -> types.YieldedLintError:
-    """Run each code block checker function and yield filtered ``LintError``.
+    """Run each code block checker function and yield filtered :py:class:`rstcheck.types.LintError`.
 
     :param checker_list: List of code block checker functions
     :param ignore_messages: Regex for ignoring error messages;
-        defaults to None
-    :return: None
-    :yield: Filtered LintErrors from run checker function
+        defaults to :py:obj:`None`
+    :return: :py:obj:`None`
+    :yield: Filtered :py:class:`rstcheck.types.LintError` s from run checker function
     """
     for checker in checker_list:
         for lint_error in checker():
@@ -242,14 +242,14 @@ def _parse_and_filter_rst_errors(
     source_origin: types.SourceFileOrString,
     ignore_messages: t.Optional[t.Pattern] = None,  # type: ignore[type-arg]
 ) -> types.YieldedLintError:
-    """Parse rst errors and yield filtered ``LintError``.
+    """Parse rst errors and yield filtered :py:class:`rstcheck.types.LintError`.
 
     :param rst_errors: String with rst errors
     :param source_origin: Origin of the source with the errors
     :param ignore_messages: Regex for ignoring error messages;
-        defaults to None
-    :return: None
-    :yield: Parsed and filtered LintErrors
+        defaults to :py:obj:`None`
+    :return: :py:obj:`None`
+    :yield: Parsed and filtered :py:class:`rstcheck.types.LintError` s
     """
     for message in rst_errors.splitlines():
         with contextlib.suppress(ValueError):
@@ -270,12 +270,13 @@ def __init__(
         ignores: t.Optional[types.IgnoreDict] = None,
         report_level: config.ReportLevel = config.DEFAULT_REPORT_LEVEL,
     ) -> None:
-        """Inititalize _CheckWriter.
+        """Inititalize :py:class:`_CheckWriter`.
 
         :param source: Rst source to check
         :param source_origin: Path to file the source comes from
-        :param ignores: Ignore information; defaults to None
-        :param report_level: Report level; defaults to config.DEFAULT_REPORT_LEVEL
+        :param ignores: Ignore information; defaults to :py:obj:`None`
+        :param report_level: Report level;
+            defaults to :py:data:`rstcheck.config.DEFAULT_REPORT_LEVEL`
         """
         docutils.writers.Writer.__init__(self)
         self.checkers: t.List[types.CheckerRunFunction] = []
@@ -308,13 +309,14 @@ def __init__(  # pylint: disable=too-many-arguments
         ignores: t.Optional[types.IgnoreDict] = None,
         report_level: config.ReportLevel = config.DEFAULT_REPORT_LEVEL,
     ) -> None:
-        """Inititalize _CheckTranslator.
+        """Inititalize :py:class:`_CheckTranslator`.
 
         :param document: Document node
         :param source: Rst source to check
         :param source_origin: Path to file the source comes from
-        :param ignores: Ignore information; defaults to None
-        :param report_level: Report level; defaults to config.DEFAULT_REPORT_LEVEL
+        :param ignores: Ignore information; defaults to :py:obj:`None`
+        :param report_level: Report level;
+            defaults to :py:data:`rstcheck.config.DEFAULT_REPORT_LEVEL`
         """
         docutils.nodes.NodeVisitor.__init__(self, document)
         self.checkers: t.List[types.CheckerRunFunction] = []
@@ -482,8 +484,9 @@ def __init__(
         """Inititalize CodeBlockChecker.
 
         :param source_origin: Path to file the source comes from
-        :param ignores: Ignore information; defaults to None
-        :param report_level: Report level; defaults to config.DEFAULT_REPORT_LEVEL
+        :param ignores: Ignore information; defaults to :py:obj:`None`
+        :param report_level: Report level;
+            defaults to :py:data:`rstcheck.config.DEFAULT_REPORT_LEVEL`
         """
         self.source_origin = source_origin
         self.ignores = ignores
@@ -511,7 +514,7 @@ def check(self, source_code: str, language: str) -> types.YieldedLintError:
 
         :param source: Source code to check
         :param language: Language of the source code
-        :return: None if language is not supported
+        :return: :py:obj:`None` if language is not supported
         :yield: Found issues
         """
         checker_function = t.Callable[[str], types.YieldedLintError]
@@ -526,7 +529,7 @@ def check_python(self, source_code: str) -> types.YieldedLintError:
         """Check python source for syntax errors.
 
         :param source: Python source code to check
-        :return: None
+        :return: :py:obj:`None`
         :yield: Found issues
         """
         logger.debug("Check python source.")
@@ -543,7 +546,7 @@ def check_json(self, source_code: str) -> types.YieldedLintError:
         """Check JSON source for syntax errors.
 
         :param source: JSON source code to check
-        :return: None
+        :return: :py:obj:`None`
         :yield: Found issues
         """
         logger.debug("Check JSON source.")
@@ -562,7 +565,7 @@ def check_xml(self, source_code: str) -> types.YieldedLintError:
         """Check XML source for syntax errors.
 
         :param source: XML source code to check
-        :return: None
+        :return: :py:obj:`None`
         :yield: Found issues
         """
         logger.debug("Check XML source.")
@@ -581,7 +584,7 @@ def check_rst(self, source_code: str) -> types.YieldedLintError:
         """Check nested rst source for syntax errors.
 
         :param source: rst source code to check
-        :return: None
+        :return: :py:obj:`None`
         :yield: Found issues
         """
         logger.debug("Check RST source.")
@@ -600,7 +603,7 @@ def check_doctest(self, source_code: str) -> types.YieldedLintError:
         incorrect for testing purposes.
 
         :param source: XML source code to check
-        :return: None
+        :return: :py:obj:`None`
         :yield: Found issues
         """
         logger.debug("Check doctest source.")
@@ -621,7 +624,7 @@ def check_bash(self, source_code: str) -> types.YieldedLintError:
         """Check bash source for syntax errors.
 
         :param source: bash source code to check
-        :return: None
+        :return: :py:obj:`None`
         :yield: Found issues
         """
         logger.debug("Check bash source.")
@@ -645,7 +648,7 @@ def check_c(self, source_code: str) -> types.YieldedLintError:
         """Check C source for syntax errors.
 
         :param source: C source code to check
-        :return: None
+        :return: :py:obj:`None`
         :yield: Found issues
         """
         logger.debug("Check C source.")
@@ -662,7 +665,7 @@ def check_cpp(self, source_code: str) -> types.YieldedLintError:
         """Check C++ source for syntax errors.
 
         :param source: C++ source code to check
-        :return: None
+        :return: :py:obj:`None`
         :yield: Found issues
         """
         logger.debug("Check C++ source.")
@@ -683,7 +686,7 @@ def _gcc_checker(
         :param source_code: Source code to check
         :param filename_suffix: File suffix for language of the source code
         :param arguments: Command and arguments to run
-        :return: None
+        :return: :py:obj:`None`
         :yield: Found issues
         """
         result = self._run_in_subprocess(
@@ -709,7 +712,8 @@ def _run_in_subprocess(
         :param source_code: Source code to check
         :param filename_suffix: File suffix for language of the source code
         :param arguments: Command and arguments to run
-        :return: ``None`` if no issues were found else a tuple of the stderr and temp-file name
+        :return: :py:obj:`None` if no issues were found else a tuple of the stderr and temp-file
+            name
         """
         get_encoding = lambda: locale.getpreferredencoding() or sys.getdefaultencoding()
 
@@ -751,7 +755,7 @@ def _parse_gcc_style_error_message(
 
     :param message: Message to parse
     :param filename: File the message is associated with
-    :param has_column: The the message has a column number; defaults to True
+    :param has_column: The the message has a column number; defaults to :py:obj:`True`
     :raises ValueError: If the message cannot be parsed
     :return: Parsed message
     """
diff --git a/src/rstcheck/config.py b/src/rstcheck/config.py
index 1276896b..560b7c1c 100644
--- a/src/rstcheck/config.py
+++ b/src/rstcheck/config.py
@@ -20,6 +20,7 @@
 
 
 CONFIG_FILES = [".rstcheck.cfg", "setup.cfg"]
+"""Supported default config files."""
 if _extras.TOMLI_INSTALLED:  # pragma: no cover
     CONFIG_FILES = [".rstcheck.cfg", "pyproject.toml", "setup.cfg"]
 
@@ -45,13 +46,14 @@ class ReportLevel(enum.Enum):
 
 
 DEFAULT_REPORT_LEVEL = ReportLevel.INFO
+"""Default report level."""
 
 
 class RstcheckConfigFile(pydantic.BaseModel):  # pylint: disable=no-member
     """Rstcheck config file.
 
-    :raises ValueError:: If setting has incorrect value or type
-    :raises pydantic.error_wrappers.ValidationError:: If setting is not parsable into correct type
+    :raises ValueError: If setting has incorrect value or type
+    :raises pydantic.error_wrappers.ValidationError: If setting is not parsable into correct type
     """
 
     report_level: t.Optional[ReportLevel]
@@ -68,8 +70,8 @@ def valid_report_level(cls, value: t.Any) -> t.Optional[ReportLevel]:  # noqa: A
         """Validate the report_level setting.
 
         :param value: Value to validate
-        :raises ValueError: If ``Value`` is not a valid docutils report level
-        :return: Instance of ``ReportLevel`` or None if emptry string.
+        :raises ValueError: If ``value`` is not a valid docutils report level
+        :return: Instance of :py:class:`ReportLevel` or None if emptry string.
         """
         if value is None:
             return None
@@ -110,7 +112,7 @@ def split_str(cls, value: t.Any) -> t.Optional[t.List[str]]:  # noqa: ANN401
         Comma separated strings are split into a list.
 
         :param value: Value to validate
-        :raises ValueError: If not a ``str`` or ``List[str]``
+        :raises ValueError: If not a :py:class:`str` or :py:class:`list` of :py:class:`str`
         :return: List of things to ignore in the respective category
         """
         if value is None:
@@ -134,8 +136,9 @@ def join_regex_str(
         If a list ist given, the entries are concatenated with "|" to create an or RegEx.
 
         :param value: Value to validate
-        :raises ValueError: If not a ``str`` or ``List[str]``
-        :return: A RegEx string with messages to ignore or Pattern if it is one already
+        :raises ValueError: If not a :py:class:`str` or :py:class:`list` of :py:class:`str`
+        :return: A RegEx string with messages to ignore or :py:class:`typing.Pattern` if it is one
+            already
         """
         if value is None:
             return None
@@ -155,8 +158,8 @@ def join_regex_str(
 class RstcheckConfig(RstcheckConfigFile):  # pylint: disable=too-few-public-methods
     """Rstcheck config.
 
-    :raises ValueError:: If setting has incorrect value or type
-    :raises pydantic.error_wrappers.ValidationError:: If setting is not parsable into correct type
+    :raises ValueError: If setting has incorrect value or type
+    :raises pydantic.error_wrappers.ValidationError: If setting is not parsable into correct type
     """
 
     config_path: t.Optional[pathlib.Path]
@@ -169,9 +172,9 @@ class _RstcheckConfigINIFile(
 ):  # pylint: disable=too-few-public-methods
     """Type for [rstcheck] section in INI file.
 
-    The types apply to the file's data before the parsing by ``RstcheckConfig`` is done.
+    The types apply to the file's data before the parsing by :py:class:`RstcheckConfig` is done.
 
-    :raises pydantic.error_wrappers.ValidationError:: If setting is not parsable into correct type
+    :raises pydantic.error_wrappers.ValidationError: If setting is not parsable into correct type
     """
 
     report_level: pydantic.NoneStr = pydantic.Field(None)  # pylint: disable=no-member
@@ -192,12 +195,13 @@ def _load_config_from_ini_file(
 
     :param ini_file: INI file to load config from
     :param log_missing_section_as_warning: If a missing [tool.rstcheck] section should be logged at
-        WARNING (``True``) or ``INFO`` (``False``) level;
-        defaults to ``True``
+        WARNING (:py:obj:`True`) or ``INFO`` (:py:obj:`False`) level;
+        defaults to :py:obj:`True`
     :param warn_unknown_settings: If a warning should be logged for unknown settings in config file;
         defaults to :py:obj:`False`
     :raises FileNotFoundError: If the file is not found
-    :return: instance of ``RstcheckConfigFile`` or ``None`` on missing config section
+    :return: instance of :py:class:`RstcheckConfigFile` or :py:class:`None` on missing config
+        section
     """
     logger.debug(f"Try loading config from INI file: '{ini_file}'")
     resolved_file = ini_file.resolve()
@@ -233,9 +237,9 @@ class _RstcheckConfigTOMLFile(
 ):  # pylint: disable=too-few-public-methods
     """Type for [tool.rstcheck] section in TOML file.
 
-    The types apply to the file's data before the parsing by ``RstcheckConfig`` is done.
+    The types apply to the file's data before the parsing by :py:class:`RstcheckConfig` is done.
 
-    :raises pydantic.error_wrappers.ValidationError:: If setting is not parsable into correct type
+    :raises pydantic.error_wrappers.ValidationError: If setting is not parsable into correct type
     """
 
     report_level: t.Optional[str] = pydantic.Field(None)
@@ -261,13 +265,13 @@ def _load_config_from_toml_file(
 
     :param toml_file: TOML file to load config from
     :param log_missing_section_as_warning: If a missing [tool.rstcheck] section should be logged at
-        WARNING (``True``) or ``INFO`` (``False``) level;
-        defaults to ``True``
+        WARNING (:py:obj:`True`) or ``INFO`` (:py:obj:`False`) level;
+        defaults to :py:obj:`True`
     :param warn_unknown_settings: If a warning should be logged for unknown settings in config file;
         defaults to :py:obj:`False`
     :raises ValueError: If the file is not a TOML file
     :raises FileNotFoundError: If the file is not found
-    :return: instance of ``RstcheckConfigFile`` or ``None`` on missing config section
+    :return: instance of :py:class:`RstcheckConfigFile` or :py:obj:`None` on missing config section
     """
     _extras.install_guard("tomli")
     logger.debug(f"Try loading config from TOML file: '{toml_file}'.")
@@ -318,16 +322,16 @@ def load_config_file(
     .. caution::
 
         If a TOML file is passed this function need tomli installed!
-        Use toml extra or install manally.
+        Use toml extra or install manually.
 
     :param file_path: File to load config from
     :param log_missing_section_as_warning: If a missing config section should be logged at
-        WARNING (``True``) or ``INFO`` (``False``) level;
-        defaults to ``True``
+        WARNING (:py:obj:`True`) or ``INFO`` (:py:obj:`False`) level;
+        defaults to :py:obj:`True`
     :param warn_unknown_settings: If a warning should be logged for unknown settings in config file;
         defaults to :py:obj:`False`
     :raises FileNotFoundError: If the file is not found
-    :return: instance of ``RstcheckConfigFile`` or ``None`` on missing config section
+    :return: instance of :py:class:`RstcheckConfigFile` or :py:obj:`None` on missing config section
     """
     logger.debug("Try loading config file.")
     if file_path.suffix.casefold() == ".toml":
@@ -351,17 +355,17 @@ def load_config_file_from_dir(
 ) -> t.Optional[RstcheckConfigFile]:
     """Search, load, parse and validate rstcheck config from a directory.
 
-    Searches files from ``CONFIG_FILES`` in the directory. If a file is found, try to load the
-    config from it. If is has no config, search further.
+    Searches files from :py:data:`CONFIG_FILES` in the directory. If a file is found, try to load
+    the config from it. If is has no config, search further.
 
     :param dir_path: Directory to search
     :param log_missing_section_as_warning: If a missing config section in a config file should be
-        logged at WARNING (``True``) or ``INFO`` (``False``) level;
-        defaults to ``False``
+        logged at WARNING (:py:obj:`True`) or ``INFO`` (:py:obj:`False`) level;
+        defaults to :py:obj:`False`
     :param warn_unknown_settings: If a warning should be logged for unknown settings in config file;
         defaults to :py:obj:`False`
-    :return: instance of ``RstcheckConfigFile`` or
-        ``None`` if no file is found or no file has a rstcheck section
+    :return: instance of :py:class:`RstcheckConfigFile` or
+        :py:obj:`None` if no file is found or no file has a rstcheck section
     """
     logger.debug(f"Try loading config file from directory: '{dir_path}'.")
     config = None
@@ -393,18 +397,18 @@ def load_config_file_from_dir_tree(
 ) -> t.Optional[RstcheckConfigFile]:
     """Search, load, parse and validate rstcheck config from a directory tree.
 
-    Searches files from ``CONFIG_FILES`` in the directory. If a file is found, try to load the
-    config from it. If is has no config, search further. If no config is found in the directory
+    Searches files from :py:data:`CONFIG_FILES` in the directory. If a file is found, try to load
+    the config from it. If is has no config, search further. If no config is found in the directory
     search its parents one by one.
 
     :param dir_path: Directory to search
     :param log_missing_section_as_warning: If a missing config section in a config file should be
-        logged at WARNING (``True``) or ``INFO`` (``False``) level;
-        defaults to ``False``
+        logged at ``WARNING`` (:py:obj:`True`) or ``INFO`` (:py:obj:`False`) level;
+        defaults to :py:obj:`False`
     :param warn_unknown_settings: If a warning should be logged for unknown settings in config file;
         defaults to :py:obj:`False`
-    :return: instance of ``RstcheckConfigFile`` or
-        ``None`` if no file is found or no file has a rstcheck section
+    :return: instance of :py:class:`RstcheckConfigFile` or
+        :py:obj:`None` if no file is found or no file has a rstcheck section
     """
     logger.debug(f"Try loading config file from directory tree: '{dir_path}'.")
     config = None
@@ -447,19 +451,19 @@ def load_config_file_from_path(
     :param path: Path to load config file from; can be a file or directory
     :param search_dir_tree: If the directory tree should be searched;
         only applies if ``path`` is a directory;
-        defaults to False
+        defaults to :py:obj:`False`
     :param log_missing_section_as_warning_for_file: If a missing config section in a config file
-        should be logged at WARNING (``True``) or ``INFO`` (``False``) level when the given path is
-        a file;
-        defaults to ``True``
+        should be logged at WARNING (:py:obj:`True`) or ``INFO`` (:py:obj:`False`) level when the
+        given path is a file;
+        defaults to :py:obj:`True`
     :param log_missing_section_as_warning_for_dir: If a missing config section in a config file
-        should be logged at WARNING (``True``) or ``INFO`` (``False``) level when the given file is
-        a direcotry;
-        defaults to ``False``
+        should be logged at ``WARNING`` (:py:obj:`True`) or ``INFO`` (:py:obj:`False`) level when
+        the given file is a direcotry;
+        defaults to :py:obj:`False`
     :param warn_unknown_settings: If a warning should be logged for unknown settings in config file;
         defaults to :py:obj:`False`
-    :return: instance of ``RstcheckConfigFile`` or
-        ``None`` if no file is found or no file has a rstcheck section
+    :return: instance of :py:class:`RstcheckConfigFile` or
+        :py:obj:`None` if no file is found or no file has a rstcheck section
     """
     logger.debug(f"Try loading config file from path: '{path}'.")
     resolved_path = path.resolve()
@@ -499,7 +503,7 @@ def merge_configs(
     :param config_base: The base config to merge into
     :param config_add: The config that is merged into the ``config_base``
     :param config_add_is_dominant: If the ``config_add`` overwrites values of ``config_base``;
-        defaults to True
+        defaults to :py:obj:`True`
     :return: New merged config
     """
     logger.debug("Merging configs.")
diff --git a/src/rstcheck/inline_config.py b/src/rstcheck/inline_config.py
index a6eefec8..9a870879 100644
--- a/src/rstcheck/inline_config.py
+++ b/src/rstcheck/inline_config.py
@@ -21,6 +21,10 @@ def find_ignored_languages(
 
     For example, to ignore C++, JSON, and Python:
 
+    .. testsetup::
+
+        from rstcheck.inline_config import find_ignored_languages
+
     >>> list(find_ignored_languages('''
     ... Example
     ... =======
@@ -28,8 +32,8 @@ def find_ignored_languages(
     ... .. rstcheck: ignore-languages=cpp,json
     ...
     ... .. rstcheck: ignore-languages=python
-    ... '''))
-    ["cpp", "json", "python"]
+    ... ''', "<string>"))
+    ['cpp', 'json', 'python']
 
     :param source: Rst source code
     :param source_origin: Origin of the source with the inline ignore comments
diff --git a/src/rstcheck/runner.py b/src/rstcheck/runner.py
index 0f63920b..dd72f535 100644
--- a/src/rstcheck/runner.py
+++ b/src/rstcheck/runner.py
@@ -22,7 +22,7 @@ def __init__(
         rstcheck_config: config.RstcheckConfig,
         overwrite_config: bool = True,
     ) -> None:
-        """Initialize the ``RstcheckMainRunner`` with a base config.
+        """Initialize the :py:class:`RstcheckMainRunner` with a base config.
 
         :param check_paths: Files to check.
         :param rstcheck_config: Base configuration config from e.g. the CLI.
@@ -50,8 +50,8 @@ def load_config_file(
     ) -> None:
         """Load config from file and merge with current config.
 
-        If the loaded file config overwrites the current config depends on the ``overwrite_config``
-        attribute set on initialization.
+        If the loaded file config overwrites the current config depends on the
+        ``self.overwrite_config`` attribute set on initialization.
 
         :param config_path: Path to config file; can be directory or file
         :param warn_unknown_settings: If a warning should be logged for unknown settings in config
@@ -79,9 +79,9 @@ def update_file_list(self) -> None:  # noqa: CCR001
         """Update file path list with paths specified on initialization.
 
         Clear the current file list. Then get the file and directory paths specified with
-        ``self.check_paths`` and search them for rst files to check. Add those files to the file
-        list.
-        """
+        ``self.check_paths`` attribute set on initialization and search them for rst files
+        to check. Add those files to the file list.
+        """  # noqa: Q440,Q441,Q447,Q449
         logger.debug("Updating list of files to check.")
         paths = list(self.check_paths)
         self.files_to_check = []
@@ -141,7 +141,8 @@ def _run_checks_parallel(self) -> t.List[t.List[types.LintError]]:
     def _update_results(self, results: t.List[t.List[types.LintError]]) -> None:
         """Take results and update error cache.
 
-        Result normally come from ``self._run_checks_sync`` or ``self._run_checks_parallel``.
+        Result normally come from :py:meth:`RstcheckMainRunner._run_checks_sync` or
+        :py:meth:`RstcheckMainRunner._run_checks_parallel`.
         :param results: List of lists of errors found
         """
         self.errors = []
diff --git a/src/rstcheck/types.py b/src/rstcheck/types.py
index 143b7a46..a1c64c6e 100644
--- a/src/rstcheck/types.py
+++ b/src/rstcheck/types.py
@@ -18,7 +18,7 @@ class LintError(_compat.TypedDict):
 
 
 YieldedLintError = t.Generator[LintError, None, None]
-"""Yielded version of type ``LintError``."""
+"""Yielded version of type :py:class:`LintError`."""
 
 
 class IgnoreDict(_compat.TypedDict):
@@ -35,5 +35,5 @@ class IgnoreDict(_compat.TypedDict):
 CheckerRunFunction = t.Callable[..., YieldedLintError]
 """Function to run checks.
 
-Returned by ``CodeBlockChecker.create_checker``.
+Returned by :py:meth:`rstcheck.checker.CodeBlockChecker.create_checker`.
 """
diff --git a/tox.ini b/tox.ini
index abc55bac..6886fa7c 100644
--- a/tox.ini
+++ b/tox.ini
@@ -15,6 +15,8 @@ envlist =
     py{310,39,38,37}
     py{310,39,38,37}-with-sphinx{2,3,4}
     py{310,39,38,37}-with-tomli
+    coverage-all
+    docs-test-{html,linkcheck,coverage,doctest,spelling}
 
 
 [envlists]
@@ -23,6 +25,7 @@ py3.7 = py37,py37-with-sphinx{2,3,4},py37-with-tomli,coverage-all
 py3.8 = py38,py38-with-sphinx{2,3,4},py38-with-tomli,coverage-all
 py3.9 = py39,py39-with-sphinx{2,3,4},py39-with-tomli,coverage-all
 py3.10 = py310,py310-with-sphinx{2,3,4},py310-with-tomli,package,coverage-all
+docs = docs-test-{html,linkcheck,coverage,doctest,spelling}
 
 
 [testenv]
@@ -33,6 +36,7 @@ passenv =
     CI_FORCE_COLORS_PRE_COMMIT
     CI_FORCE_COLORS_POETRY
     CI_FORCE_COLORS_PYTEST
+    CI_FORCE_COLORS_SPHINX
 setenv =
     PIP_DISABLE_VERSION_CHECK = 1
 download = true
@@ -40,6 +44,7 @@ download = true
 
 [testenv:pre-commit]
 description = format and check the code
+envdir = {toxworkdir}/pre-commit
 passenv =
     {[testenv]passenv}
     SSH_AUTH_SOCK
@@ -49,6 +54,15 @@ setenv =
     SKIP = {tty:identity:},{env:SKIP:}
 skip_install = true
 deps = pre-commit >= 2.17
+commands =
+    pre-commit {posargs:--help}
+
+
+[testenv:pre-commit-run]
+description = install pre-commit as git hook from the tox env
+envdir = {[testenv:pre-commit]envdir}
+skip_install = {[testenv:pre-commit]skip_install}
+deps = {[testenv:pre-commit]deps}
 commands =
     pre-commit run {posargs} \
         --all-files \
@@ -56,6 +70,14 @@ commands =
         {tty:--color always:{env:CI_FORCE_COLORS_PRE_COMMIT:}}
 
 
+[testenv:pre-commit-install]
+description = install pre-commit as git hook from the tox env
+envdir = {[testenv:pre-commit]envdir}
+skip_install = {[testenv:pre-commit]skip_install}
+deps = {[testenv:pre-commit]deps}
+commands = pre-commit install
+
+
 [testenv:mypy]
 description = run mypy type checker
 deps = mypy >=0.931
@@ -63,10 +85,13 @@ extras =
     sphinx
     toml
     testing
+    docs
 ignore_errors = true
 commands =
     mypy src/rstcheck
     mypy tests
+    mypy docs/source/conf.py
+    mypy prep_release.py
 
 
 [testenv:pylint]
@@ -76,7 +101,8 @@ extras =
     sphinx
     toml
     testing
-commands = pylint src/rstcheck tests
+    docs
+commands = pylint src/rstcheck tests docs/source/conf.py prep_release.py
 
 
 [testenv:package]
@@ -109,6 +135,7 @@ commands =
         {posargs:tests}
     ; python -m doctest -v README.rst rstcheck/__init__.py
 
+
 [testenv:py{310,39,38,37}-with-sphinx{2,3,4}]
 description = run tests with {basepython} and sphinx
 passenv =
@@ -136,6 +163,7 @@ commands =
         {posargs:tests}
     ; python -m doctest -v README.rst rstcheck/__init__.py
 
+
 [testenv:py{310,39,38,37}-with-tomli]
 description = run tests with {basepython} and tomli
 passenv =
@@ -157,6 +185,7 @@ commands =
         {posargs:tests}
     ; python -m doctest -v README.rst rstcheck/__init__.py
 
+
 [testenv:coverage-{all,merge,report}]
 description =
     all,merge: combine coverage data and create xml/html reports;
@@ -189,3 +218,43 @@ commands =
     all,report:     --fail-under {env:MIN_DIFF_COVERAGE:0} \
     all,report:     --diff-range-notation {env:DIFF_RANGE_NOTATION:..} \
     all,report:     {toxinidir}/.coverage_cache/coverage.xml
+
+
+[testenv:docs{,-auto}]
+description = build docs with sphinx
+envdir = {toxworkdir}/docs
+setenv =
+    {[testenv]setenv}
+    TOXENV_BUILDCMD = sphinx-build {tty:--color:}
+    auto: TOXENV_BUILDCMD = sphinx-autobuild
+extras =
+    docs
+    sphinx
+    toml
+commands =
+    # Build fresh docs
+    {env:TOXENV_BUILDCMD} -b html -aE docs/source docs/build/html
+    # Output link to index.html
+    python -c \
+       'from pathlib import Path; \
+        index_file = Path(r"{toxinidir}")/"docs/build/html/index.html"; \
+        print(f"DOCUMENTATION AVAILABLE UNDER: \{index_file.as_uri()\}")'
+
+
+[testenv:docs-test-{html,linkcheck,coverage,doctest,spelling}]
+description = Build and check docs with (see env name) sphinx builder
+envdir = {[testenv:docs]envdir}
+setenv =
+    {[testenv]setenv}
+    html:       TOXENV_BUILDER = html
+    linkcheck:  TOXENV_BUILDER = linkcheck
+    coverage:   TOXENV_BUILDER = coverage
+    doctest:    TOXENV_BUILDER = doctest
+    spelling:   TOXENV_BUILDER = spelling
+extras = {[testenv:docs]extras}
+commands =
+    sphinx-build \
+        {tty:--color:{env:CI_FORCE_COLORS_SPHINX:}} \
+        -b {env:TOXENV_BUILDER} \
+        -aE -v -nW --keep-going \
+        docs/source docs/build/test/{env:TOXENV_BUILDER}


Test patch:
diff --git a/tests/integration_tests/conftest.py b/tests/integration_tests/conftest.py
index a0e7320a..26daf0f7 100644
--- a/tests/integration_tests/conftest.py
+++ b/tests/integration_tests/conftest.py
@@ -5,7 +5,7 @@
 import typer
 import typer.testing
 
-from rstcheck import cli
+from rstcheck import _cli
 
 
 ERROR_CODE_REGEX = re.compile(r"\([A-Z]*?/\d\)")
@@ -14,9 +14,7 @@
 @pytest.fixture(name="cli_app")
 def cli_app_fixture() -> typer.Typer:
     """Create typer app from ``cli`` function for testing."""
-    app = typer.Typer()
-    app.command()(cli.cli)
-    return app
+    return _cli.app
 
 
 @pytest.fixture(name="cli_runner")
diff --git a/tests/test_cli.py b/tests/test__cli.py
similarity index 74%
rename from tests/test_cli.py
rename to tests/test__cli.py
index fa361c50..765da161 100644
--- a/tests/test_cli.py
+++ b/tests/test__cli.py
@@ -1,21 +1,21 @@
-"""Tests for ``cli`` module.
+"""Tests for ``_cli`` module.
 
-``cli.cli`` is not really good testable with unit tests.
+``_cli.cli`` is not really good testable with unit tests.
 Therfore tests are in the ``integration_tests`` directory.
 """
 import pytest
 
-from rstcheck import cli
+from rstcheck import _cli
 
 
 @pytest.mark.parametrize("level", ["SEVERE", "NONE"])
 def test_setup_logger_errors_on_invalid_levels(level: str) -> None:
     """Tests exception is raised on invalid levels."""
     with pytest.raises(ValueError, match=f"Invalid log level: {level}"):
-        cli.setup_logger(level)
+        _cli.setup_logger(level)
 
 
 @pytest.mark.parametrize("level", ["debug", "InFO", "WARNING", "ErRor", "critical"])
 def test_setup_logger_valid_levels(level: str) -> None:
     """Test no execption is raised on valid levels."""
-    cli.setup_logger(level)  # act
+    _cli.setup_logger(level)  # act