From 108b61bbb406b06e417f5e295b0294cd1ebb7d00 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Thu, 12 Sep 2024 23:03:47 +0200
Subject: [PATCH 01/62] check pre-commit code checks and formatters via
 precommit-ci-lite bot

---
 .github/workflows/format-code.yaml |  25 +++++
 .pre-commit-config.yaml            | 155 +++++++++++++++++++++++++++++
 2 files changed, 180 insertions(+)
 create mode 100644 .github/workflows/format-code.yaml
 create mode 100644 .pre-commit-config.yaml

diff --git a/.github/workflows/format-code.yaml b/.github/workflows/format-code.yaml
new file mode 100644
index 00000000..b9e1b2bf
--- /dev/null
+++ b/.github/workflows/format-code.yaml
@@ -0,0 +1,25 @@
+name: Check code
+on:
+  pull_request:
+    branches: [main]
+
+permissions:
+  contents: write
+  pull-requests: write
+
+jobs:
+  main:
+    runs-on: ubuntu-22.04
+    steps:
+      - uses: actions/checkout@v4
+      - uses: actions/setup-python@v4
+        with:
+          python-version: 3.x
+      - uses: pre-commit/action@v3.0.1
+      - uses: pre-commit-ci/lite-action@v1.0.3
+        name: pre-commit-ci-lite
+        if: always()
+        with:
+          msg: apply code formatting
+    env:
+      GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 00000000..11472f54
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,155 @@
+# All available hooks: https://pre-commit.com/hooks.html
+# R specific hooks: https://github.com/lorenzwalthert/precommit
+repos:
+-   repo: https://github.com/lorenzwalthert/precommit
+    rev: v0.4.3
+    hooks: 
+    -   id: style-files
+        args: [--style_pkg=styler, --style_fun=tidyverse_style, --cache-root=styler-perm]
+        exclude: > 
+          (?x)^(
+          tests/testthat/in/.*|
+          renv/.*
+          )$
+    -   id: roxygenize
+        additional_dependencies:
+        -    cli
+        -    fs
+        -    here
+        -    magrittr
+        -    purrr
+        -    R.cache
+        -    rlang
+        -    rprojroot
+        -    rstudioapi
+        -    withr
+        -    yaml
+        -    r-lib/pkgapi
+    # codemeta must be above use-tidy-description when both are used
+    # -   id: codemeta-description-updated
+    -   id: use-tidy-description
+    -   id: spell-check
+        exclude: >
+          (?x)^(
+          .*\.[rR]|
+          .*\.feather|
+          .*\.jpeg|
+          .*\.pdf|
+          .*\.png|
+          .*\.py|
+          .*\.RData|
+          .*\.rds|
+          .*\.Rds|
+          .*\.Rproj|
+          .*\.sh|
+          (.*/|)\.gitignore|
+          (.*/|)\.pre-commit-.*|
+          (.*/|)\.Rbuildignore|
+          (.*/|)\.Renviron|
+          (.*/|)\.Rprofile|
+          (.*/|)\.travis\.yml|
+          (.*/|)appveyor\.yml|
+          (.*/|)NAMESPACE|
+          (.*/|)renv/settings\.dcf|
+          (.*/|)renv\.lock|
+          (.*/|)WORDLIST|
+          \.github/workflows/.*|
+          LICENSE|
+          revdep/.*|
+          tests/testthat/in/.*|
+          )$
+    -   id: readme-rmd-rendered
+    -   id: parsable-R
+        exclude: > 
+          (?x)^(
+          tests/testthat/in/.*|
+          )$
+    -   id: no-browser-statement
+        exclude: > 
+          (?x)^(
+          tests/testthat/in/.*|
+          )$
+    -   id: no-debug-statement
+        exclude: >
+          (?x)^(
+          tests/testthat/in/.*|
+          )$
+    -   id: deps-in-desc
+    -   id: pkgdown
+-   repo: https://github.com/pre-commit/pre-commit-hooks
+    rev: v4.6.0
+    hooks: 
+    -   id: check-added-large-files
+    -   id: end-of-file-fixer
+        exclude: '\.Rd' # sometimes roxygen fails to generate EOF blank line.
+    -   id: file-contents-sorter
+        files: '^\.Rbuildignore$'
+-   repo: https://github.com/pre-commit-ci/pre-commit-ci-config
+    rev: v1.6.1
+    hooks:
+    # Only required when https://pre-commit.ci is used for config validation
+    -   id: check-pre-commit-ci-config
+-   repo: https://github.com/lorenzwalthert/gitignore-tidy
+    rev: 0.1.2
+    hooks: 
+    -   id: tidy-gitignore
+-   repo: local
+    hooks:
+    -   id: consistent-release-tag
+        name: consistent-release-tag
+        entry: Rscript inst/hooks/local/consistent-release-tag.R
+        language: r
+        additional_dependencies:
+        -    docopt
+        -    fs
+        -    yaml
+        -    purrr
+        -    glue
+        -    rlang
+        -    git2r
+        -    desc
+        -    lorenzwalthert/precommit
+        stages: [commit, push]
+    -   id: hooks-config-to-inst
+        name: hooks-config-to-inst
+        entry: Rscript inst/hooks/local/hooks-config-to-inst.R
+        language: r
+        stages: [commit, push]
+        additional_dependencies:
+        -    fs
+        require_serial: True
+    -   id: spell-check-exclude-identical
+        name: spell-check-exclude-identical
+        entry: Rscript inst/hooks/local/spell-check-exclude-identical.R
+        language: r
+        stages: [commit, push]
+        additional_dependencies:
+        -    magrittr
+        -    purrr
+        -    yaml
+        -    here
+        -    rlang
+        require_serial: True
+    -   id: forbid-to-commit
+        name: Don't commit common R artifacts
+        entry: Cannot commit .Rhistory, .Rdata, .csv and similar.
+        language: fail
+        files: '\.(Rhistory|csv|RData|Rds|rds)$'
+        # `exclude: <regex>` to allow committing specific files.
+    -   id: spell-check-ordered-exclude
+        name: Ordered regex pattern for spell-check exclusion
+        description: Ensure alphabetical order in `exclude:` key of spell check.
+        entry: Rscript inst/hooks/local/spell-check-ordered-exclude.R
+        language: r
+        files: '^(.*/|)\.?pre-commit-config.*\.yaml$'
+        additional_dependencies:
+        -    magrittr
+        -    yaml
+        -    purrr
+        -    rlang
+
+default_stages: ["commit"]
+
+ci:
+    skip: [consistent-release-tag, spell-check-ordered-exclude, pkgdown]
+    autoupdate_schedule: monthly

From f9b040f36c77676c5b427c4290a6e3b3b06d8148 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Thu, 12 Sep 2024 23:36:22 +0200
Subject: [PATCH 02/62] fix according pre-commit hoooks

---
 man/rix.Rd | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/man/rix.Rd b/man/rix.Rd
index ea5e9abb..d3d92c16 100644
--- a/man/rix.Rd
+++ b/man/rix.Rd
@@ -114,7 +114,7 @@ command line, or from another editor (such as Emacs or Vim), set the \code{ide}
 argument to \code{"other"}. We recommend reading the
 \code{vignette("e-interactive-use")} for more details.
 
-Packages to install from Github must be provided in a list of 3 elements:
+Packages to install from Github or Gitlab must be provided in a list of 3 elements:
 "package_name", "repo_url" and "commit". To install several packages,
 provide a list of lists of these 3 elements, one per package to install. It
 is also possible to install old versions of packages by specifying a
@@ -127,9 +127,9 @@ have looked at the time of \code{{ggplot2}}'s version 2.2.1 release, then use
 the Nix revision closest to that date, by setting \code{r_ver = "3.1.0"}, which
 was the version of R current at the time. This ensures that Nix builds a
 completely coherent environment. For security purposes, users that wish to
-install packages from Github or from the CRAN archives must provide a
+install packages from Github/Gitlab or from the CRAN archives must provide a
 security hash for each package. \code{{rix}} automatically precomputes this hash
-for the source directory of R packages from GitHub or from the CRAN
+for the source directory of R packages from GitHub/Gitlab or from the CRAN
 archives, to make sure the expected trusted sources that match the
 precomputed hashes in the \code{default.nix} are downloaded. If Nix is
 available, then the hash will be computed on the user's machine, however,

From a99e688a53bed220fd4e6e083bc915b421804ecd Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Fri, 13 Sep 2024 10:18:02 +0200
Subject: [PATCH 03/62] debug: slim down hooks to styler

---
 .pre-commit-config.yaml | 122 ----------------------------------------
 1 file changed, 122 deletions(-)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 11472f54..5c122182 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -25,128 +25,6 @@ repos:
         -    withr
         -    yaml
         -    r-lib/pkgapi
-    # codemeta must be above use-tidy-description when both are used
-    # -   id: codemeta-description-updated
-    -   id: use-tidy-description
-    -   id: spell-check
-        exclude: >
-          (?x)^(
-          .*\.[rR]|
-          .*\.feather|
-          .*\.jpeg|
-          .*\.pdf|
-          .*\.png|
-          .*\.py|
-          .*\.RData|
-          .*\.rds|
-          .*\.Rds|
-          .*\.Rproj|
-          .*\.sh|
-          (.*/|)\.gitignore|
-          (.*/|)\.pre-commit-.*|
-          (.*/|)\.Rbuildignore|
-          (.*/|)\.Renviron|
-          (.*/|)\.Rprofile|
-          (.*/|)\.travis\.yml|
-          (.*/|)appveyor\.yml|
-          (.*/|)NAMESPACE|
-          (.*/|)renv/settings\.dcf|
-          (.*/|)renv\.lock|
-          (.*/|)WORDLIST|
-          \.github/workflows/.*|
-          LICENSE|
-          revdep/.*|
-          tests/testthat/in/.*|
-          )$
-    -   id: readme-rmd-rendered
-    -   id: parsable-R
-        exclude: > 
-          (?x)^(
-          tests/testthat/in/.*|
-          )$
-    -   id: no-browser-statement
-        exclude: > 
-          (?x)^(
-          tests/testthat/in/.*|
-          )$
-    -   id: no-debug-statement
-        exclude: >
-          (?x)^(
-          tests/testthat/in/.*|
-          )$
-    -   id: deps-in-desc
-    -   id: pkgdown
--   repo: https://github.com/pre-commit/pre-commit-hooks
-    rev: v4.6.0
-    hooks: 
-    -   id: check-added-large-files
-    -   id: end-of-file-fixer
-        exclude: '\.Rd' # sometimes roxygen fails to generate EOF blank line.
-    -   id: file-contents-sorter
-        files: '^\.Rbuildignore$'
--   repo: https://github.com/pre-commit-ci/pre-commit-ci-config
-    rev: v1.6.1
-    hooks:
-    # Only required when https://pre-commit.ci is used for config validation
-    -   id: check-pre-commit-ci-config
--   repo: https://github.com/lorenzwalthert/gitignore-tidy
-    rev: 0.1.2
-    hooks: 
-    -   id: tidy-gitignore
--   repo: local
-    hooks:
-    -   id: consistent-release-tag
-        name: consistent-release-tag
-        entry: Rscript inst/hooks/local/consistent-release-tag.R
-        language: r
-        additional_dependencies:
-        -    docopt
-        -    fs
-        -    yaml
-        -    purrr
-        -    glue
-        -    rlang
-        -    git2r
-        -    desc
-        -    lorenzwalthert/precommit
-        stages: [commit, push]
-    -   id: hooks-config-to-inst
-        name: hooks-config-to-inst
-        entry: Rscript inst/hooks/local/hooks-config-to-inst.R
-        language: r
-        stages: [commit, push]
-        additional_dependencies:
-        -    fs
-        require_serial: True
-    -   id: spell-check-exclude-identical
-        name: spell-check-exclude-identical
-        entry: Rscript inst/hooks/local/spell-check-exclude-identical.R
-        language: r
-        stages: [commit, push]
-        additional_dependencies:
-        -    magrittr
-        -    purrr
-        -    yaml
-        -    here
-        -    rlang
-        require_serial: True
-    -   id: forbid-to-commit
-        name: Don't commit common R artifacts
-        entry: Cannot commit .Rhistory, .Rdata, .csv and similar.
-        language: fail
-        files: '\.(Rhistory|csv|RData|Rds|rds)$'
-        # `exclude: <regex>` to allow committing specific files.
-    -   id: spell-check-ordered-exclude
-        name: Ordered regex pattern for spell-check exclusion
-        description: Ensure alphabetical order in `exclude:` key of spell check.
-        entry: Rscript inst/hooks/local/spell-check-ordered-exclude.R
-        language: r
-        files: '^(.*/|)\.?pre-commit-config.*\.yaml$'
-        additional_dependencies:
-        -    magrittr
-        -    yaml
-        -    purrr
-        -    rlang
 
 default_stages: ["commit"]
 

From be6b3959d2c3968b9c5b3b592edf806f877c5f67 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Fri, 13 Sep 2024 10:23:15 +0200
Subject: [PATCH 04/62] remove roxygenize

---
 .pre-commit-config.yaml | 15 ---------------
 1 file changed, 15 deletions(-)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 5c122182..14a85db1 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -9,22 +9,7 @@ repos:
         exclude: > 
           (?x)^(
           tests/testthat/in/.*|
-          renv/.*
           )$
-    -   id: roxygenize
-        additional_dependencies:
-        -    cli
-        -    fs
-        -    here
-        -    magrittr
-        -    purrr
-        -    R.cache
-        -    rlang
-        -    rprojroot
-        -    rstudioapi
-        -    withr
-        -    yaml
-        -    r-lib/pkgapi
 
 default_stages: ["commit"]
 

From 1048daea1108dbe0122590ed9c3c53178c23ebfe Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Fri, 13 Sep 2024 10:27:22 +0200
Subject: [PATCH 05/62] avoid pre-commit action and only use the lite (applies
 fixes)

---
 .github/workflows/format-code.yaml | 1 -
 1 file changed, 1 deletion(-)

diff --git a/.github/workflows/format-code.yaml b/.github/workflows/format-code.yaml
index b9e1b2bf..d022f488 100644
--- a/.github/workflows/format-code.yaml
+++ b/.github/workflows/format-code.yaml
@@ -15,7 +15,6 @@ jobs:
       - uses: actions/setup-python@v4
         with:
           python-version: 3.x
-      - uses: pre-commit/action@v3.0.1
       - uses: pre-commit-ci/lite-action@v1.0.3
         name: pre-commit-ci-lite
         if: always()

From ba7ca8923be7ead170c641e0e399ecb1dcee9a98 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Fri, 13 Sep 2024 10:31:47 +0200
Subject: [PATCH 06/62] add space to test linter

---
 R/rix.R | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/R/rix.R b/R/rix.R
index 9ab8ba1b..419b358c 100644
--- a/R/rix.R
+++ b/R/rix.R
@@ -175,7 +175,7 @@ before continuing."
   }
 
   if (message_type != "quiet" && r_ver %in% available_r() &&
-    r_ver != "latest" && r_ver <= "4.1.1") {
+     r_ver != "latest" && r_ver <= "4.1.1") {
     warning(
       "You are generating an expression for an older version of R.\n",
       "To use this environment, you should directly use `nix-shell` and not ",

From f2c99953f40919028e5da5b5531c24b40a1d374a Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Fri, 13 Sep 2024 10:39:09 +0200
Subject: [PATCH 07/62] use latest; add back precommit action

---
 .github/workflows/format-code.yaml | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/format-code.yaml b/.github/workflows/format-code.yaml
index d022f488..e6d769d9 100644
--- a/.github/workflows/format-code.yaml
+++ b/.github/workflows/format-code.yaml
@@ -9,12 +9,13 @@ permissions:
 
 jobs:
   main:
-    runs-on: ubuntu-22.04
+    runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
       - uses: actions/setup-python@v4
         with:
           python-version: 3.x
+      - uses: pre-commit/action@v3.0.1
       - uses: pre-commit-ci/lite-action@v1.0.3
         name: pre-commit-ci-lite
         if: always()

From 026e8f6f3cb933aa443f9f79b4eed6e981e0f2dd Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Fri, 13 Sep 2024 14:27:48 +0200
Subject: [PATCH 08/62] now after pre-commit-lite ci enabled

---
 R/rix.R | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/R/rix.R b/R/rix.R
index 419b358c..731543ea 100644
--- a/R/rix.R
+++ b/R/rix.R
@@ -162,7 +162,7 @@ rix <- function(r_ver = "latest",
                 message_type = "simple",
                 shell_hook = NULL) {
   message_type <- match.arg(message_type,
-    choices = c("quiet", "simple", "verbose")
+     choices = c("quiet", "simple", "verbose")
   )
 
   if (!(message_type %in% c("simple", "quiet")) && r_ver %in% c("bleeding_edge", "frozen_edge")) {

From 8c51a0c27cc7a42e556062894d64141839aa84a1 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Fri, 13 Sep 2024 14:33:04 +0200
Subject: [PATCH 09/62] disable unused hooks

---
 .pre-commit-config.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 14a85db1..97edb784 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -14,5 +14,5 @@ repos:
 default_stages: ["commit"]
 
 ci:
-    skip: [consistent-release-tag, spell-check-ordered-exclude, pkgdown]
+    # skip: [consistent-release-tag, spell-check-ordered-exclude, pkgdown]
     autoupdate_schedule: monthly

From b8d6bf044adaca369a4c0548cac6b1096b0048b3 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
 <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Fri, 13 Sep 2024 12:33:31 +0000
Subject: [PATCH 10/62] [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci
---
 R/rix.R          |  4 ++--
 create_dev_env.R | 26 +++++++++++++++-----------
 2 files changed, 17 insertions(+), 13 deletions(-)

diff --git a/R/rix.R b/R/rix.R
index 731543ea..9ab8ba1b 100644
--- a/R/rix.R
+++ b/R/rix.R
@@ -162,7 +162,7 @@ rix <- function(r_ver = "latest",
                 message_type = "simple",
                 shell_hook = NULL) {
   message_type <- match.arg(message_type,
-     choices = c("quiet", "simple", "verbose")
+    choices = c("quiet", "simple", "verbose")
   )
 
   if (!(message_type %in% c("simple", "quiet")) && r_ver %in% c("bleeding_edge", "frozen_edge")) {
@@ -175,7 +175,7 @@ before continuing."
   }
 
   if (message_type != "quiet" && r_ver %in% available_r() &&
-     r_ver != "latest" && r_ver <= "4.1.1") {
+    r_ver != "latest" && r_ver <= "4.1.1") {
     warning(
       "You are generating an expression for an older version of R.\n",
       "To use this environment, you should directly use `nix-shell` and not ",
diff --git a/create_dev_env.R b/create_dev_env.R
index 7562fe5b..07bae46c 100644
--- a/create_dev_env.R
+++ b/create_dev_env.R
@@ -1,13 +1,17 @@
 library(rix)
 
-rix(r_ver = "bleeding_edge",
-    r_pkgs = c("devtools", "diffviewer", "fledge", "lintr", "styler",
-               "codetools", "jsonlite",  "httr", "sys", "testthat", "knitr",
-               "rmarkdown", "rhub"),
-    system_pkgs = c("R", "glibcLocalesUtf8", "pandoc", "nix"),
-    tex_pkgs = "scheme-small",
-    ide = "other",
-    project_path = ".",
-    overwrite = TRUE,
-    print = FALSE,
-    shell_hook = NULL)
+rix(
+  r_ver = "bleeding_edge",
+  r_pkgs = c(
+    "devtools", "diffviewer", "fledge", "lintr", "styler",
+    "codetools", "jsonlite", "httr", "sys", "testthat", "knitr",
+    "rmarkdown", "rhub"
+  ),
+  system_pkgs = c("R", "glibcLocalesUtf8", "pandoc", "nix"),
+  tex_pkgs = "scheme-small",
+  ide = "other",
+  project_path = ".",
+  overwrite = TRUE,
+  print = FALSE,
+  shell_hook = NULL
+)

From 6c46d03655a5b9996b4e0b7bd6537d5adc568a24 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Fri, 13 Sep 2024 14:41:20 +0200
Subject: [PATCH 11/62] parsable R and no browser()

---
 .pre-commit-config.yaml | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 97edb784..0634556e 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -10,6 +10,16 @@ repos:
           (?x)^(
           tests/testthat/in/.*|
           )$
+    -   id: parsable-R
+        exclude: > 
+          (?x)^(
+          tests/testthat/in/.*|
+          )$
+    -   id: no-browser-statement
+        exclude: > 
+          (?x)^(
+          tests/testthat/in/.*|
+          )$
 
 default_stages: ["commit"]
 

From f38c3a271fa23c2eef50a36fe2944ba18713ac18 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Fri, 13 Sep 2024 14:52:51 +0200
Subject: [PATCH 12/62] remove old lintr action

---
 .github/workflows/lint.yaml | 38 -------------------------------------
 1 file changed, 38 deletions(-)
 delete mode 100644 .github/workflows/lint.yaml

diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml
deleted file mode 100644
index 974c286e..00000000
--- a/.github/workflows/lint.yaml
+++ /dev/null
@@ -1,38 +0,0 @@
-# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
-# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
-on:
-  push:
-    branches: [main, master]
-  pull_request:
-    branches: [main, master]
-
-name: lint
-
-permissions: read-all
-
-jobs:
-  lint:
-    runs-on: ubuntu-latest
-    env:
-      GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
-    steps:
-      - uses: actions/checkout@v4
-
-      - name: Install Nix
-        uses: DeterminateSystems/nix-installer-action@main
-
-      - uses: cachix/cachix-action@v15
-        with:
-          name: rstats-on-nix
-          # If you chose signing key for write access
-          # signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}'
-          # If you chose API tokens for write access OR if you have a private cache
-          authToken: '${{ secrets.CACHIX_AUTH }}'
-
-      - name: Build dev env
-        run: nix-build
-
-      - name: Run lintr
-        run: nix-shell --run "Rscript -e 'lintr::lint_package()'"
-        env:
-          LINTR_ERROR_ON_LINT: false

From 9e8b9db6424a22b7cd6900b7a7d0a845bba47adf Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Fri, 13 Sep 2024 15:08:27 +0200
Subject: [PATCH 13/62] avoid race conditions

---
 .pre-commit-config.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 0634556e..e08f3c24 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -6,6 +6,7 @@ repos:
     hooks: 
     -   id: style-files
         args: [--style_pkg=styler, --style_fun=tidyverse_style, --cache-root=styler-perm]
+        require_serial: true
         exclude: > 
           (?x)^(
           tests/testthat/in/.*|

From 17894c4aa1f902d2fed4809d6828d5ea4d96d65e Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Fri, 13 Sep 2024 15:14:13 +0200
Subject: [PATCH 14/62] also add .lintr hook

---
 .pre-commit-config.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index e08f3c24..49c31489 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -11,6 +11,7 @@ repos:
           (?x)^(
           tests/testthat/in/.*|
           )$
+    -   id: lintr
     -   id: parsable-R
         exclude: > 
           (?x)^(

From 95efc16bd900a89efc5af2cdf3b8fabc9d38cac3 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Fri, 13 Sep 2024 15:35:42 +0200
Subject: [PATCH 15/62] please lintr

---
 R/fetchers.R | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/R/fetchers.R b/R/fetchers.R
index 5ada15be..e8adcc54 100644
--- a/R/fetchers.R
+++ b/R/fetchers.R
@@ -96,7 +96,11 @@ fetchzip <- function(archive_pkg, sri_hash = NULL) {
 #' @noRd
 remove_base <- function(list_imports) {
   imports_nobase <- gsub(
-    "(^base$)|(^compiler$)|(^datasets$)|(^grDevices$)|(^graphics$)|(^grid$)|(^methods$)|(^parallel$)|(^profile$)|(^splines$)|(^stats$)|(^stats4$)|(^tcltk$)|(^tools$)|(^translations$)|(^utils$)",
+    paste0(
+      "(^base$)|(^compiler$)|(^datasets$)|(^grDevices$)|(^graphics$)|(^grid$)|",
+      "(^methods$)|(^parallel$)|(^profile$)|(^splines$)|(^stats$)|",
+      "(^stats4$)|(^tcltk$)|(^tools$)|(^translations$)|(^utils$)"
+    ),
     NA_character_,
     list_imports
   )
@@ -226,7 +230,14 @@ fetchgits <- function(git_pkgs) {
   } else if (all(vapply(git_pkgs, is.list, logical(1)))) {
     paste(lapply(git_pkgs, fetchgit), collapse = "\n")
   } else {
-    stop("There is something wrong with the input. Make sure it is either a list of three elements 'package_name', 'repo_url' and 'commit' or a list of lists with these three elements")
+    stop(
+      paste0(
+        "There is something wrong with the input. ",
+        "Make sure it is either a list of three elements ",
+        "'package_name', 'repo_url' and 'commit', or ",
+        "a list of lists with these three elements"
+      )
+    )
   }
 }
 

From 276b3b6e4c5c4b523664680f3340a10f4bdc6d12 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Fri, 13 Sep 2024 15:36:00 +0200
Subject: [PATCH 16/62] exclude test-fetchers.R

---
 .pre-commit-config.yaml | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 49c31489..b626406c 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -7,21 +7,17 @@ repos:
     -   id: style-files
         args: [--style_pkg=styler, --style_fun=tidyverse_style, --cache-root=styler-perm]
         require_serial: true
-        exclude: > 
+    -   id: lintr
+        exclude: >
           (?x)^(
-          tests/testthat/in/.*|
+          tests/testthat/test-fetchers.R
           )$
-    -   id: lintr
     -   id: parsable-R
         exclude: > 
           (?x)^(
           tests/testthat/in/.*|
           )$
     -   id: no-browser-statement
-        exclude: > 
-          (?x)^(
-          tests/testthat/in/.*|
-          )$
 
 default_stages: ["commit"]
 

From 4aba03ff52ce8de8e319916bcffa315aafc84a91 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Fri, 13 Sep 2024 15:36:20 +0200
Subject: [PATCH 17/62] exclude lintr

---
 .lintr | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/.lintr b/.lintr
index 1375c994..a8ac14e9 100644
--- a/.lintr
+++ b/.lintr
@@ -1,5 +1,6 @@
 linters: linters_with_defaults(
     line_length_linter(100),
-    commented_code_linter = NULL
+    commented_code_linter = NULL,
+    object_usage_linter=NULL
   )
 encoding: "UTF-8"

From d393956a67868cc9120008c492a32daff1e4aac5 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Sat, 14 Sep 2024 13:22:33 +0200
Subject: [PATCH 18/62] update linter config, fix lints

---
 .lintr               |  3 ++-
 R/rix.R              | 39 ++++++++++++++++++++++++++++-----------
 R/with_nix_helpers.R | 13 ++++++++-----
 3 files changed, 38 insertions(+), 17 deletions(-)

diff --git a/.lintr b/.lintr
index a8ac14e9..286405bd 100644
--- a/.lintr
+++ b/.lintr
@@ -1,6 +1,7 @@
 linters: linters_with_defaults(
     line_length_linter(100),
     commented_code_linter = NULL,
-    object_usage_linter=NULL
+    object_usage_linter = NULL,
+    cyclocomp_linter = NULL
   )
 encoding: "UTF-8"
diff --git a/R/rix.R b/R/rix.R
index 9ab8ba1b..02b943db 100644
--- a/R/rix.R
+++ b/R/rix.R
@@ -19,7 +19,7 @@
 #' @param system_pkgs Vector of characters. List further software you wish to
 #'   install that are not R packages such as command line applications for
 #'   example. You can look for available software on the NixOS website
-#'   \url{https://search.nixos.org/packages?channel=unstable&from=0&size=50&sort=relevance&type=packages&query=}
+#'   \url{https://search.nixos.org/packages?channel=unstable&from=0&size=50&sort=relevance&type=packages&query=} # nolint
 #' @param git_pkgs List. A list of packages to install from Git. See details for
 #'   more information.
 #' @param local_r_pkgs List. A list of local packages to install. These packages
@@ -129,7 +129,8 @@
 #'   environment will be up-to-date on the date that the `default.nix` will be
 #'   generated, and then each subsequent call to `nix-build` will result in the
 #'   same environment. We highly recommend you read the vignette titled
-#'   "z - Advanced topic: Understanding the rPackages set release cycle and using bleeding edge packages".
+#'   "z - Advanced topic: Understanding the rPackages set release cycle and 
+#'   using bleeding edge packages".
 #' @export
 #' @examples
 #' \dontrun{
@@ -165,7 +166,10 @@ rix <- function(r_ver = "latest",
     choices = c("quiet", "simple", "verbose")
   )
 
-  if (!(message_type %in% c("simple", "quiet")) && r_ver %in% c("bleeding_edge", "frozen_edge")) {
+  if (
+    !(message_type %in% c("simple", "quiet")) &&
+     r_ver %in% c("bleeding_edge", "frozen_edge")
+  ) {
     warning(
       "You chose 'bleeding_edge' or 'frozen_edge' as the value for
 `r_ver`. Please read the vignette
@@ -174,8 +178,10 @@ before continuing."
     )
   }
 
-  if (message_type != "quiet" && r_ver %in% available_r() &&
-    r_ver != "latest" && r_ver <= "4.1.1") {
+  if (
+    message_type != "quiet" && r_ver %in% available_r() &&
+      r_ver != "latest" && r_ver <= "4.1.1"
+  ) {
     warning(
       "You are generating an expression for an older version of R.\n",
       "To use this environment, you should directly use `nix-shell` and not ",
@@ -195,8 +201,10 @@ before continuing."
 
   ide <- match.arg(ide, c("other", "code", "radian", "rstudio", "rserver"))
 
-  if (identical(ide, "rstudio") && is.null(r_pkgs) && is.null(git_pkgs) &&
-    is.null(local_r_pkgs)) {
+  if (
+    identical(ide, "rstudio") && is.null(r_pkgs) && is.null(git_pkgs) &&
+      is.null(local_r_pkgs)
+  ) {
     stop(
       paste0(
         "You chose 'rstudio' as the IDE, but didn't add any R packages",
@@ -213,7 +221,10 @@ before continuing."
     rserver = "rstudioServerWrapper"
   )
 
-  if (message_type != "quiet" && Sys.info()["sysname"] == "Darwin" && ide == "rstudio") {
+  if (
+    message_type != "quiet" && Sys.info()["sysname"] == "Darwin" &&
+      ide == "rstudio"
+  ) {
     warning(
       "Your detected operating system is macOS, and you chose
 'rstudio' as the IDE. Please note that 'rstudio' is not
@@ -231,8 +242,10 @@ for more details."
     project_path <- normalizePath(path = project_path)
   }
 
+  # nolint start: object_name_linter
   default.nix_path <- file.path(project_path, "default.nix")
   .Rprofile_path <- file.path(project_path, ".Rprofile")
+  # nolint end
 
   # Find url to use
   # In case of bleeding or frozen edge, the rstats-on-nix/nixpkgs
@@ -246,7 +259,9 @@ for more details."
   cran_pkgs <- get_rpkgs(r_pkgs, ide)
 
   # If there are R packages, passes the string "rpkgs" to buildInputs
-  flag_rpkgs <- if (is.null(cran_pkgs$rPackages) | cran_pkgs$rPackages == "") {
+  flag_rpkgs <- if (
+    is.null(cran_pkgs$rPackages) || cran_pkgs$rPackages == ""
+  ) {
     ""
   } else {
     "rpkgs"
@@ -260,7 +275,9 @@ for more details."
   }
 
   # If there are R packages from Git, passes the string "git_archive_pkgs" to buildInputs
-  flag_git_archive <- if (!is.null(cran_pkgs$archive_pkgs) | !is.null(git_pkgs)) {
+  flag_git_archive <- if (
+    !is.null(cran_pkgs$archive_pkgs) || !is.null(git_pkgs)
+  ) {
     "git_archive_pkgs"
   } else {
     ""
@@ -284,7 +301,7 @@ for more details."
     ""
   }
 
-  # Generate default.nix file
+  # Generate default.nix file # nolint next: object_name_linter
   default.nix <- paste(
     generate_header(
       nix_repo,
diff --git a/R/with_nix_helpers.R b/R/with_nix_helpers.R
index 4f8051fd..cc522994 100644
--- a/R/with_nix_helpers.R
+++ b/R/with_nix_helpers.R
@@ -47,7 +47,7 @@ serialize_lobjs <- function(lobjs, temp_dir) {
         # for unnamed arguments like `expr = function(x) print(x)`
         # x would be an empty symbol, see also ; i.e. arguments without
         # default expressions; i.e. tagged arguments with no value
-        # https://stackoverflow.com/questions/3892580/create-missing-objects-aka-empty-symbols-empty-objects-needed-for-f
+        # https://stackoverflow.com/questions/3892580/create-missing-objects-aka-empty-symbols-empty-objects-needed-for-f # nolint
         lobjs[[i]] <- as.symbol(names(lobjs)[i])
       }
       saveRDS(
@@ -280,8 +280,11 @@ classify_globals <- function(globals_expr, args_vec) {
     if (length(globs_empty) == 0L) {
       globs_empty <- NULL
     }
-    globs_other <- vec_envs_check[!names(vec_envs_check) %in%
-      names(c(globs_pkg, globs_globalenv, globs_empty, globs_base))]
+    globs_other <- vec_envs_check[
+      !names(vec_envs_check) %in% names(
+        c(globs_pkg, globs_globalenv, globs_empty, globs_base)
+      )
+    ]
     if (length(globs_other) == 0L) {
       globs_other <- NULL
     }
@@ -612,8 +615,8 @@ with_assign_vec_call <- function(vec) {
 #' @return representation of `expr` as character vector of length 1
 #' @author R Core Team
 #' @noRd
-deparse_chr1 <- function(expr, width.cutoff = 500L, collapse = " ", ...) {
-  paste(deparse(expr, width.cutoff, ...), collapse = collapse)
+deparse_chr1 <- function(expr, width_cutoff = 500L, collapse = " ", ...) {
+  paste(deparse(expr, width_cutoff, ...), collapse = collapse)
 }
 
 

From 07755af7099554536c1428b6f05a2395cfe55e5a Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
 <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Sat, 14 Sep 2024 11:23:06 +0000
Subject: [PATCH 19/62] [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci
---
 R/rix.R | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/R/rix.R b/R/rix.R
index 02b943db..81f09555 100644
--- a/R/rix.R
+++ b/R/rix.R
@@ -129,7 +129,7 @@
 #'   environment will be up-to-date on the date that the `default.nix` will be
 #'   generated, and then each subsequent call to `nix-build` will result in the
 #'   same environment. We highly recommend you read the vignette titled
-#'   "z - Advanced topic: Understanding the rPackages set release cycle and 
+#'   "z - Advanced topic: Understanding the rPackages set release cycle and
 #'   using bleeding edge packages".
 #' @export
 #' @examples
@@ -168,7 +168,7 @@ rix <- function(r_ver = "latest",
 
   if (
     !(message_type %in% c("simple", "quiet")) &&
-     r_ver %in% c("bleeding_edge", "frozen_edge")
+      r_ver %in% c("bleeding_edge", "frozen_edge")
   ) {
     warning(
       "You chose 'bleeding_edge' or 'frozen_edge' as the value for

From 1699a4bf0c09f23529bd25a928a337f7a751fe5b Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Sat, 14 Sep 2024 13:41:28 +0200
Subject: [PATCH 20/62] fix lints

---
 .../{format-code.yaml => lints-and-code-formatter.yaml}  | 2 +-
 R/detect_os.R                                            | 5 ++++-
 R/nix_build.R                                            | 9 ++++++---
 R/rix.R                                                  | 1 +
 R/with_nix_helpers.R                                     | 1 +
 5 files changed, 13 insertions(+), 5 deletions(-)
 rename .github/workflows/{format-code.yaml => lints-and-code-formatter.yaml} (90%)

diff --git a/.github/workflows/format-code.yaml b/.github/workflows/lints-and-code-formatter.yaml
similarity index 90%
rename from .github/workflows/format-code.yaml
rename to .github/workflows/lints-and-code-formatter.yaml
index e6d769d9..2e5ead16 100644
--- a/.github/workflows/format-code.yaml
+++ b/.github/workflows/lints-and-code-formatter.yaml
@@ -20,6 +20,6 @@ jobs:
         name: pre-commit-ci-lite
         if: always()
         with:
-          msg: apply code formatting
+          msg: check lints and apply code formatting
     env:
       GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
diff --git a/R/detect_os.R b/R/detect_os.R
index ca98e349..d6adcb32 100644
--- a/R/detect_os.R
+++ b/R/detect_os.R
@@ -21,7 +21,10 @@ detect_os <- function() {
 #' @noRd
 generate_locale_archive <- function(os) {
   if (os == "Linux" || os == "Darwin") {
-    'LOCALE_ARCHIVE = if pkgs.system == \"x86_64-linux\" then  \"${pkgs.glibcLocales}/lib/locale/locale-archive\" else \"\";'
+    paste0(
+      'LOCALE_ARCHIVE = if pkgs.system == \"x86_64-linux\" then ',
+      '\"${pkgs.glibcLocales}/lib/locale/locale-archive\" else \"\";'
+    )
   } else {
     stop("Operating System unsupported")
   }
diff --git a/R/nix_build.R b/R/nix_build.R
index 51ae9347..3c24c9e2 100644
--- a/R/nix_build.R
+++ b/R/nix_build.R
@@ -28,18 +28,19 @@ nix_build <- function(project_path = ".",
     choices = c("simple", "quiet", "verbose")
   )
   # if nix store is not PATH variable; e.g. on macOS (system's) RStudio
-  PATH <- set_nix_path()
+  PATH <- set_nix_path() # nolint: object_name_linter
   if (isTRUE(nzchar(Sys.getenv("NIX_STORE")))) {
     # for Nix R sessions, guarantee that the system's user library
     # (R_LIBS_USER) is not in the search path for packages => run-time purity
     current_libpaths <- .libPaths()
     # don't do this in covr test environment, because this sets R_LIBS_USER
     # to multiple paths
-    R_LIBS_USER <- Sys.getenv("R_LIBS_USER")
+    R_LIBS_USER <- Sys.getenv("R_LIBS_USER") # nolint: object_name_linter
     if (isFALSE(nzchar(Sys.getenv("R_COVR")))) {
       remove_r_libs_user()
     }
   } else {
+    # nolint next: object_name_linter
     LD_LIBRARY_PATH_default <- Sys.getenv("LD_LIBRARY_PATH")
     if (nzchar(LD_LIBRARY_PATH_default)) {
       # On some systems, like Ubuntu 22.04, we found that a preset
@@ -56,7 +57,7 @@ nix_build <- function(project_path = ".",
       fix_ld_library_path()
       cat(
         "* Current LD_LIBRARY_PATH in system R session is:",
-        LD_LIBRARY_PATH_default
+        LD_LIBRARY_PATH_default # nolint: object_name_linter
       )
       cat("\n", "Setting `LD_LIBRARY_PATH` to `''` during `nix_build()`")
     }
@@ -65,6 +66,7 @@ nix_build <- function(project_path = ".",
   nix_dir <- normalizePath(project_path)
   nix_file <- file.path(nix_dir, "default.nix")
 
+  # nolint start: line_length_linter
   stopifnot(
     "`project_path` must be character of length 1." =
       is.character(project_path) && length(project_path) == 1L,
@@ -73,6 +75,7 @@ nix_build <- function(project_path = ".",
     "`nix-build` not available. To install, we suggest you follow https://zero-to-nix.com/start/install ." =
       isTRUE(has_nix_build)
   )
+  # nolint end
 
   max_jobs <- getOption("rix.nix_build_max_jobs", default = 1L)
   stopifnot(
diff --git a/R/rix.R b/R/rix.R
index 02b943db..2b80ea16 100644
--- a/R/rix.R
+++ b/R/rix.R
@@ -321,6 +321,7 @@ for more details."
     collapse = "\n"
   )
 
+  # nolint next: object_name_linter
   default.nix <- readLines(textConnection(default.nix))
 
   if (print) {
diff --git a/R/with_nix_helpers.R b/R/with_nix_helpers.R
index cc522994..37c4e18f 100644
--- a/R/with_nix_helpers.R
+++ b/R/with_nix_helpers.R
@@ -73,6 +73,7 @@ serialize_args <- function(args, temp_dir) {
         # for unnamed arguments like `expr = function(x) print(x)`
         # x would be an empty symbol, see also ; i.e. arguments without
         # default expressions; i.e., tagged arguments with no value
+        # nolint next: line_length_linter
         # https://stackoverflow.com/questions/3892580/create-missing-objects-aka-empty-symbols-empty-objects-needed-for-f
         args[[i]] <- as.symbol(names(args)[i])
       }

From b55a0972e93f7c02805ed64fa66016bb64dd52b8 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Sat, 14 Sep 2024 13:54:12 +0200
Subject: [PATCH 21/62] fix more lints

---
 R/make_nixpkgs_url.R | 4 +++-
 R/nix_hash.R         | 9 +++++++--
 R/with_nix.R         | 6 +++++-
 3 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/R/make_nixpkgs_url.R b/R/make_nixpkgs_url.R
index a41dd6ee..9adeffcc 100644
--- a/R/make_nixpkgs_url.R
+++ b/R/make_nixpkgs_url.R
@@ -15,7 +15,9 @@ make_nixpkgs_url <- function(r_ver) {
   latest_commit <- get_latest(r_ver)
 
   list(
-    "url" = paste0("https://github.com/", github_repo, "archive/", latest_commit, ".tar.gz"),
+    "url" = paste0(
+      "https://github.com/", github_repo, "archive/", latest_commit, ".tar.gz"
+    ),
     "latest_commit" = latest_commit,
     "r_ver" = r_ver
   )
diff --git a/R/nix_hash.R b/R/nix_hash.R
index 2a1c33d1..68e7c0bc 100644
--- a/R/nix_hash.R
+++ b/R/nix_hash.R
@@ -104,16 +104,21 @@ nix_sri_hash <- function(path) {
 
   # not needed for Nix R sessions, workaround on Debian and Debian-based
   # systems with nix installed
+  # nolint start: object_name_linter
   LD_LIBRARY_PATH_default <- Sys.getenv("LD_LIBRARY_PATH")
   needs_ld_fix <- isFALSE(nzchar(Sys.getenv("NIX_STORE"))) &&
     nzchar(LD_LIBRARY_PATH_default)
+  # nolint end
 
   if (isTRUE(needs_ld_fix)) {
     # On Debian and Debian-based systems, like Ubuntu 22.04, we found that a
     # preset `LD_LIBRARY_PATH` environment variable in the system's R session
     # leads to errors like
-    # nix-hash: /usr/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.38' not found (required by nix-hash)
-    # nix-hash: /usr/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.38' not found (required by /nix/store/4z754a0vzl98asv0pa95i5d9szw5jqbs-lowdown-1.0.2-lib/lib/liblowdown.so.3)
+    # nix-hash: /usr/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.38'
+    # not found (required by nix-hash)
+    # nix-hash: /usr/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.38'
+    # not found (required by # nolint next: line_length_linter
+    # /nix/store/4z754a0vzl98asv0pa95i5d9szw5jqbs-lowdown-1.0.2-lib/lib/liblowdown.so.3)
     # etc...
     # for both `nix-hash`; it occurs via
     # `sys::exec_internal`, `base::system()` or `base::system2()` from R.
diff --git a/R/with_nix.R b/R/with_nix.R
index c6a93cd2..7b8ead27 100644
--- a/R/with_nix.R
+++ b/R/with_nix.R
@@ -134,6 +134,7 @@ with_nix <- function(expr,
                      project_path = ".",
                      message_type = c("simple", "quiet", "verbose")) {
   nix_file <- file.path(project_path, "default.nix")
+  # nolint start: line_length_linter
   stopifnot(
     "`project_path` must be character of length 1." =
       is.character(project_path) && length(project_path) == 1L,
@@ -143,6 +144,7 @@ with_nix <- function(expr,
     "`expr` needs to be a call or function for `program = R`, and character of length 1 for `program = shell`" =
       is.function(expr) || is.call(expr) || (is.character(expr) && length(expr) == 1L)
   )
+  # nolint end
 
   program <- match.arg(program, choices = c("R", "shell"))
   message_type <- match.arg(message_type,
@@ -170,11 +172,12 @@ with_nix <- function(expr,
     current_libpaths <- .libPaths()
     # don't do this in covr test environment, because this sets R_LIBS_USER
     # to multiple paths
-    R_LIBS_USER <- Sys.getenv("R_LIBS_USER")
+    R_LIBS_USER <- Sys.getenv("R_LIBS_USER") # nolint: object_name_linter
     if (isFALSE(nzchar(Sys.getenv("R_COVR")))) {
       remove_r_libs_user()
     }
   } else {
+    # lolint start: object_name_linter
     LD_LIBRARY_PATH_default <- Sys.getenv("LD_LIBRARY_PATH")
     if (nzchar(LD_LIBRARY_PATH_default)) {
       # On some systems, like Ubuntu 22.04, we found that a preset
@@ -195,6 +198,7 @@ with_nix <- function(expr,
       )
       cat("\n", "Setting `LD_LIBRARY_PATH` to `''` during `nix_build()`")
     }
+    # nolint end
   }
 
   has_nix_shell <- nix_shell_available() # TRUE if yes, FALSE if no

From ee536cca237901e4f05965159710d4dbee4f9d02 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Sat, 14 Sep 2024 13:58:33 +0200
Subject: [PATCH 22/62] fix lint cmd

---
 R/with_nix.R | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/R/with_nix.R b/R/with_nix.R
index 7b8ead27..6f3f72f5 100644
--- a/R/with_nix.R
+++ b/R/with_nix.R
@@ -177,7 +177,7 @@ with_nix <- function(expr,
       remove_r_libs_user()
     }
   } else {
-    # lolint start: object_name_linter
+    # nolint start: object_name_linter
     LD_LIBRARY_PATH_default <- Sys.getenv("LD_LIBRARY_PATH")
     if (nzchar(LD_LIBRARY_PATH_default)) {
       # On some systems, like Ubuntu 22.04, we found that a preset

From 24d802fe99123256ec78319dcf1bbc661c7b0cad Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Sat, 14 Sep 2024 14:02:43 +0200
Subject: [PATCH 23/62] lint

---
 data-raw/DATASET.R | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/data-raw/DATASET.R b/data-raw/DATASET.R
index 0a3589ea..78f79c0e 100644
--- a/data-raw/DATASET.R
+++ b/data-raw/DATASET.R
@@ -1,6 +1,5 @@
 ## code to prepare `DATASET` dataset goes here
 
-
 library(rix)
 
 # This script is only needed for the developers of `{rix}`.
@@ -16,8 +15,11 @@ library(rix)
 # library(rvest)
 # library(dplyr)
 # library(janitor)
-#
-# r_nix_revs <- read_html("https://lazamar.co.uk/nix-versions/?channel=nixpkgs-unstable&package=r") |>
+
+# r_nix_revs <-
+#  read_html(
+#    "https://lazamar.co.uk/nix-versions/?channel=nixpkgs-unstable&package=r"
+#  ) |>
 #  html_element("table") |>
 #  html_table() |>
 #  clean_names() |>

From 1d7ccb97bfe7cda6fd65d9b1b7bc3dfe687885e3 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Sat, 14 Sep 2024 14:24:17 +0200
Subject: [PATCH 24/62] again fix remaing lint errors

---
 R/make_nixpkgs_url.R |  3 ++-
 R/rix_helpers.R      | 50 ++++++++++++++++++++++++++++------------
 R/rix_init.R         | 54 ++++++++++++++++++++++++++++++++------------
 3 files changed, 76 insertions(+), 31 deletions(-)

diff --git a/R/make_nixpkgs_url.R b/R/make_nixpkgs_url.R
index 9adeffcc..9bba1887 100644
--- a/R/make_nixpkgs_url.R
+++ b/R/make_nixpkgs_url.R
@@ -1,5 +1,6 @@
 #' make_nixpkgs_url Find the right Nix revision
-#' @param r_version Character. R version to look for, for example, "4.2.0". If a nixpkgs revision is provided instead, this gets returned.
+#' @param r_version Character. R version to look for, for example, "4.2.0". If a
+#' nixpkgs revision is provided instead, this gets returned.
 #' @return A character. The url to use
 #'
 #' @examples
diff --git a/R/rix_helpers.R b/R/rix_helpers.R
index fc79a3a3..52c5b39e 100644
--- a/R/rix_helpers.R
+++ b/R/rix_helpers.R
@@ -1,6 +1,9 @@
-#' generate_header Internal function used to generate the header of the `default.nix` file.
-#' @param nix_repo Character. nixpkgs reop to use (upstream or rstats-on-nix fork) with latest commit hash.
-#' @param r_version Character. R version to look for, for example, "4.2.0". If a nixpkgs revision is provided instead, this gets returned.
+#' generate_header Internal function used to generate the header of the
+#' `default.nix` file.
+#' @param nix_repo Character. nixpkgs reop to use (upstream or rstats-on-nix
+#' fork) with latest commit hash.
+#' @param r_version Character. R version to look for, for example, "4.2.0". If a
+#' nixpkgs revision is provided instead, this gets returned.
 #' @param rix_call Character, call to rix().
 #' @noRd
 generate_header <- function(nix_repo,
@@ -70,9 +73,11 @@ let
   }
 }
 
-#' generate_rix_call Internal function used to generate the call to `rix()` as shown in `default.nix`
+#' generate_rix_call Internal function used to generate the call to `rix()` as
+#' shown in `default.nix`
 #' @param rix_call Character, call to rix().
-#' @param nix_repo Character. nixpkgs reop to use (upstream or rstats-on-nix fork) with latest commit hash.
+#' @param nix_repo Character. nixpkgs reop to use (upstream or rstats-on-nix
+#' fork) with latest commit hash.
 #' @noRd
 generate_rix_call <- function(rix_call, nix_repo) {
   if (grepl("NixOS", nix_repo$url)) {
@@ -108,9 +113,11 @@ get_rpkgs <- function(r_pkgs, ide) {
     r_pkgs
   }
 
+  # nolint start: object_name_linter
   rPackages <- paste(c("", r_pkgs), collapse = "\n      ")
 
   rPackages <- gsub("\\.", "_", rPackages)
+  # nolint end
 
   list(
     "rPackages" = rPackages,
@@ -118,10 +125,12 @@ get_rpkgs <- function(r_pkgs, ide) {
   )
 }
 
-#' generate_rpkgs Internal function that generates the string containing the correct Nix expression to get R packages.
+#' generate_rpkgs Internal function that generates the string containing the
+#' correct Nix expression to get R packages.
 #' @param rPackages Character, list of R packages to install.
 #' @param flag_rpkgs Character, are there any R packages at all?
 #' @noRd
+#' # nolint start: object_name_linter
 generate_rpkgs <- function(rPackages, flag_rpkgs) {
   if (flag_rpkgs == "") {
     NULL
@@ -136,8 +145,10 @@ generate_rpkgs <- function(rPackages, flag_rpkgs) {
     )
   }
 }
+# nolint end: object_name_linter
 
-#' generate_local_r_pkgs Internal function that generates the string containing the correct Nix expression for installing local packages
+#' generate_local_r_pkgs Internal function that generates the string containing
+#' the correct Nix expression for installing local packages
 #' @param local_r_pkgs Character, list of local R packages to install.
 #' @param flag_local_r_pkgs Character, are there any local R packages at all?
 #' @noRd
@@ -156,7 +167,8 @@ generate_local_r_pkgs <- function(local_r_pkgs, flag_local_r_pkgs) {
   }
 }
 
-#' generate_tex_pkgs Internal function that generates the string containing the correct Nix expression to get LaTeX packages.
+#' generate_tex_pkgs Internal function that generates the string containing the
+#' correct Nix expression to get LaTeX packages.
 #' @param tex_pkgs Character, list of LaTeX packages to install.
 #' @noRd
 generate_tex_pkgs <- function(tex_pkgs) {
@@ -176,7 +188,8 @@ generate_tex_pkgs <- function(tex_pkgs) {
   }
 }
 
-#' generate_system_pkgs Internal function that formats the system package names correctly for Nix.
+#' generate_system_pkgs Internal function that formats the system package names
+#' correctly for Nix.
 #' @param system_pkgs Character, list of LaTeX packages to install.
 #' @param r_pkgs Character, list of LaTeX packages to install.
 #' @noRd
@@ -184,7 +197,8 @@ get_system_pkgs <- function(system_pkgs, r_pkgs) {
   # We always need these packages
   system_pkgs <- c(system_pkgs, "R", "glibcLocales", "nix")
 
-  # If the user wants the R {quarto} package, then the quarto software needs to be installed
+  # If the user wants the R {quarto} package, then the quarto software needs to
+  # be installed
   system_pkgs <- if (any(grepl("quarto", r_pkgs))) {
     unique(c(system_pkgs, "quarto"))
   } else {
@@ -194,7 +208,8 @@ get_system_pkgs <- function(system_pkgs, r_pkgs) {
 }
 
 
-#' generate_system_pkgs Internal function that generates the string containing the correct Nix expression to get system packages.
+#' generate_system_pkgs Internal function that generates the string containing
+#' the correct Nix expression to get system packages.
 #' @param system_pkgs Character, list of LaTeX packages to install.
 #' @param r_pkgs Character, list of LaTeX packages to install.
 #' @noRd
@@ -210,12 +225,16 @@ generate_system_pkgs <- function(system_pkgs, r_pkgs) {
 }
 
 
-#' generate_git_archived_pkgs Internal function that generates the string containing the correct Nix expression to get system packages.
+#' generate_git_archived_pkgs Internal function that generates the string
+#' containing the correct Nix expression to get system packages.
 #' @param git_pkgs Character, list of R packages to install from Github.
-#' @param archive_pkgs Character, list of R packages to install from the CRAN archives.
+#' @param archive_pkgs Character, list of R packages to install from the CRAN
+#' archives.
 #' @param flag_git_archive Character, are there R packages from Github at all?
 #' @noRd
-generate_git_archived_pkgs <- function(git_pkgs, archive_pkgs, flag_git_archive) {
+generate_git_archived_pkgs <- function(git_pkgs,
+                                       archive_pkgs,
+                                       flag_git_archive) {
   if (flag_git_archive == "") {
     NULL
   } else {
@@ -225,7 +244,8 @@ generate_git_archived_pkgs <- function(git_pkgs, archive_pkgs, flag_git_archive)
 }
 
 
-#' generate_locale_variables Internal function that generates the string containing the correct Nix expression to set locales.
+#' generate_locale_variables Internal function that generates the string
+#' containing the correct Nix expression to set locales.
 #' @noRd
 generate_locale_variables <- function() {
   locale_defaults <- list(
diff --git a/R/rix_init.R b/R/rix_init.R
index 97bee94a..9d3af2a5 100644
--- a/R/rix_init.R
+++ b/R/rix_init.R
@@ -1,13 +1,13 @@
 #' Initiate and maintain an isolated, project-specific, and runtime-pure R
 #' setup via Nix.
 #'
-#' Creates an isolated project folder for a Nix-R configuration. `rix::rix_init()`
-#' also adds, appends, or updates with or without backup a custom `.Rprofile`
-#' file with code that initializes a startup R environment without system's user
-#' libraries within a Nix software environment. Instead, it restricts search
-#' paths to load R packages exclusively from the Nix store. Additionally, it
-#' makes Nix utilities like `nix-shell` available to run system commands from
-#' the system's RStudio R session, for both Linux and macOS.
+#' Creates an isolated project folder for a Nix-R configuration.
+#' `rix::rix_init()` also adds, appends, or updates with or without backup a
+#' custom `.Rprofile` file with code that initializes a startup R environment
+#' without system's user libraries within a Nix software environment. Instead,
+#' it restricts search paths to load R packages exclusively from the Nix store.
+#' Additionally, it makes Nix utilities like `nix-shell` available to run system
+#' commands from the system's RStudio R session, for both Linux and macOS.
 #'
 #' **Enhancement of computational reproducibility for Nix-R environments:**
 #'
@@ -75,12 +75,14 @@
 #'   does exist; `"append"` appends the existing file with code that is tailored
 #'   to an isolated Nix-R project setup.
 #' @param message_type Character. Message type, defaults to `"simple"`, which
-#'   gives minimal but sufficient feedback. Other values are currently
-#'   `"quiet`, which writes `.Rprofile` without message, and `"verbose"`,
-#'   which displays the mechanisms implemented to achieve fully controlled R project environments in Nix.
+#'   gives minimal but sufficient feedback. Other values are currently `"quiet`,
+#'   which writes `.Rprofile` without message, and `"verbose"`, which displays
+#'   the mechanisms implemented to achieve fully controlled R project
+#'   environments in Nix.
 #' @export
 #' @seealso [with_nix()]
-#' @return Nothing, this function only has the side-effect of writing a file called ".Rprofile" to the specified path.
+#' @return Nothing, this function only has the side-effect of writing a file
+#' called ".Rprofile" to the specified path.
 #' @examples
 #' \dontrun{
 #' # create an isolated, runtime-pure R setup via Nix
@@ -272,6 +274,7 @@ message_rprofile <- function(action_string = "Added",
 #' @return Character vector that lists `PATH` entries after modification, which
 #' are separated by `":"`.
 #' @noRd
+# nolint start: object_name_linter
 set_message_session_PATH <- function(message_type =
                                        c("simple", "quiet", "verbose")) {
   message_type <- match.arg(message_type,
@@ -293,6 +296,7 @@ set_message_session_PATH <- function(message_type =
     cat("\n\n* Updated `PATH` variable is:\n\n", PATH)
   }
 }
+# nolint end: object_name_linter
 
 
 #' Report whether the current R session is running in Nix and RStudio, or not.
@@ -392,6 +396,7 @@ set_nix_path <- function() {
 #' @return language object with parsed expression
 #' @noRd
 nix_rprofile <- function() {
+  # nolint start: object_name_linter
   quote({
     is_rstudio <- Sys.getenv("RSTUDIO") == "1"
     is_nix_r <- nzchar(Sys.getenv("NIX_STORE"))
@@ -417,19 +422,37 @@ nix_rprofile <- function() {
 
     if (isTRUE(is_nix_r)) {
       install.packages <- function(...) {
-        stop("You are currently in an R session running from Nix.\nDon't install packages using install.packages(),\nadd them to the default.nix file instead.")
+        stop(
+          "You are currently in an R session running from Nix.\n",
+          "Don't install packages using install.packages(),\nadd them to ",
+          "the default.nix file instead."
+        )
       }
 
       update.packages <- function(...) {
-        stop("You are currently in an R session running from Nix.\nDon't update packages using update.packages(),\ngenerate a new default.nix with a more recent version of R. If you need bleeding edge packages, read the 'Understanding the rPackages set release cycle and using bleeding edge packages' vignette.")
+        stop(
+          "You are currently in an R session running from Nix.\n",
+          "Don't update packages using update.packages(),\n",
+          "generate a new default.nix with a more recent version of R. ",
+          "If you need bleeding edge packages, read the", 
+          "'Understanding the rPackages set release cycle and using ",
+          "bleeding edge packages' vignette."
+        )
       }
 
       remove.packages <- function(...) {
-        stop("You are currently in an R session running from Nix.\nDon't remove packages using remove.packages(),\ndelete them from the default.nix file instead.")
+        stop(
+          "You are currently in an R session running from Nix.\n",
+          "Don't remove packages using `remove.packages()``,\ndelete them ",
+          "from the default.nix file instead.")
       }
       current_paths <- .libPaths()
       userlib_paths <- Sys.getenv("R_LIBS_USER")
-      user_dir <- grep(paste(userlib_paths, collapse = "|"), current_paths, fixed = TRUE)
+      user_dir <- grep(
+        paste(userlib_paths, collapse = "|"),
+        current_paths,
+        fixed = TRUE
+      )
       new_paths <- current_paths[-user_dir]
       # sets new library path without user library, making nix-R pure at
       # run-time
@@ -439,4 +462,5 @@ nix_rprofile <- function() {
 
     rm(is_rstudio, is_nix_r)
   })
+  # nolint end: object_name
 }

From a16202d34ee8971041cf653dcb3f323df6e4a0b6 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
 <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Sat, 14 Sep 2024 12:25:01 +0000
Subject: [PATCH 25/62] [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci
---
 R/rix_init.R | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/R/rix_init.R b/R/rix_init.R
index 9d3af2a5..aff4d49a 100644
--- a/R/rix_init.R
+++ b/R/rix_init.R
@@ -434,7 +434,7 @@ nix_rprofile <- function() {
           "You are currently in an R session running from Nix.\n",
           "Don't update packages using update.packages(),\n",
           "generate a new default.nix with a more recent version of R. ",
-          "If you need bleeding edge packages, read the", 
+          "If you need bleeding edge packages, read the",
           "'Understanding the rPackages set release cycle and using ",
           "bleeding edge packages' vignette."
         )
@@ -444,7 +444,8 @@ nix_rprofile <- function() {
         stop(
           "You are currently in an R session running from Nix.\n",
           "Don't remove packages using `remove.packages()``,\ndelete them ",
-          "from the default.nix file instead.")
+          "from the default.nix file instead."
+        )
       }
       current_paths <- .libPaths()
       userlib_paths <- Sys.getenv("R_LIBS_USER")

From f3bcb1d0d1c148df391ec5e439228b178288e130 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Sat, 14 Sep 2024 14:30:06 +0200
Subject: [PATCH 26/62] fix lints

---
 R/rix_helpers.R                                             | 6 ++++--
 .../c-using-rix-to-build-project-specific-environments.Rmd  | 4 +---
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/R/rix_helpers.R b/R/rix_helpers.R
index 52c5b39e..f402f730 100644
--- a/R/rix_helpers.R
+++ b/R/rix_helpers.R
@@ -283,7 +283,8 @@ generate_locale_variables <- function() {
 }
 
 
-#' generate_wrapped_pkgs Internal function that generates the string containing the correct Nix expression to get wrapped packages.
+#' generate_wrapped_pkgs Internal function that generates the string containing
+#' the correct Nix expression to get wrapped packages.
 #' @param ide Character, defaults to "other". If you wish to use RStudio to work
 #'   interactively use "rstudio" or "rserver" for the server version. Use "code"
 #'   for Visual Studio Code. You can also use "radian", an interactive REPL. For
@@ -319,7 +320,8 @@ generate_wrapped_pkgs <- function(ide,
 }
 
 
-#' generate_wrapped_pkgs Internal function that generates the string containing the correct Nix expression to get wrapped packages.
+#' generate_wrapped_pkgs Internal function that generates the string containing
+#' the correct Nix expression to get wrapped packages.
 #' @param flag_git_archive Character, are there R packages from Github at all?
 #' @param flag_rpkgs Character, are there any R packages at all?
 #' @param flag_tex_pkgs Character, are there any LaTex packages at all?
diff --git a/vignettes/c-using-rix-to-build-project-specific-environments.Rmd b/vignettes/c-using-rix-to-build-project-specific-environments.Rmd
index c39b1b28..066707b3 100644
--- a/vignettes/c-using-rix-to-build-project-specific-environments.Rmd
+++ b/vignettes/c-using-rix-to-build-project-specific-environments.Rmd
@@ -18,8 +18,6 @@ knitr::opts_chunk$set(
 library(rix)
 ```
 
-<!-- WARNING - This vignette is generated by {fusen} from dev/c-building_envs_with_rix.Rmd: do not edit by hand -->
-
 ## Project-specific Nix environments
 
 Now that you have the required software installed, it’s to time learn more about
@@ -50,7 +48,7 @@ file. You need to provide the following inputs to `rix()`:
 Run the following command to generate the right `default.nix` file:
 
 
-```{r, eval = F}
+```{r, eval = FALSE}
 path_default_nix <- tempdir()
 
 rix(

From e83d9cc75134ca942aee237c37093f100136a1ef Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Sat, 14 Sep 2024 14:32:46 +0200
Subject: [PATCH 27/62] exclude from lintr

---
 .pre-commit-config.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index b626406c..9180fda5 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -11,6 +11,7 @@ repos:
         exclude: >
           (?x)^(
           tests/testthat/test-fetchers.R
+          vignettes/c-using-rix-to-build-project-specific-environments.Rmd
           )$
     -   id: parsable-R
         exclude: > 

From e1a05c7e10b72e28b15f979a0fda090601edc4e3 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Sat, 14 Sep 2024 14:34:45 +0200
Subject: [PATCH 28/62] fix rhub nix runner to use current branch

---
 .github/workflows/run_rhub.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/run_rhub.yaml b/.github/workflows/run_rhub.yaml
index bbcf973f..997bcdb7 100644
--- a/.github/workflows/run_rhub.yaml
+++ b/.github/workflows/run_rhub.yaml
@@ -30,4 +30,4 @@ jobs:
           authToken: '${{ secrets.CACHIX_AUTH }}'
 
       - name: Run checks
-        run: nix-shell --run "Rscript -e \"rhub::rhub_check(platforms = c('linux','macos','macos-arm64','windows','ubuntu-next','ubuntu-release'), branch = 'main')\""
+        run: nix-shell --run "Rscript -e \"rhub::rhub_check(platforms = c('linux','macos','macos-arm64','windows','ubuntu-next','ubuntu-release'))\""

From d3eb26fbb1f17d4d204317accc98c7f1a57ddd21 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Sat, 14 Sep 2024 14:43:19 +0200
Subject: [PATCH 29/62] exclude vignettes

---
 .pre-commit-config.yaml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 9180fda5..3ee27346 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -10,8 +10,8 @@ repos:
     -   id: lintr
         exclude: >
           (?x)^(
-          tests/testthat/test-fetchers.R
-          vignettes/c-using-rix-to-build-project-specific-environments.Rmd
+          tests/testthat/test-fetchers.\.R|
+          vignettes/.*
           )$
     -   id: parsable-R
         exclude: > 

From 5d937269444358d295dbae520b50a598559e9e6c Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Sat, 14 Sep 2024 14:50:18 +0200
Subject: [PATCH 30/62] more fixes

---
 .pre-commit-config.yaml |  2 +-
 R/get_latest.R          | 18 ++++++++++++++----
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 3ee27346..24f3e1a5 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -10,7 +10,7 @@ repos:
     -   id: lintr
         exclude: >
           (?x)^(
-          tests/testthat/test-fetchers.\.R|
+          tests/testthat/test-fetchers\.R|
           vignettes/.*
           )$
     -   id: parsable-R
diff --git a/R/get_latest.R b/R/get_latest.R
index e396978d..2edb2c49 100644
--- a/R/get_latest.R
+++ b/R/get_latest.R
@@ -1,5 +1,6 @@
 #' Get the latest R version and packages
-#' @param r_version Character. R version to look for, for example, "4.2.0". If a nixpkgs revision is provided instead, this gets returned.
+#' @param r_version Character. R version to look for, for example, "4.2.0". If a
+#' nixpkgs revision is provided instead, this gets returned.
 #' @return A character. The commit hash of the latest nixpkgs-unstable revision
 #' @importFrom curl new_handle curl_fetch_memory handle_reset
 #' @importFrom jsonlite fromJSON
@@ -18,7 +19,13 @@ get_latest <- function(r_version) {
   } else if (
     !(r_version %in% c("bleeding_edge", "frozen_edge", available_r()))
   ) {
-    stop("The provided R version is likely wrong.\nPlease check that you provided a correct R version.\nYou can list available versions using `available_r()`.\nYou can also directly provide a commit, but you need to make sure it points to the right repo used by `rix()`.\nYou can also use 'bleeding_edge' and 'frozen_edge'.")
+    stop(
+      "The provided R version is likely wrong.\nPlease check that you ",
+      "provided a correct R version.\nYou can list available versions using ",
+      "`available_r()`.\nYou can also directly provide a commit, but you need ",
+      "to make sure it points to the right repo used by `rix()`.\nYou can ",
+      "also use 'bleeding_edge' and 'frozen_edge'."
+    )
   } else if (!is_online) {
     stop("ERROR! You don't seem to be connected to the internet.")
   } else if (r_version == "bleeding_edge") {
@@ -33,11 +40,14 @@ get_latest <- function(r_version) {
 #' @noRd
 get_right_commit <- function(r_version) {
   if (r_version == "frozen_edge") {
+    # nolint next: line_length_linter
     api_url <- "https://api.github.com/repos/rstats-on-nix/nixpkgs/commits?sha=r-daily"
-  } else if (r_version %in% Filter(function(x) `!=`(x, "latest"), available_r())) { # all but latest
-
+  } else if (
+    r_version %in% Filter(function(x) `!=`(x, "latest"), available_r())
+  ) { # all but latest
     return(sysdata$revision[sysdata$version == r_version])
   } else {
+    # nolint next: line_length_linter
     api_url <- "https://api.github.com/repos/NixOS/nixpkgs/commits?sha=nixpkgs-unstable"
   }
 

From e2aedaabe96753a4f5fb04f171651de268e237e5 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Sat, 14 Sep 2024 15:23:08 +0200
Subject: [PATCH 31/62] try fix rhub gh url

---
 .github/workflows/run_rhub.yaml | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/run_rhub.yaml b/.github/workflows/run_rhub.yaml
index 997bcdb7..48d7606a 100644
--- a/.github/workflows/run_rhub.yaml
+++ b/.github/workflows/run_rhub.yaml
@@ -28,6 +28,9 @@ jobs:
           # signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}'
           # If you chose API tokens for write access OR if you have a private cache
           authToken: '${{ secrets.CACHIX_AUTH }}'
-
+      
       - name: Run checks
-        run: nix-shell --run "Rscript -e \"rhub::rhub_check(platforms = c('linux','macos','macos-arm64','windows','ubuntu-next','ubuntu-release'))\""
+        run: |
+          git remote add origin https://github.com/ropensci/rix
+          nix-shell --run "Rscript -e \"rhub::rhub_check(platforms = c('linux','macos','macos-arm64','windows','ubuntu-next','ubuntu-release'))\""
+

From 39a39f8a3adcf1bdf7a2192d64af8584a1e48771 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Sat, 14 Sep 2024 15:24:14 +0200
Subject: [PATCH 32/62] remote already there

---
 .github/workflows/run_rhub.yaml | 1 -
 1 file changed, 1 deletion(-)

diff --git a/.github/workflows/run_rhub.yaml b/.github/workflows/run_rhub.yaml
index 48d7606a..532edb18 100644
--- a/.github/workflows/run_rhub.yaml
+++ b/.github/workflows/run_rhub.yaml
@@ -31,6 +31,5 @@ jobs:
       
       - name: Run checks
         run: |
-          git remote add origin https://github.com/ropensci/rix
           nix-shell --run "Rscript -e \"rhub::rhub_check(platforms = c('linux','macos','macos-arm64','windows','ubuntu-next','ubuntu-release'))\""
 

From c10c2bdfe009f9b106f7532713bd31733aaec9de Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
 <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 16 Sep 2024 13:33:16 +0000
Subject: [PATCH 33/62] [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci
---
 R/rix_helpers.R | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/R/rix_helpers.R b/R/rix_helpers.R
index 00f639e5..0d0409dc 100644
--- a/R/rix_helpers.R
+++ b/R/rix_helpers.R
@@ -114,7 +114,7 @@ get_rpkgs <- function(r_pkgs, ide) {
   }
 
   r_pkgs <- sort(r_pkgs)
-  
+
   # nolint start: object_name_linter
   rPackages <- paste(c("", r_pkgs), collapse = "\n      ")
 

From b5fe46d722669d59c3859c4325351c6d7dc6df4c Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Mon, 16 Sep 2024 19:35:06 +0200
Subject: [PATCH 34/62] add docopt for precommit nix R hooks

---
 .../workflows/lints-and-code-formatter.yaml   | 10 +++++++
 create_dev_env.R                              |  2 +-
 default.nix                                   | 26 ++++++++++---------
 3 files changed, 25 insertions(+), 13 deletions(-)

diff --git a/.github/workflows/lints-and-code-formatter.yaml b/.github/workflows/lints-and-code-formatter.yaml
index 2e5ead16..963668f2 100644
--- a/.github/workflows/lints-and-code-formatter.yaml
+++ b/.github/workflows/lints-and-code-formatter.yaml
@@ -12,6 +12,16 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
+      - name: Install Nix
+        uses: DeterminateSystems/nix-installer-action@main
+
+      - uses: cachix/cachix-action@v15
+        with:
+          name: rstats-on-nix
+          # If you chose signing key for write access
+          # signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}'
+          # If you chose API tokens for write access OR if you have a private cache
+          authToken: '${{ secrets.CACHIX_AUTH }}'
       - uses: actions/setup-python@v4
         with:
           python-version: 3.x
diff --git a/create_dev_env.R b/create_dev_env.R
index 07bae46c..c1c9bed9 100644
--- a/create_dev_env.R
+++ b/create_dev_env.R
@@ -5,7 +5,7 @@ rix(
   r_pkgs = c(
     "devtools", "diffviewer", "fledge", "lintr", "styler",
     "codetools", "jsonlite", "httr", "sys", "testthat", "knitr",
-    "rmarkdown", "rhub"
+    "rmarkdown", "rhub", "docopt"
   ),
   system_pkgs = c("R", "glibcLocalesUtf8", "pandoc", "nix"),
   tex_pkgs = "scheme-small",
diff --git a/default.nix b/default.nix
index af0a64a8..0ab6a43b 100644
--- a/default.nix
+++ b/default.nix
@@ -1,4 +1,4 @@
-# This file was generated by the {rix} R package v0.7.1 on 2024-06-28
+# This file was generated by the {rix} R package v0.11.0 on 2024-09-16
 # with following call:
 # >rix(r_ver = "bleeding_edge",
 #  > r_pkgs = c("devtools",
@@ -13,7 +13,8 @@
 #  > "testthat",
 #  > "knitr",
 #  > "rmarkdown",
-#  > "precommit"),
+#  > "rhub",
+#  > "docopt"),
 #  > system_pkgs = c("R",
 #  > "glibcLocalesUtf8",
 #  > "pandoc",
@@ -34,19 +35,20 @@ let
  
   rpkgs = builtins.attrValues {
     inherit (pkgs.rPackages) 
+      codetools
       devtools
       diffviewer
+      docopt
       fledge
-      lintr
-      styler
-      codetools
-      jsonlite
       httr
-      sys
-      testthat
+      jsonlite
       knitr
+      lintr
+      rhub
       rmarkdown
-      rhub;
+      styler
+      sys
+      testthat;
   };
   
   tex = (pkgs.texlive.combine {
@@ -56,11 +58,11 @@ let
   
   system_packages = builtins.attrValues {
     inherit (pkgs) 
-      R
+      glibcLocales
       glibcLocalesUtf8
-      pandoc
       nix
-      glibcLocales;
+      pandoc
+      R;
   };
   
 in

From a421aba19d000816b4a9287ee9e04f850d3a463b Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Mon, 16 Sep 2024 19:35:47 +0200
Subject: [PATCH 35/62] use forked action

---
 .pre-commit-config.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 24f3e1a5..10a1ecd5 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,7 +1,7 @@
 # All available hooks: https://pre-commit.com/hooks.html
 # R specific hooks: https://github.com/lorenzwalthert/precommit
 repos:
--   repo: https://github.com/lorenzwalthert/precommit
+-   repo: https://github.com/philipp-baumann/precommit-r-nix
     rev: v0.4.3
     hooks: 
     -   id: style-files

From 9eefc15338bc93c2270ca8c6fa0bbf9b7423b1b4 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Mon, 16 Sep 2024 19:44:21 +0200
Subject: [PATCH 36/62] use fixed fork revision

---
 .pre-commit-config.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 10a1ecd5..80dbacd6 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -2,7 +2,7 @@
 # R specific hooks: https://github.com/lorenzwalthert/precommit
 repos:
 -   repo: https://github.com/philipp-baumann/precommit-r-nix
-    rev: v0.4.3
+    rev: 9c54f8c09f17e305db1338cb8159aac9b58f86a3
     hooks: 
     -   id: style-files
         args: [--style_pkg=styler, --style_fun=tidyverse_style, --cache-root=styler-perm]

From ad1211a8169b4a8c5a679d9263187d8bd27de2d7 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Mon, 16 Sep 2024 19:48:51 +0200
Subject: [PATCH 37/62] test nix styler

---
 R/nix_build.R | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/R/nix_build.R b/R/nix_build.R
index 3c24c9e2..8edcaf89 100644
--- a/R/nix_build.R
+++ b/R/nix_build.R
@@ -24,7 +24,7 @@
 #' }
 nix_build <- function(project_path = ".",
                       message_type = c("simple", "quiet", "verbose")) {
-  message_type <- match.arg(message_type,
+  message_type <-  match.arg(message_type,
     choices = c("simple", "quiet", "verbose")
   )
   # if nix store is not PATH variable; e.g. on macOS (system's) RStudio

From 049e68ab8472d0cc86adc1392ef448854788fe07 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
 <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 16 Sep 2024 17:49:28 +0000
Subject: [PATCH 38/62] [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci
---
 R/nix_build.R | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/R/nix_build.R b/R/nix_build.R
index 8edcaf89..3c24c9e2 100644
--- a/R/nix_build.R
+++ b/R/nix_build.R
@@ -24,7 +24,7 @@
 #' }
 nix_build <- function(project_path = ".",
                       message_type = c("simple", "quiet", "verbose")) {
-  message_type <-  match.arg(message_type,
+  message_type <- match.arg(message_type,
     choices = c("simple", "quiet", "verbose")
   )
   # if nix store is not PATH variable; e.g. on macOS (system's) RStudio

From b6020de18d35465af83c20ce4fc0ad4973e23734 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Mon, 16 Sep 2024 20:00:37 +0200
Subject: [PATCH 39/62] no renv

---
 .pre-commit-config.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 80dbacd6..7fccf9ef 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -2,7 +2,7 @@
 # R specific hooks: https://github.com/lorenzwalthert/precommit
 repos:
 -   repo: https://github.com/philipp-baumann/precommit-r-nix
-    rev: 9c54f8c09f17e305db1338cb8159aac9b58f86a3
+    rev: 93c9802d28ad9c648a81c2b69dbffc90aab03fcb
     hooks: 
     -   id: style-files
         args: [--style_pkg=styler, --style_fun=tidyverse_style, --cache-root=styler-perm]

From ceb15e6cc4b166bfeada73b93509f1204682d263 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Mon, 16 Sep 2024 20:12:44 +0200
Subject: [PATCH 40/62] add precommit to the dev env

---
 create_dev_env.R | 2 +-
 default.nix      | 4 +++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/create_dev_env.R b/create_dev_env.R
index c1c9bed9..5ab7075e 100644
--- a/create_dev_env.R
+++ b/create_dev_env.R
@@ -5,7 +5,7 @@ rix(
   r_pkgs = c(
     "devtools", "diffviewer", "fledge", "lintr", "styler",
     "codetools", "jsonlite", "httr", "sys", "testthat", "knitr",
-    "rmarkdown", "rhub", "docopt"
+    "rmarkdown", "rhub", "docopt", "precommit"
   ),
   system_pkgs = c("R", "glibcLocalesUtf8", "pandoc", "nix"),
   tex_pkgs = "scheme-small",
diff --git a/default.nix b/default.nix
index 0ab6a43b..c91e11dc 100644
--- a/default.nix
+++ b/default.nix
@@ -14,7 +14,8 @@
 #  > "knitr",
 #  > "rmarkdown",
 #  > "rhub",
-#  > "docopt"),
+#  > "docopt",
+#  > "precommit"),
 #  > system_pkgs = c("R",
 #  > "glibcLocalesUtf8",
 #  > "pandoc",
@@ -44,6 +45,7 @@ let
       jsonlite
       knitr
       lintr
+      precommit
       rhub
       rmarkdown
       styler

From 83f2e301984eb8086911a773db7155b16f91990e Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Mon, 16 Sep 2024 20:19:32 +0200
Subject: [PATCH 41/62] update fork revision

---
 .pre-commit-config.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 7fccf9ef..ed67f202 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -2,7 +2,7 @@
 # R specific hooks: https://github.com/lorenzwalthert/precommit
 repos:
 -   repo: https://github.com/philipp-baumann/precommit-r-nix
-    rev: 93c9802d28ad9c648a81c2b69dbffc90aab03fcb
+    rev: 71f194a0aef52d395f200023741c932d5ea4bf45
     hooks: 
     -   id: style-files
         args: [--style_pkg=styler, --style_fun=tidyverse_style, --cache-root=styler-perm]

From 8c66d2f337b73bc795386c9d4e01c272866ed00d Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Mon, 16 Sep 2024 20:27:48 +0200
Subject: [PATCH 42/62] lint with flint

---
 R/rix.R                        | 2 +-
 tests/testthat/test-with_nix.R | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/R/rix.R b/R/rix.R
index f6c90dd3..16f929dc 100644
--- a/R/rix.R
+++ b/R/rix.R
@@ -336,7 +336,7 @@ for more details."
     writeLines(default.nix, default.nix_path)
 
     if (file.exists(.Rprofile_path)) {
-      if (all(!grepl(
+      if (!any(grepl(
         "File generated by `rix::rix_init()",
         readLines(.Rprofile_path)
       ))) {
diff --git a/tests/testthat/test-with_nix.R b/tests/testthat/test-with_nix.R
index 44f17cd0..520e61c6 100644
--- a/tests/testthat/test-with_nix.R
+++ b/tests/testthat/test-with_nix.R
@@ -27,7 +27,7 @@ testthat::test_that("Testing `with_nix()` if Nix is installed", {
   out_subshell <- with_nix(
     expr = function() {
       set.seed(1234)
-      a <- sample(seq(1, 10), 5)
+      a <- sample(seq_len(10), 5)
       set.seed(NULL)
       return(a)
     },

From 17a57414b5f94d9ba12c88d074efda2208650ebc Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Mon, 16 Sep 2024 20:55:41 +0200
Subject: [PATCH 43/62] update precommit fork revision

---
 .pre-commit-config.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index ed67f202..5428cb27 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -2,7 +2,7 @@
 # R specific hooks: https://github.com/lorenzwalthert/precommit
 repos:
 -   repo: https://github.com/philipp-baumann/precommit-r-nix
-    rev: 71f194a0aef52d395f200023741c932d5ea4bf45
+    rev: 1f1f92bd00e4fcdcba3d4311d2e1c0810500302d
     hooks: 
     -   id: style-files
         args: [--style_pkg=styler, --style_fun=tidyverse_style, --cache-root=styler-perm]

From 016a51e09f9e668d7afd4408842bb2c25dc4d7a5 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Mon, 16 Sep 2024 21:10:11 +0200
Subject: [PATCH 44/62] do an extra precommit clean and use original R action

---
 .pre-commit-config.yaml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 5428cb27..5322d988 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,8 +1,8 @@
 # All available hooks: https://pre-commit.com/hooks.html
 # R specific hooks: https://github.com/lorenzwalthert/precommit
 repos:
--   repo: https://github.com/philipp-baumann/precommit-r-nix
-    rev: 1f1f92bd00e4fcdcba3d4311d2e1c0810500302d
+-   repo: https://github.com/lorenzwalthert/precommit
+    rev: v0.4.3.9001
     hooks: 
     -   id: style-files
         args: [--style_pkg=styler, --style_fun=tidyverse_style, --cache-root=styler-perm]

From d4d8f2dde3e05bd692161508cb72daafbccf8b65 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Mon, 16 Sep 2024 21:19:52 +0200
Subject: [PATCH 45/62] clean cache

---
 .github/workflows/lints-and-code-formatter.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.github/workflows/lints-and-code-formatter.yaml b/.github/workflows/lints-and-code-formatter.yaml
index 963668f2..83d6113c 100644
--- a/.github/workflows/lints-and-code-formatter.yaml
+++ b/.github/workflows/lints-and-code-formatter.yaml
@@ -26,6 +26,7 @@ jobs:
         with:
           python-version: 3.x
       - uses: pre-commit/action@v3.0.1
+      - run: pre-commit clean
       - uses: pre-commit-ci/lite-action@v1.0.3
         name: pre-commit-ci-lite
         if: always()

From 2ffc9de35e1b724320f86c4e32288679ef57be4b Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Mon, 16 Sep 2024 21:54:05 +0200
Subject: [PATCH 46/62] direct styling, no extra PR

---
 .github/workflows/styler.yaml | 32 +++++++-------------------------
 1 file changed, 7 insertions(+), 25 deletions(-)

diff --git a/.github/workflows/styler.yaml b/.github/workflows/styler.yaml
index 5b46d29d..743c2b81 100644
--- a/.github/workflows/styler.yaml
+++ b/.github/workflows/styler.yaml
@@ -33,31 +33,13 @@ jobs:
       - name: Run styler::style_pkg
         run: nix-shell --run "Rscript -e 'styler::style_pkg()'"
 
-      - name: Check if PR exists
-        id: check_pr
+      - name: commit
         run: |
-          PR=$(gh pr list -S 'Style package' --json number --jq '.[0].number')
-          echo "PR_NUMBER=$PR" >> $GITHUB_ENV
+          git config --local user.name "$GITHUB_ACTOR"
+          git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com"
+          git add \*.R
+          git commit -m 'Style'
 
-      - name: Configure user and check for changes
-        run: |
-          git config --global user.email "ga-ci@no-reply.com"
-          git config --global user.name "CI Robot"
-          git diff-index --quiet HEAD || echo "has_changes=true" >> $GITHUB_ENV
-
-      - name: Commit and push changes
-        if: env.has_changes == 'true'
-        run: |
-          git add .
-          git commit -m "Styled package"
-          git push origin main:style_pkg --force
-
-      - name: Create Pull Request
-        if: env.PR_NUMBER == ''
-        uses: peter-evans/create-pull-request@v6
+      - uses: r-lib/actions/pr-push@v2
         with:
-          branch: style_pkg
-          title: 'Style package'
-          body: 'Automated PR to style package using `styler:style_pkg()`'
-          base: main
-          branch-suffix: ''
+          repo-token: ${{ secrets.GITHUB_TOKEN }}

From 363c25ae315feafec4bea526c50c296de31a67c1 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Mon, 16 Sep 2024 21:58:33 +0200
Subject: [PATCH 47/62] fix styling

---
 R/rix_init.R | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/R/rix_init.R b/R/rix_init.R
index aff4d49a..7f84f776 100644
--- a/R/rix_init.R
+++ b/R/rix_init.R
@@ -223,7 +223,9 @@ rix_init <- function(project_path = ".",
     cat(readLines(con = file(rprofile_file)), sep = "\n")
   }
 
-  on.exit(close(file(rprofile_file)))
+  on.exit({
+    close(file(rprofile_file))
+  })
 }
 
 #' Get character vector of length two with comment and code write `.Rprofile`

From 65c8faa2989fc09168f3178be6ce4a5bb0cd8cd7 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Mon, 16 Sep 2024 22:04:08 +0200
Subject: [PATCH 48/62] manual fix

---
 R/with_nix.R | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/R/with_nix.R b/R/with_nix.R
index 6f3f72f5..5be36395 100644
--- a/R/with_nix.R
+++ b/R/with_nix.R
@@ -326,7 +326,11 @@ with_nix <- function(expr,
     if (nzchar(LD_LIBRARY_PATH_default)) {
       # set old LD_LIBRARY_PATH (only if system's R session and if it wasn't
       # `""`)
-      on.exit(Sys.setenv(LD_LIBRARY_PATH = LD_LIBRARY_PATH_default))
+      on.exit(
+        {
+          Sys.setenv(LD_LIBRARY_PATH = LD_LIBRARY_PATH_default)
+        }
+      )
     }
   }
 

From 42c94c74bf24817a758a83aae03501b56662b727 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Mon, 16 Sep 2024 22:08:39 +0200
Subject: [PATCH 49/62] do pull before committing

---
 .github/workflows/styler.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.github/workflows/styler.yaml b/.github/workflows/styler.yaml
index 743c2b81..b63cd51d 100644
--- a/.github/workflows/styler.yaml
+++ b/.github/workflows/styler.yaml
@@ -37,6 +37,7 @@ jobs:
         run: |
           git config --local user.name "$GITHUB_ACTOR"
           git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com"
+          git pull
           git add \*.R
           git commit -m 'Style'
 

From 3ae73f5ec4d726446ef5330f0b23258a8ba0d47e Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Mon, 16 Sep 2024 22:14:07 +0200
Subject: [PATCH 50/62] add fetch PR

---
 .github/workflows/styler.yaml | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/styler.yaml b/.github/workflows/styler.yaml
index b63cd51d..09c9b46b 100644
--- a/.github/workflows/styler.yaml
+++ b/.github/workflows/styler.yaml
@@ -20,6 +20,10 @@ jobs:
     steps:
       - uses: actions/checkout@v4
 
+      - uses: r-lib/actions/pr-fetch@v2
+        with:
+          repo-token: ${{ secrets.GITHUB_TOKEN }}
+
       - name: Install Nix
         uses: DeterminateSystems/nix-installer-action@main
 
@@ -37,7 +41,6 @@ jobs:
         run: |
           git config --local user.name "$GITHUB_ACTOR"
           git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com"
-          git pull
           git add \*.R
           git commit -m 'Style'
 

From 40774757efac93cba53493eec5f11c6d301e5a94 Mon Sep 17 00:00:00 2001
From: philipp-baumann <philipp-baumann@users.noreply.github.com>
Date: Mon, 16 Sep 2024 20:16:24 +0000
Subject: [PATCH 51/62] Style

---
 R/with_nix.R | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/R/with_nix.R b/R/with_nix.R
index 5be36395..a275c362 100644
--- a/R/with_nix.R
+++ b/R/with_nix.R
@@ -326,11 +326,9 @@ with_nix <- function(expr,
     if (nzchar(LD_LIBRARY_PATH_default)) {
       # set old LD_LIBRARY_PATH (only if system's R session and if it wasn't
       # `""`)
-      on.exit(
-        {
-          Sys.setenv(LD_LIBRARY_PATH = LD_LIBRARY_PATH_default)
-        }
-      )
+      on.exit({
+        Sys.setenv(LD_LIBRARY_PATH = LD_LIBRARY_PATH_default)
+      })
     }
   }
 

From 2786531dbdf5e4d768e8e732a8e2dbe615276c66 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Mon, 16 Sep 2024 22:20:03 +0200
Subject: [PATCH 52/62] remove precommit

---
 .../workflows/lints-and-code-formatter.yaml   | 36 -------------------
 1 file changed, 36 deletions(-)
 delete mode 100644 .github/workflows/lints-and-code-formatter.yaml

diff --git a/.github/workflows/lints-and-code-formatter.yaml b/.github/workflows/lints-and-code-formatter.yaml
deleted file mode 100644
index 83d6113c..00000000
--- a/.github/workflows/lints-and-code-formatter.yaml
+++ /dev/null
@@ -1,36 +0,0 @@
-name: Check code
-on:
-  pull_request:
-    branches: [main]
-
-permissions:
-  contents: write
-  pull-requests: write
-
-jobs:
-  main:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v4
-      - name: Install Nix
-        uses: DeterminateSystems/nix-installer-action@main
-
-      - uses: cachix/cachix-action@v15
-        with:
-          name: rstats-on-nix
-          # If you chose signing key for write access
-          # signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}'
-          # If you chose API tokens for write access OR if you have a private cache
-          authToken: '${{ secrets.CACHIX_AUTH }}'
-      - uses: actions/setup-python@v4
-        with:
-          python-version: 3.x
-      - uses: pre-commit/action@v3.0.1
-      - run: pre-commit clean
-      - uses: pre-commit-ci/lite-action@v1.0.3
-        name: pre-commit-ci-lite
-        if: always()
-        with:
-          msg: check lints and apply code formatting
-    env:
-      GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}

From fd411f77fec34905d22bc376535056db667e8b2c Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Mon, 16 Sep 2024 22:28:58 +0200
Subject: [PATCH 53/62] commit only if changes

---
 .github/workflows/styler.yaml | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/styler.yaml b/.github/workflows/styler.yaml
index 09c9b46b..0591d370 100644
--- a/.github/workflows/styler.yaml
+++ b/.github/workflows/styler.yaml
@@ -37,12 +37,17 @@ jobs:
       - name: Run styler::style_pkg
         run: nix-shell --run "Rscript -e 'styler::style_pkg()'"
 
-      - name: commit
+      - name: config bot user and check for changes
         run: |
           git config --local user.name "$GITHUB_ACTOR"
           git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com"
+          git diff-index --quiet HEAD || echo "has_changes=true" >> $GITHUB_ENV
+          
+      - name: commit if changes
+        if: env.has_changes == 'true'
+        run: |
           git add \*.R
-          git commit -m 'Style'
+          git commit -m 'Style via {styler}'
 
       - uses: r-lib/actions/pr-push@v2
         with:

From 2d5f20ad3ca3b60e39dfb5602275f18bf2cb621c Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Mon, 16 Sep 2024 22:33:21 +0200
Subject: [PATCH 54/62] run rhub nix action only on main not in PR

---
 .github/workflows/run_rhub.yaml | 2 --
 1 file changed, 2 deletions(-)

diff --git a/.github/workflows/run_rhub.yaml b/.github/workflows/run_rhub.yaml
index 532edb18..266e6700 100644
--- a/.github/workflows/run_rhub.yaml
+++ b/.github/workflows/run_rhub.yaml
@@ -2,8 +2,6 @@
 on:
   push:
     branches: [main, master]
-  pull_request:
-    branches: [main, master]
 
 name: run-rhub-checks
 

From 705e3b2c8094ffd6a4702350981834245d217a5d Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Mon, 16 Sep 2024 22:40:25 +0200
Subject: [PATCH 55/62] add lintr and combine lint-and-style action

---
 .github/workflows/style-and-lint.yaml | 59 +++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)
 create mode 100644 .github/workflows/style-and-lint.yaml

diff --git a/.github/workflows/style-and-lint.yaml b/.github/workflows/style-and-lint.yaml
new file mode 100644
index 00000000..32d10f11
--- /dev/null
+++ b/.github/workflows/style-and-lint.yaml
@@ -0,0 +1,59 @@
+# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
+# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
+on:
+  push:
+    branches: [main, master]
+  pull_request:
+    branches: [main, master]
+
+name: styler
+
+permissions: write-all
+
+jobs:
+  style_pkg:
+    runs-on: ubuntu-latest
+    env:
+     GH_TOKEN: ${{ github.token }}
+     GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
+
+    steps:
+      - uses: actions/checkout@v4
+
+      - uses: r-lib/actions/pr-fetch@v2
+        with:
+          repo-token: ${{ secrets.GITHUB_TOKEN }}
+
+      - name: Install Nix
+        uses: DeterminateSystems/nix-installer-action@main
+
+      - uses: cachix/cachix-action@v15
+        with:
+          name: rstats-on-nix
+
+      - name: Build dev env
+        run: nix-build
+
+      - name: Run styler::style_pkg
+        run: nix-shell --run "Rscript -e 'styler::style_pkg()'"
+
+       name: Run lintr
+        run: nix-shell --run "Rscript -e 'lintr::lint_package()'"
+        env:
+          LINTR_ERROR_ON_LINT: true
+
+      - name: config bot user and check for changes
+        run: |
+          git config --local user.name "$GITHUB_ACTOR"
+          git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com"
+          git diff-index --quiet HEAD || echo "has_changes=true" >> $GITHUB_ENV
+          
+      - name: commit if changes
+        if: env.has_changes == 'true'
+        run: |
+          git add \*.R
+          git commit -m 'Style via {styler}'
+
+      - uses: r-lib/actions/pr-push@v2
+        with:
+          repo-token: ${{ secrets.GITHUB_TOKEN }}

From a68af1f2b0cf0f1fa2f04f90cdd6682ad9f0e6f7 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Mon, 16 Sep 2024 22:41:18 +0200
Subject: [PATCH 56/62] name and rename action

---
 .github/workflows/style-and-lint.yaml |  2 +-
 .github/workflows/styler.yaml         | 54 ---------------------------
 2 files changed, 1 insertion(+), 55 deletions(-)
 delete mode 100644 .github/workflows/styler.yaml

diff --git a/.github/workflows/style-and-lint.yaml b/.github/workflows/style-and-lint.yaml
index 32d10f11..13e6cf0c 100644
--- a/.github/workflows/style-and-lint.yaml
+++ b/.github/workflows/style-and-lint.yaml
@@ -6,7 +6,7 @@ on:
   pull_request:
     branches: [main, master]
 
-name: styler
+name: style-and-lint
 
 permissions: write-all
 
diff --git a/.github/workflows/styler.yaml b/.github/workflows/styler.yaml
deleted file mode 100644
index 0591d370..00000000
--- a/.github/workflows/styler.yaml
+++ /dev/null
@@ -1,54 +0,0 @@
-# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
-# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
-on:
-  push:
-    branches: [main, master]
-  pull_request:
-    branches: [main, master]
-
-name: styler
-
-permissions: write-all
-
-jobs:
-  style_pkg:
-    runs-on: ubuntu-latest
-    env:
-     GH_TOKEN: ${{ github.token }}
-     GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
-
-    steps:
-      - uses: actions/checkout@v4
-
-      - uses: r-lib/actions/pr-fetch@v2
-        with:
-          repo-token: ${{ secrets.GITHUB_TOKEN }}
-
-      - name: Install Nix
-        uses: DeterminateSystems/nix-installer-action@main
-
-      - uses: cachix/cachix-action@v15
-        with:
-          name: rstats-on-nix
-
-      - name: Build dev env
-        run: nix-build
-
-      - name: Run styler::style_pkg
-        run: nix-shell --run "Rscript -e 'styler::style_pkg()'"
-
-      - name: config bot user and check for changes
-        run: |
-          git config --local user.name "$GITHUB_ACTOR"
-          git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com"
-          git diff-index --quiet HEAD || echo "has_changes=true" >> $GITHUB_ENV
-          
-      - name: commit if changes
-        if: env.has_changes == 'true'
-        run: |
-          git add \*.R
-          git commit -m 'Style via {styler}'
-
-      - uses: r-lib/actions/pr-push@v2
-        with:
-          repo-token: ${{ secrets.GITHUB_TOKEN }}

From 0137a6f6bbbe06a2636762d5695cae55aa283cc5 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Mon, 16 Sep 2024 22:42:34 +0200
Subject: [PATCH 57/62] fix syntax

---
 .github/workflows/style-and-lint.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/style-and-lint.yaml b/.github/workflows/style-and-lint.yaml
index 13e6cf0c..2fb82d0b 100644
--- a/.github/workflows/style-and-lint.yaml
+++ b/.github/workflows/style-and-lint.yaml
@@ -37,7 +37,7 @@ jobs:
       - name: Run styler::style_pkg
         run: nix-shell --run "Rscript -e 'styler::style_pkg()'"
 
-       name: Run lintr
+      - name: Run lintr
         run: nix-shell --run "Rscript -e 'lintr::lint_package()'"
         env:
           LINTR_ERROR_ON_LINT: true

From 673734b3076325c66f1546d2fcc585b2deeee350 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Mon, 16 Sep 2024 22:49:19 +0200
Subject: [PATCH 58/62] exclude files from lints

---
 .lintr | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/.lintr b/.lintr
index 286405bd..7ef17297 100644
--- a/.lintr
+++ b/.lintr
@@ -4,4 +4,8 @@ linters: linters_with_defaults(
     object_usage_linter = NULL,
     cyclocomp_linter = NULL
   )
+exclusions: list(
+  "tests/testthat/test-fetchers.R",
+  "vignettes/"
+)
 encoding: "UTF-8"

From 385f5cfc6896da97050355144079e2d8ac35c37d Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Mon, 16 Sep 2024 22:54:05 +0200
Subject: [PATCH 59/62] reformat

---
 .lintr | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/.lintr b/.lintr
index 7ef17297..ab25bef9 100644
--- a/.lintr
+++ b/.lintr
@@ -1,9 +1,9 @@
 linters: linters_with_defaults(
-    line_length_linter(100),
-    commented_code_linter = NULL,
-    object_usage_linter = NULL,
-    cyclocomp_linter = NULL
-  )
+  line_length_linter(100),
+  commented_code_linter = NULL,
+  object_usage_linter = NULL,
+  cyclocomp_linter = NULL
+)
 exclusions: list(
   "tests/testthat/test-fetchers.R",
   "vignettes/"

From 2ecc2e093b7a5b0e8001ee3cb7d60c0522e87d71 Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Mon, 16 Sep 2024 23:02:01 +0200
Subject: [PATCH 60/62] fix linter config format

---
 .lintr | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/.lintr b/.lintr
index ab25bef9..3c29bc69 100644
--- a/.lintr
+++ b/.lintr
@@ -1,11 +1,11 @@
 linters: linters_with_defaults(
-  line_length_linter(100),
-  commented_code_linter = NULL,
-  object_usage_linter = NULL,
-  cyclocomp_linter = NULL
-)
+    line_length_linter = line_length_linter(100),
+    commented_code_linter = NULL,
+    object_usage_linter = NULL,
+    cyclocomp_linter = NULL
+  )
 exclusions: list(
-  "tests/testthat/test-fetchers.R",
-  "vignettes/"
-)
+    "tests/testthat/test-fetchers.R",
+    "vignettes/"
+  )
 encoding: "UTF-8"

From dc9a962d983107910e5ea3055134883bd26c1c5c Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Mon, 16 Sep 2024 23:18:13 +0200
Subject: [PATCH 61/62] add flint to ignores and set up flint

---
 .Rbuildignore                               |  5 +-
 .github/workflows/flint-code-formatter.yaml | 55 +++++++++++++++++++++
 .gitignore                                  |  1 +
 3 files changed, 60 insertions(+), 1 deletion(-)
 create mode 100644 .github/workflows/flint-code-formatter.yaml

diff --git a/.Rbuildignore b/.Rbuildignore
index ea5f8885..76727e35 100644
--- a/.Rbuildignore
+++ b/.Rbuildignore
@@ -23,4 +23,7 @@ create_dev_env.R
 ^\.pre-commit-config\.yaml$
 ^data-raw$
 .envrc
-.direnv
\ No newline at end of file
+.direnv
+
+# flint files
+^flint$
\ No newline at end of file
diff --git a/.github/workflows/flint-code-formatter.yaml b/.github/workflows/flint-code-formatter.yaml
new file mode 100644
index 00000000..9af5998e
--- /dev/null
+++ b/.github/workflows/flint-code-formatter.yaml
@@ -0,0 +1,55 @@
+# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
+# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
+on:
+  push:
+    branches: [main, master]
+  pull_request:
+    branches: [main, master]
+  release:
+    types: [published]
+  workflow_dispatch:
+
+name: flint-code-formatter
+
+jobs:
+  flint:
+    runs-on: ubuntu-latest
+    # Only restrict concurrency for non-PR jobs
+    concurrency:
+      group: rix-${{ github.event_name != 'pull_request' || github.run_id }}
+    env:
+      GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
+    permissions:
+      contents: write
+    steps:
+      - uses: actions/checkout@v4
+
+      - uses: r-lib/actions/pr-fetch@v2
+        with:
+          repo-token: ${{ secrets.GITHUB_TOKEN }}
+
+      - uses: r-lib/actions/setup-r@v2
+
+      - name: Install flint
+        run: install.packages("flint", repos = c("https://etiennebacher.r-universe.dev/", getOption("repos")))
+        shell: Rscript {0}
+
+      - name: Run flint
+        run: flint::lint_package(exclude_path = "inst")
+        shell: Rscript {0}
+
+      - name: config bot user and check for changes
+        run: |
+          git config --local user.name "$GITHUB_ACTOR"
+          git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com"
+          git diff-index --quiet HEAD || echo "has_changes=true" >> $GITHUB_ENV
+          
+      - name: commit if changes
+        if: env.has_changes == 'true'
+        run: |
+          git add \*.R
+          git commit -m 'Check and format code with {flint}'
+
+      - uses: r-lib/actions/pr-push@v2
+        with:
+          repo-token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.gitignore b/.gitignore
index 630f4210..0b98b66d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,7 @@
 .httr-oauth
 inst/doc
 docs
+flint/cache_file_state.rds
 result
 /doc/
 /Meta/

From fdd288954c879afba3f85da1ca9e1fe63a4e2dbd Mon Sep 17 00:00:00 2001
From: Philipp Baumann <baumann-philipp@protonmail.com>
Date: Mon, 16 Sep 2024 23:18:48 +0200
Subject: [PATCH 62/62] add flint rules

---
 flint/config.yml                     |  44 ++++++++++
 flint/rules/T_and_F_symbol.yml       |  97 ++++++++++++++++++++
 flint/rules/absolute_path.yml        |  13 +++
 flint/rules/any_duplicated.yml       |  91 +++++++++++++++++++
 flint/rules/any_is_na.yml            |   7 ++
 flint/rules/class_equals.yml         |  42 +++++++++
 flint/rules/double_assignment.yml    |  23 +++++
 flint/rules/duplicate_argument.yml   |  46 ++++++++++
 flint/rules/empty_assignment.yml     |  15 ++++
 flint/rules/equal_assignment.yml     |  10 +++
 flint/rules/equals_na.yml            |  37 ++++++++
 flint/rules/expect_comparison.yml    |  37 ++++++++
 flint/rules/expect_length.yml        |  12 +++
 flint/rules/expect_named.yml         |  79 +++++++++++++++++
 flint/rules/expect_not.yml           |  23 +++++
 flint/rules/expect_null.yml          |  22 +++++
 flint/rules/expect_true_false.yml    |  28 ++++++
 flint/rules/expect_type.yml          |  51 +++++++++++
 flint/rules/for_loop_index.yml       |  27 ++++++
 flint/rules/function_return.yml      |  11 +++
 flint/rules/implicit_assignment.yml  |  69 +++++++++++++++
 flint/rules/is_numeric.yml           |  25 ++++++
 flint/rules/length_levels.yml        |   7 ++
 flint/rules/length_test.yml          |  59 +++++++++++++
 flint/rules/lengths.yml              |  59 +++++++++++++
 flint/rules/library_call.yml         |  26 ++++++
 flint/rules/literal_coercion.yml     |  89 +++++++++++++++++++
 flint/rules/matrix_apply.yml         | 110 +++++++++++++++++++++++
 flint/rules/missing_argument.yml     |  44 ++++++++++
 flint/rules/nested_ifelse.yml        |  29 ++++++
 flint/rules/numeric_leading_zero.yml |  11 +++
 flint/rules/outer_negation.yml       |  29 ++++++
 flint/rules/package_hooks.yml        | 127 +++++++++++++++++++++++++++
 flint/rules/paste.yml                |  75 ++++++++++++++++
 flint/rules/redundant_equals.yml     |  29 ++++++
 flint/rules/redundant_ifelse.yml     |  67 ++++++++++++++
 flint/rules/right_assignment.yml     |  10 +++
 flint/rules/semicolon.yml            |  10 +++
 flint/rules/seq.yml                  | 121 +++++++++++++++++++++++++
 flint/rules/sort.yml                 |  85 ++++++++++++++++++
 flint/rules/todo_comment.yml         |   7 ++
 flint/rules/undesirable_function.yml |  13 +++
 flint/rules/undesirable_operator.yml |  29 ++++++
 flint/rules/unnecessary_nesting.yml  |  31 +++++++
 flint/rules/unreachable_code.yml     |  64 ++++++++++++++
 45 files changed, 1940 insertions(+)
 create mode 100644 flint/config.yml
 create mode 100644 flint/rules/T_and_F_symbol.yml
 create mode 100644 flint/rules/absolute_path.yml
 create mode 100644 flint/rules/any_duplicated.yml
 create mode 100644 flint/rules/any_is_na.yml
 create mode 100644 flint/rules/class_equals.yml
 create mode 100644 flint/rules/double_assignment.yml
 create mode 100644 flint/rules/duplicate_argument.yml
 create mode 100644 flint/rules/empty_assignment.yml
 create mode 100644 flint/rules/equal_assignment.yml
 create mode 100644 flint/rules/equals_na.yml
 create mode 100644 flint/rules/expect_comparison.yml
 create mode 100644 flint/rules/expect_length.yml
 create mode 100644 flint/rules/expect_named.yml
 create mode 100644 flint/rules/expect_not.yml
 create mode 100644 flint/rules/expect_null.yml
 create mode 100644 flint/rules/expect_true_false.yml
 create mode 100644 flint/rules/expect_type.yml
 create mode 100644 flint/rules/for_loop_index.yml
 create mode 100644 flint/rules/function_return.yml
 create mode 100644 flint/rules/implicit_assignment.yml
 create mode 100644 flint/rules/is_numeric.yml
 create mode 100644 flint/rules/length_levels.yml
 create mode 100644 flint/rules/length_test.yml
 create mode 100644 flint/rules/lengths.yml
 create mode 100644 flint/rules/library_call.yml
 create mode 100644 flint/rules/literal_coercion.yml
 create mode 100644 flint/rules/matrix_apply.yml
 create mode 100644 flint/rules/missing_argument.yml
 create mode 100644 flint/rules/nested_ifelse.yml
 create mode 100644 flint/rules/numeric_leading_zero.yml
 create mode 100644 flint/rules/outer_negation.yml
 create mode 100644 flint/rules/package_hooks.yml
 create mode 100644 flint/rules/paste.yml
 create mode 100644 flint/rules/redundant_equals.yml
 create mode 100644 flint/rules/redundant_ifelse.yml
 create mode 100644 flint/rules/right_assignment.yml
 create mode 100644 flint/rules/semicolon.yml
 create mode 100644 flint/rules/seq.yml
 create mode 100644 flint/rules/sort.yml
 create mode 100644 flint/rules/todo_comment.yml
 create mode 100644 flint/rules/undesirable_function.yml
 create mode 100644 flint/rules/undesirable_operator.yml
 create mode 100644 flint/rules/unnecessary_nesting.yml
 create mode 100644 flint/rules/unreachable_code.yml

diff --git a/flint/config.yml b/flint/config.yml
new file mode 100644
index 00000000..6ae436e8
--- /dev/null
+++ b/flint/config.yml
@@ -0,0 +1,44 @@
+keep:
+  - any_duplicated
+  - any_is_na
+  - class_equals
+  - double_assignment
+  - duplicate_argument
+  - empty_assignment
+  - equal_assignment
+  - equals_na
+  - expect_comparison
+  - expect_length
+  - expect_named
+  - expect_not
+  - expect_null
+  - expect_true_false
+  - expect_type
+  - for_loop_index
+  - function_return
+  - implicit_assignment
+  - is_numeric
+  - length_levels
+  - length_test
+  - lengths
+  - library_call
+  - literal_coercion
+  - matrix_apply
+  - missing_argument
+  - nested_ifelse
+  - numeric_leading_zero
+  - outer_negation
+  - package_hooks
+  - paste
+  - redundant_equals
+  - redundant_ifelse
+  - right_assignment
+  - semicolon
+  - seq
+  - sort
+  - T_and_F_symbol
+  - todo_comment
+  - undesirable_function
+  - undesirable_operator
+  - unnecessary_nesting
+  - unreachable_code
diff --git a/flint/rules/T_and_F_symbol.yml b/flint/rules/T_and_F_symbol.yml
new file mode 100644
index 00000000..8bfd14df
--- /dev/null
+++ b/flint/rules/T_and_F_symbol.yml
@@ -0,0 +1,97 @@
+id: true_false_symbol
+language: r
+severity: warning
+rule:
+  pattern: T
+  kind: identifier
+  not:
+    any:
+      - precedes:
+          any:
+            - pattern: <-
+            - pattern: =
+            - regex: ^~$
+      - follows:
+          any:
+            - pattern: $
+            - regex: ^~$
+      - inside:
+          any:
+            - kind: parameter
+            - kind: call
+            - kind: binary_operator
+              follows:
+                regex: ^~$
+                stopBy: end
+          stopBy:
+            kind:
+              argument
+fix: TRUE
+message: Use TRUE instead of the symbol T.
+
+---
+
+id: true_false_symbol_2
+language: r
+severity: warning
+rule:
+  pattern: F
+  kind: identifier
+  not:
+    any:
+      - precedes:
+          any:
+            - pattern: <-
+            - pattern: =
+            - regex: ^~$
+      - follows:
+          any:
+            - pattern: $
+            - regex: ^~$
+      - inside:
+          any:
+            - kind: parameter
+            - kind: call
+            - kind: binary_operator
+              follows:
+                regex: ^~$
+                stopBy: end
+          stopBy:
+            kind:
+              argument
+fix: FALSE
+message: Use FALSE instead of the symbol F.
+
+---
+
+id: true_false_symbol_3
+language: r
+severity: warning
+rule:
+  pattern: T
+  kind: identifier
+  precedes:
+    any:
+      - pattern: <-
+      - pattern: =
+  not:
+    inside:
+      kind: argument
+message: Don't use T as a variable name, as it can break code relying on T being TRUE.
+
+---
+
+id: true_false_symbol_4
+language: r
+severity: warning
+rule:
+  pattern: F
+  kind: identifier
+  precedes:
+    any:
+      - pattern: <-
+      - pattern: =
+  not:
+    inside:
+      kind: argument
+message: Don't use F as a variable name, as it can break code relying on F being FALSE.
diff --git a/flint/rules/absolute_path.yml b/flint/rules/absolute_path.yml
new file mode 100644
index 00000000..3c1e9345
--- /dev/null
+++ b/flint/rules/absolute_path.yml
@@ -0,0 +1,13 @@
+id: absolute_path-1
+language: r
+severity: warning
+rule:
+  kind: string_content
+  any:
+    - regex: '^~[[:alpha:]]'
+    - regex: '^~/[[:alpha:]]'
+    - regex: '^[[:alpha:]]:'
+    - regex: '^(/|~)$'
+    - regex: '^/[[:alpha:]]'
+    - regex: '^\\'
+message: Do not use absolute paths.
diff --git a/flint/rules/any_duplicated.yml b/flint/rules/any_duplicated.yml
new file mode 100644
index 00000000..514b028f
--- /dev/null
+++ b/flint/rules/any_duplicated.yml
@@ -0,0 +1,91 @@
+id: any_duplicated-1
+language: r
+severity: warning
+rule:
+  pattern: any($$$ duplicated($MYVAR) $$$)
+fix: anyDuplicated(~~MYVAR~~) > 0
+message: anyDuplicated(x, ...) > 0 is better than any(duplicated(x), ...).
+
+---
+
+id: any_duplicated-2
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: length(unique($MYVAR)) == length($MYVAR)
+    - pattern: length($MYVAR) == length(unique($MYVAR))
+fix: anyDuplicated(~~MYVAR~~) == 0L
+message: anyDuplicated(x) == 0L is better than length(unique(x)) == length(x).
+
+---
+
+id: any_duplicated-3
+language: r
+severity: warning
+rule:
+  pattern: length(unique($MYVAR)) != length($MYVAR)
+fix: anyDuplicated(~~MYVAR~~) != 0L
+message: |
+  Use anyDuplicated(x) != 0L (or > or <)  instead of length(unique(x)) != length(x)
+  (or > or <).
+
+---
+
+id: any_duplicated-4
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: nrow($DATA) != length(unique($DATA$µCOL))
+    - pattern: length(unique($DATA$µCOL)) != nrow($DATA)
+fix: anyDuplicated(~~DATA~~$~~COL~~) != 0L
+message: |
+  anyDuplicated(DF$col) != 0L is better than length(unique(DF$col)) != nrow(DF)
+
+---
+
+# id: any_duplicated-5
+# language: r
+# severity: warning
+# rule:
+#   any:
+#     - pattern:
+#         context: nrow($DATA) != length(unique($DATA[["µCOL"]]))
+#         strictness: ast
+#     - pattern:
+#         context: length(unique($DATA[["µCOL"]])) != nrow($DATA)
+#         strictness: ast
+# fix: anyDuplicated(~~DATA~~[["~~COL~~"]]) != 0L
+# message: |
+#   anyDuplicated(DF[["col"]]) != 0L is better than length(unique(DF[["col"]])) != nrow(DF)
+#
+# ---
+
+id: any_duplicated-6
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: nrow($DATA) == length(unique($DATA$µCOL))
+    - pattern: length(unique($DATA$µCOL)) == nrow($DATA)
+fix: anyDuplicated(~~DATA~~$~~COL~~) == 0L
+message: |
+  anyDuplicated(DF$col) == 0L is better than length(unique(DF$col)) == nrow(DF)
+
+# ---
+#
+# id: any_duplicated-7
+# language: r
+# severity: warning
+# rule:
+#   any:
+#     - pattern:
+#         context: nrow($DATA) == length(unique($DATA[["µCOL"]]))
+#         strictness: ast
+#     - pattern:
+#         context: length(unique($DATA[["µCOL"]])) == nrow($DATA)
+#         strictness: ast
+# fix: anyDuplicated(~~DATA~~[["~~COL~~"]]) == 0L
+# message: |
+#   anyDuplicated(DF[["col"]]) == 0L is better than length(unique(DF[["col"]])) == nrow(DF)
diff --git a/flint/rules/any_is_na.yml b/flint/rules/any_is_na.yml
new file mode 100644
index 00000000..7b05a75b
--- /dev/null
+++ b/flint/rules/any_is_na.yml
@@ -0,0 +1,7 @@
+id: any_na-1
+language: r
+severity: warning
+rule:
+  pattern: any($$$ is.na($MYVAR) $$$)
+fix: anyNA(~~MYVAR~~)
+message: anyNA(x) is better than any(is.na(x)).
diff --git a/flint/rules/class_equals.yml b/flint/rules/class_equals.yml
new file mode 100644
index 00000000..9b8804f7
--- /dev/null
+++ b/flint/rules/class_equals.yml
@@ -0,0 +1,42 @@
+id: class_equals_1
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: class($VAR) == $CLASSNAME
+    - pattern: $CLASSNAME == class($VAR)
+  not:
+    inside:
+      kind: argument
+fix: inherits(~~VAR~~, ~~CLASSNAME~~)
+message: Instead of comparing class(x) with ==, use inherits(x, 'class-name') or is.<class> or is(x, 'class')
+
+---
+
+id: class_equals_2
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: class($VAR) != $CLASSNAME
+    - pattern: $CLASSNAME != class($VAR)
+  not:
+    inside:
+      kind: argument
+fix: "!inherits(~~VAR~~, ~~CLASSNAME~~)"
+message: "Instead of comparing class(x) with !=, use !inherits(x, 'class-name') or is.<class> or is(x, 'class')"
+
+---
+
+id: class_equals_3
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: $CLASSNAME %in% class($VAR)
+    - pattern: class($VAR) %in% $CLASSNAME
+constraints:
+  CLASSNAME:
+    kind: string
+fix: inherits(~~VAR~~, ~~CLASSNAME~~)
+message: Instead of comparing class(x) with %in%, use inherits(x, 'class-name') or is.<class> or is(x, 'class')
diff --git a/flint/rules/double_assignment.yml b/flint/rules/double_assignment.yml
new file mode 100644
index 00000000..60a04e23
--- /dev/null
+++ b/flint/rules/double_assignment.yml
@@ -0,0 +1,23 @@
+id: right_double_assignment
+language: r
+severity: hint
+rule:
+  pattern: $RHS ->> $LHS
+  has:
+    field: rhs
+    kind: identifier
+message: ->> can have hard-to-predict behavior; prefer assigning to a
+  specific environment instead (with assign() or <-).
+
+---
+
+id: left_double_assignment
+language: r
+severity: hint
+rule:
+  pattern: $LHS <<- $RHS
+  has:
+    field: lhs
+    kind: identifier
+message: <<- can have hard-to-predict behavior; prefer assigning to a
+  specific environment instead (with assign() or <-).
diff --git a/flint/rules/duplicate_argument.yml b/flint/rules/duplicate_argument.yml
new file mode 100644
index 00000000..415b9ff8
--- /dev/null
+++ b/flint/rules/duplicate_argument.yml
@@ -0,0 +1,46 @@
+id: duplicate_argument-1
+language: r
+severity: warning
+rule:
+  # Look for a function argument...
+  kind: argument
+  any:
+    - has:
+        kind: identifier
+        field: name
+        pattern: $OBJ
+    - has:
+        kind: string_content
+        pattern: $OBJ
+        stopBy: end
+
+  # ... that follows other argument(s) with the same name...
+  follows:
+    kind: argument
+    stopBy: end
+    has:
+      stopBy: end
+      kind: identifier
+      field: name
+      pattern: $OBJ
+
+  # ... inside a function call (or a subset environment for data.table)...
+  inside:
+    kind: arguments
+    follows:
+      any:
+        - kind: identifier
+          pattern: $FUN
+        - kind: string
+      inside:
+        any:
+          - kind: call
+          - kind: subset
+
+# ... that is not a function listed below.
+constraints:
+  FUN:
+    not:
+      regex: ^(mutate|transmute)$
+
+message: Avoid duplicate arguments in function calls.
diff --git a/flint/rules/empty_assignment.yml b/flint/rules/empty_assignment.yml
new file mode 100644
index 00000000..ccc995fa
--- /dev/null
+++ b/flint/rules/empty_assignment.yml
@@ -0,0 +1,15 @@
+id: empty_assignment-1
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: $OBJ <- {}
+    - pattern: $OBJ <- {$CONTENT}
+    - pattern: $OBJ = {}
+    - pattern: $OBJ = {$CONTENT}
+constraints:
+  CONTENT:
+    regex: ^\s+$
+message: |
+  Assign NULL explicitly or, whenever possible, allocate the empty object with
+  the right type and size.
diff --git a/flint/rules/equal_assignment.yml b/flint/rules/equal_assignment.yml
new file mode 100644
index 00000000..77074fe1
--- /dev/null
+++ b/flint/rules/equal_assignment.yml
@@ -0,0 +1,10 @@
+id: equal_assignment
+language: r
+severity: hint
+rule:
+  pattern: $LHS = $RHS
+  has:
+    field: lhs
+    kind: identifier
+fix: ~~LHS~~ <- ~~RHS~~
+message: Use <-, not =, for assignment.
diff --git a/flint/rules/equals_na.yml b/flint/rules/equals_na.yml
new file mode 100644
index 00000000..d044f304
--- /dev/null
+++ b/flint/rules/equals_na.yml
@@ -0,0 +1,37 @@
+id: equals_na
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: $MYVAR == NA
+    - pattern: $MYVAR == NA_integer_
+    - pattern: $MYVAR == NA_real_
+    - pattern: $MYVAR == NA_complex_
+    - pattern: $MYVAR == NA_character_
+    - pattern: NA == $MYVAR
+    - pattern: NA_integer_ == $MYVAR
+    - pattern: NA_real_ == $MYVAR
+    - pattern: NA_complex_ == $MYVAR
+    - pattern: NA_character_ == $MYVAR
+fix: is.na(~~MYVAR~~)
+message: Use is.na for comparisons to NA (not == or !=).
+
+---
+
+id: equals_na_2
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: $MYVAR != NA
+    - pattern: $MYVAR != NA_integer_
+    - pattern: $MYVAR != NA_real_
+    - pattern: $MYVAR != NA_complex_
+    - pattern: $MYVAR != NA_character_
+    - pattern: NA != $MYVAR
+    - pattern: NA_integer_ != $MYVAR
+    - pattern: NA_real_ != $MYVAR
+    - pattern: NA_complex_ != $MYVAR
+    - pattern: NA_character_ != $MYVAR
+fix: is.na(~~MYVAR~~)
+message: Use is.na for comparisons to NA (not == or !=).
diff --git a/flint/rules/expect_comparison.yml b/flint/rules/expect_comparison.yml
new file mode 100644
index 00000000..6af9bb13
--- /dev/null
+++ b/flint/rules/expect_comparison.yml
@@ -0,0 +1,37 @@
+id: expect_comparison-1
+language: r
+severity: warning
+rule:
+  pattern: expect_true($X > $Y)
+fix: expect_gt(~~X~~, ~~Y~~)
+message: expect_gt(x, y) is better than expect_true(x > y).
+
+---
+
+id: expect_comparison-2
+language: r
+severity: warning
+rule:
+  pattern: expect_true($X >= $Y)
+fix: expect_gte(~~X~~, ~~Y~~)
+message: expect_gte(x, y) is better than expect_true(x >= y).
+
+---
+
+id: expect_comparison-3
+language: r
+severity: warning
+rule:
+  pattern: expect_true($X < $Y)
+fix: expect_lt(~~X~~, ~~Y~~)
+message: expect_lt(x, y) is better than expect_true(x < y).
+
+---
+
+id: expect_comparison-4
+language: r
+severity: warning
+rule:
+  pattern: expect_true($X <= $Y)
+fix: expect_lte(~~X~~, ~~Y~~)
+message: expect_lte(x, y) is better than expect_true(x <= y).
diff --git a/flint/rules/expect_length.yml b/flint/rules/expect_length.yml
new file mode 100644
index 00000000..cd5f2db0
--- /dev/null
+++ b/flint/rules/expect_length.yml
@@ -0,0 +1,12 @@
+id: expect_length-1
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: $FUN(length($OBJ), $VALUE)
+    - pattern: $FUN($VALUE, length($OBJ))
+constraints:
+  FUN:
+    regex: ^(expect_identical|expect_equal)$
+fix: expect_length(~~OBJ~~, ~~VALUE~~)
+message: expect_length(x, n) is better than ~~FUN~~(length(x), n).
diff --git a/flint/rules/expect_named.yml b/flint/rules/expect_named.yml
new file mode 100644
index 00000000..bf88f366
--- /dev/null
+++ b/flint/rules/expect_named.yml
@@ -0,0 +1,79 @@
+id: expect_named-1
+language: r
+severity: warning
+rule:
+  any:
+    - pattern:
+        context: expect_identical(names($OBJ), $VALUES)
+        strictness: ast
+    - pattern:
+        context: expect_identical($VALUES, names($OBJ))
+        strictness: ast
+constraints:
+  VALUES:
+    not:
+      regex: colnames|rownames|dimnames|NULL
+      has:
+        kind: null
+fix: expect_named(~~OBJ~~, ~~VALUES~~)
+message: expect_named(x, n) is better than expect_identical(names(x), n).
+
+---
+
+id: expect_named-2
+language: r
+severity: warning
+rule:
+  any:
+    - pattern:
+        context: expect_equal(names($OBJ), $VALUES)
+        strictness: ast
+    - pattern:
+        context: expect_equal($VALUES, names($OBJ))
+        strictness: ast
+constraints:
+  VALUES:
+    not:
+      regex: colnames|rownames|dimnames|NULL
+fix: expect_named(~~OBJ~~, ~~VALUES~~)
+message: expect_named(x, n) is better than expect_equal(names(x), n).
+
+---
+
+id: expect_named-3
+language: r
+severity: warning
+rule:
+  any:
+    - pattern:
+        context: testthat::expect_identical(names($OBJ), $VALUES)
+        strictness: ast
+    - pattern:
+        context: testthat::expect_identical($VALUES, names($OBJ))
+        strictness: ast
+constraints:
+  VALUES:
+    not:
+      regex: colnames|rownames|dimnames|NULL
+fix: testthat::expect_named(~~OBJ~~, ~~VALUES~~)
+message: expect_named(x, n) is better than expect_identical(names(x), n).
+
+---
+
+id: expect_named-4
+language: r
+severity: warning
+rule:
+  any:
+    - pattern:
+        context: testthat::expect_equal(names($OBJ), $VALUES)
+        strictness: ast
+    - pattern:
+        context: testthat::expect_equal($VALUES, names($OBJ))
+        strictness: ast
+constraints:
+  VALUES:
+    not:
+      regex: colnames|rownames|dimnames|NULL
+fix: testthat::expect_named(~~OBJ~~, ~~VALUES~~)
+message: expect_named(x, n) is better than expect_equal(names(x), n).
diff --git a/flint/rules/expect_not.yml b/flint/rules/expect_not.yml
new file mode 100644
index 00000000..3a23e9f2
--- /dev/null
+++ b/flint/rules/expect_not.yml
@@ -0,0 +1,23 @@
+id: expect_not-1
+language: r
+severity: warning
+rule:
+  all:
+    - pattern: expect_true(!$COND)
+    - not:
+        regex: '^expect_true\(!!'
+fix: expect_false(~~COND~~)
+message: expect_false(x) is better than expect_true(!x), and vice versa.
+
+---
+
+id: expect_not-2
+language: r
+severity: warning
+rule:
+  all:
+    - pattern: expect_false(!$COND)
+    - not:
+        regex: '^expect_false\(!!'
+fix: expect_true(~~COND~~)
+message: expect_false(x) is better than expect_true(!x), and vice versa.
diff --git a/flint/rules/expect_null.yml b/flint/rules/expect_null.yml
new file mode 100644
index 00000000..7888fdb0
--- /dev/null
+++ b/flint/rules/expect_null.yml
@@ -0,0 +1,22 @@
+id: expect_null-1
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: $FUN(NULL, $VALUES)
+    - pattern: $FUN($VALUES, NULL)
+constraints:
+  FUN:
+    regex: ^(expect_identical|expect_equal)$
+fix: expect_null(~~VALUES~~)
+message: expect_null(x) is better than ~~FUN~~(x, NULL).
+
+---
+
+id: expect_null-2
+language: r
+severity: warning
+rule:
+  pattern: expect_true(is.null($VALUES))
+fix: expect_null(~~VALUES~~)
+message: expect_null(x) is better than expect_true(is.null(x)).
diff --git a/flint/rules/expect_true_false.yml b/flint/rules/expect_true_false.yml
new file mode 100644
index 00000000..784843d8
--- /dev/null
+++ b/flint/rules/expect_true_false.yml
@@ -0,0 +1,28 @@
+id: expect_true_false-1
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: $FUN(TRUE, $VALUES)
+    - pattern: $FUN($VALUES, TRUE)
+constraints:
+  FUN:
+    regex: ^(expect_identical|expect_equal)$
+fix: expect_true(~~VALUES~~)
+message: expect_true(x) is better than ~~FUN~~(x, TRUE).
+
+---
+
+id: expect_true_false-2
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: $FUN(FALSE, $VALUES)
+    - pattern: $FUN($VALUES, FALSE)
+constraints:
+  FUN:
+    regex: ^(expect_identical|expect_equal)$
+fix: expect_false(~~VALUES~~)
+message: expect_false(x) is better than ~~FUN~~(x, FALSE).
+
diff --git a/flint/rules/expect_type.yml b/flint/rules/expect_type.yml
new file mode 100644
index 00000000..1ab20eca
--- /dev/null
+++ b/flint/rules/expect_type.yml
@@ -0,0 +1,51 @@
+id: expect_type-1
+language: r
+severity: warning
+rule:
+  any:
+    - pattern:
+        context: expect_identical(typeof($OBJ), $VALUES)
+        strictness: ast
+    - pattern:
+        context: expect_identical($VALUES, typeof($OBJ))
+        strictness: ast
+constraints:
+  VALUES:
+    not:
+      regex: typeof
+fix: expect_type(~~OBJ~~, ~~VALUES~~)
+message: expect_type(x, t) is better than expect_identical(typeof(x), t).
+
+---
+
+id: expect_type-2
+language: r
+severity: warning
+rule:
+  any:
+    - pattern:
+        context: expect_equal(typeof($OBJ), $VALUES)
+        strictness: ast
+    - pattern:
+        context: expect_equal($VALUES, typeof($OBJ))
+        strictness: ast
+constraints:
+  VALUES:
+    not:
+      regex: typeof
+fix: expect_type(~~OBJ~~, ~~VALUES~~)
+message: expect_type(x, t) is better than expect_equal(typeof(x), t).
+
+---
+
+id: expect_type-3
+language: r
+severity: warning
+rule:
+  pattern: expect_true($FUN($OBJ))
+constraints:
+  FUN:
+    regex: ^is\.
+    not:
+      regex: data\.frame$
+message: expect_type(x, t) is better than expect_true(is.<t>(x)).
diff --git a/flint/rules/for_loop_index.yml b/flint/rules/for_loop_index.yml
new file mode 100644
index 00000000..e5b28b43
--- /dev/null
+++ b/flint/rules/for_loop_index.yml
@@ -0,0 +1,27 @@
+id: for_loop_index-1
+language: r
+severity: warning
+rule:
+  pattern: for ($IDX in $IDX)
+message: Don't re-use any sequence symbols as the index symbol in a for loop.
+
+---
+
+id: for_loop_index-2
+language: r
+severity: warning
+rule:
+  pattern: for ($IDX in $SEQ)
+constraints:
+  SEQ:
+    kind: call
+    has:
+      kind: arguments
+      has:
+        kind: argument
+        stopBy: end
+        has:
+          kind: identifier
+          field: value
+          pattern: $IDX
+message: Don't re-use any sequence symbols as the index symbol in a for loop.
diff --git a/flint/rules/function_return.yml b/flint/rules/function_return.yml
new file mode 100644
index 00000000..31ba46be
--- /dev/null
+++ b/flint/rules/function_return.yml
@@ -0,0 +1,11 @@
+id: function_return-1
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: return($OBJ <- $VAL)
+    - pattern: return($OBJ <<- $VAL)
+    - pattern: return($VAL -> $OBJ)
+    - pattern: return($VAL ->> $OBJ)
+message: |
+  Move the assignment outside of the return() clause, or skip assignment altogether.
diff --git a/flint/rules/implicit_assignment.yml b/flint/rules/implicit_assignment.yml
new file mode 100644
index 00000000..133a40ef
--- /dev/null
+++ b/flint/rules/implicit_assignment.yml
@@ -0,0 +1,69 @@
+id: implicit_assignment-1
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: $RECEIVER <- $VALUE
+    - pattern: $RECEIVER <<- $VALUE
+    - pattern: $VALUE -> $RECEIVER
+    - pattern: $VALUE ->> $RECEIVER
+  inside:
+    any:
+      - kind: if_statement
+      - kind: while_statement
+    field: condition
+    stopBy: end
+    strictness: cst
+message: |
+  Avoid implicit assignments in function calls. For example, instead of
+  `if (x <- 1L) { ... }`, write `x <- 1L; if (x) { ... }`.
+
+---
+
+id: implicit_assignment-2
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: $RECEIVER <- $VALUE
+    - pattern: $RECEIVER <<- $VALUE
+    - pattern: $VALUE -> $RECEIVER
+    - pattern: $VALUE ->> $RECEIVER
+  inside:
+    kind: for_statement
+    field: sequence
+    stopBy: end
+    strictness: cst
+message: |
+  Avoid implicit assignments in function calls. For example, instead of
+  `if (x <- 1L) { ... }`, write `x <- 1L; if (x) { ... }`.
+
+# ---
+#
+# id: implicit_assignment-3
+# language: r
+# severity: warning
+# rule:
+#   any:
+#     - pattern: $RECEIVER <- $VALUE
+#     - pattern: $RECEIVER <<- $VALUE
+#     - pattern: $VALUE -> $RECEIVER
+#     - pattern: $VALUE ->> $RECEIVER
+#   inside:
+#     kind: argument
+#     field: value
+#     strictness: cst
+#     stopBy: end
+#   not:
+#     inside:
+#       kind: call
+#       field: function
+#       has:
+#         kind: identifier
+#         regex: ^(lapply)$
+#       stopBy: end
+#       strictness: cst
+# message: |
+#   Avoid implicit assignments in function calls. For example, instead of
+#   `if (x <- 1L) { ... }`, write `x <- 1L; if (x) { ... }`.
+
diff --git a/flint/rules/is_numeric.yml b/flint/rules/is_numeric.yml
new file mode 100644
index 00000000..6ef8e223
--- /dev/null
+++ b/flint/rules/is_numeric.yml
@@ -0,0 +1,25 @@
+id: is_numeric_1
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: is.numeric($VAR) || is.integer($VAR)
+    - pattern: is.integer($VAR) || is.numeric($VAR)
+message: is.numeric(x) || is.integer(x) can be simplified to is.numeric(x). Use
+    is.double(x) to test for objects stored as 64-bit floating point.
+
+---
+
+id: is_numeric_2
+language: r
+severity: warning
+rule:
+  any:
+    - pattern:
+        context: class($VAR) %in% c("numeric", "integer")
+        strictness: ast
+    - pattern:
+        context: class($VAR) %in% c("integer", "numeric")
+        strictness: ast
+message: class(x) %in% c("numeric", "integer") can be simplified to is.numeric(x). Use
+    is.double(x) to test for objects stored as 64-bit floating point.
diff --git a/flint/rules/length_levels.yml b/flint/rules/length_levels.yml
new file mode 100644
index 00000000..e1421dfc
--- /dev/null
+++ b/flint/rules/length_levels.yml
@@ -0,0 +1,7 @@
+id: length_levels_1
+language: r
+severity: warning
+rule:
+  pattern: length(levels($VAR))
+fix: nlevels(~~VAR~~)
+message: nlevels(x) is better than length(levels(x)). df
diff --git a/flint/rules/length_test.yml b/flint/rules/length_test.yml
new file mode 100644
index 00000000..26b77083
--- /dev/null
+++ b/flint/rules/length_test.yml
@@ -0,0 +1,59 @@
+# Strangely, having something like pattern: length($VAR $OP $VAR2) doesn't work
+
+id: length_test_1
+language: r
+severity: warning
+rule:
+  pattern: length($VAR == $VAR2)
+fix: length(~~VAR~~) == ~~VAR2~~
+message: Checking the length of a logical vector is likely a mistake.
+
+---
+
+id: length_test_2
+language: r
+severity: warning
+rule:
+  pattern: length($VAR != $VAR2)
+fix: length(~~VAR~~) != ~~VAR2~~
+message: Checking the length of a logical vector is likely a mistake.
+
+---
+
+id: length_test_3
+language: r
+severity: warning
+rule:
+  pattern: length($VAR > $VAR2)
+fix: length(~~VAR~~) > ~~VAR2~~
+message: Checking the length of a logical vector is likely a mistake.
+
+---
+
+id: length_test_4
+language: r
+severity: warning
+rule:
+  pattern: length($VAR >= $VAR2)
+fix: length(~~VAR~~) >= ~~VAR2~~
+message: Checking the length of a logical vector is likely a mistake.
+
+---
+
+id: length_test_5
+language: r
+severity: warning
+rule:
+  pattern: length($VAR < $VAR2)
+fix: length(~~VAR~~) < ~~VAR2~~
+message: Checking the length of a logical vector is likely a mistake.
+
+---
+
+id: length_test_6
+language: r
+severity: warning
+rule:
+  pattern: length($VAR <= $VAR2)
+fix: length(~~VAR~~) <= ~~VAR2~~
+message: Checking the length of a logical vector is likely a mistake.
diff --git a/flint/rules/lengths.yml b/flint/rules/lengths.yml
new file mode 100644
index 00000000..a4164402
--- /dev/null
+++ b/flint/rules/lengths.yml
@@ -0,0 +1,59 @@
+id: sapply_lengths-1
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: sapply($MYVAR, length)
+    - pattern: sapply(FUN = length, $MYVAR)
+    - pattern: sapply($MYVAR, FUN = length)
+    - pattern: vapply($MYVAR, length $$$)
+
+    - pattern: map_dbl($MYVAR, length)
+    - pattern: map_dbl($MYVAR, .f = length)
+    - pattern: map_dbl(.f = length, $MYVAR)
+    - pattern: map_int($MYVAR, length)
+    - pattern: map_int($MYVAR, .f = length)
+    - pattern: map_int(.f = length, $MYVAR)
+
+    - pattern: purrr::map_dbl($MYVAR, length)
+    - pattern: purrr::map_dbl($MYVAR, .f = length)
+    - pattern: purrr::map_dbl(.f = length, $MYVAR)
+    - pattern: purrr::map_int($MYVAR, length)
+    - pattern: purrr::map_int($MYVAR, .f = length)
+    - pattern: purrr::map_int(.f = length, $MYVAR)
+fix: lengths(~~MYVAR~~)
+message: Use lengths() to find the length of each element in a list.
+
+---
+
+id: sapply_lengths-2
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: $MYVAR |> sapply(length)
+    - pattern: $MYVAR |> sapply(FUN = length)
+    - pattern: $MYVAR |> vapply(length $$$)
+    - pattern: $MYVAR |> map_int(length)
+    - pattern: $MYVAR |> map_int(length $$$)
+    - pattern: $MYVAR |> purrr::map_int(length)
+    - pattern: $MYVAR |> purrr::map_int(length $$$)
+fix: ~~MYVAR~~ |> lengths()
+message: Use lengths() to find the length of each element in a list.
+
+---
+
+id: sapply_lengths-3
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: $MYVAR %>% sapply(length)
+    - pattern: $MYVAR %>% sapply(FUN = length)
+    - pattern: $MYVAR %>% vapply(length $$$)
+    - pattern: $MYVAR %>% map_int(length)
+    - pattern: $MYVAR %>% map_int(length $$$)
+    - pattern: $MYVAR %>% purrr::map_int(length)
+    - pattern: $MYVAR %>% purrr::map_int(length $$$)
+fix: ~~MYVAR~~ %>% lengths()
+message: Use lengths() to find the length of each element in a list.
diff --git a/flint/rules/library_call.yml b/flint/rules/library_call.yml
new file mode 100644
index 00000000..ef14d540
--- /dev/null
+++ b/flint/rules/library_call.yml
@@ -0,0 +1,26 @@
+id: library_call
+language: r
+severity: warning
+rule:
+  kind: call
+  has:
+    regex: ^library|require$
+    kind: identifier
+  follows:
+    not:
+      any:
+        - kind: call
+          has:
+            regex: ^library|require$
+            kind: identifier
+        - kind: comment
+  not:
+    inside:
+      any:
+        - kind: function_definition
+        - kind: call
+          has:
+            pattern: suppressPackageStartupMessages
+            kind: identifier
+message: Move all library/require calls to the top of the script.
+
diff --git a/flint/rules/literal_coercion.yml b/flint/rules/literal_coercion.yml
new file mode 100644
index 00000000..e61fb24a
--- /dev/null
+++ b/flint/rules/literal_coercion.yml
@@ -0,0 +1,89 @@
+id: literal_coercion-1
+language: r
+severity: warning
+rule:
+  pattern: $FUN($VALUE)
+constraints:
+  VALUE:
+    kind: argument
+    has:
+      kind: float
+    not:
+      regex: 'e'
+  FUN:
+    regex: ^(int|as\.integer)$
+fix: ~~VALUE~~L
+message: |
+  Use ~~VALUE~~L instead of ~~FUN~~(~~VALUE~~), i.e., use literals directly
+  where possible, instead of coercion.
+
+---
+
+id: literal_coercion-2
+language: r
+severity: warning
+rule:
+  pattern: as.character(NA)
+fix: NA_character_
+message: |
+  Use NA_character_ instead of as.character(NA), i.e., use literals directly
+  where possible, instead of coercion.
+
+---
+
+id: literal_coercion-3
+language: r
+severity: warning
+rule:
+  pattern: as.logical($VAR)
+constraints:
+  VAR:
+    kind: argument
+    has:
+      any:
+        - regex: ^1L$
+        - regex: ^1$
+        - regex: 'true'
+fix: TRUE
+message: Use TRUE instead of as.logical(~~VAR~~).
+
+---
+
+id: literal_coercion-4
+language: r
+severity: warning
+rule:
+  pattern: $FUN($VAR)
+constraints:
+  VAR:
+    kind: argument
+    has:
+      kind: float
+  FUN:
+    regex: ^(as\.numeric|as\.double)$
+fix: ~~VAR~~
+message: Use ~~VAR~~ instead of ~~FUN~~(~~VAR~~).
+
+---
+
+id: literal_coercion-5
+language: r
+severity: warning
+rule:
+  pattern: as.integer(NA)
+fix: NA_integer_
+message: Use NA_integer_ instead of as.integer(NA).
+
+---
+
+id: literal_coercion-6
+language: r
+severity: warning
+rule:
+  pattern: $FUN(NA)
+constraints:
+  FUN:
+    regex: ^(as\.numeric|as\.double)$
+fix: NA_real_
+message: Use NA_real_ instead of ~~FUN~~(NA).
+
diff --git a/flint/rules/matrix_apply.yml b/flint/rules/matrix_apply.yml
new file mode 100644
index 00000000..bbc68505
--- /dev/null
+++ b/flint/rules/matrix_apply.yml
@@ -0,0 +1,110 @@
+id: matrix_apply-1
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: apply($INPUT, 2, sum)
+    - pattern: apply($INPUT, MARGIN = 2, sum)
+    - pattern: apply($INPUT, 2, FUN = sum)
+    - pattern: apply($INPUT, MARGIN = 2, FUN = sum)
+fix: colSums(~~INPUT~~)
+message: Use colSums(x) rather than apply(x, 1, sum)
+
+---
+
+id: matrix_apply-2
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: apply($INPUT, 2, sum, na.rm = $NARM)
+    - pattern: apply($INPUT, MARGIN = 2, sum, na.rm = $NARM)
+    - pattern: apply($INPUT, 2, FUN = sum, na.rm = $NARM)
+    - pattern: apply($INPUT, MARGIN = 2, FUN = sum, na.rm = $NARM)
+fix: colSums(~~INPUT~~, na.rm = ~~NARM~~)
+message: Use colSums(x, na.rm = ~~NARM~~) rather than apply(x, 2, sum, na.rm = ~~NARM~~).
+
+---
+
+id: matrix_apply-3
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: apply($INPUT, 1, sum)
+    - pattern: apply($INPUT, MARGIN = 1, sum)
+    - pattern: apply($INPUT, 1, FUN = sum)
+    - pattern: apply($INPUT, MARGIN = 1, FUN = sum)
+fix: rowSums(~~INPUT~~)
+message: Use rowSums(x) rather than apply(x, 1, sum)
+
+---
+
+id: matrix_apply-4
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: apply($INPUT, 1, sum, na.rm = $NARM)
+    - pattern: apply($INPUT, MARGIN = 1, sum, na.rm = $NARM)
+    - pattern: apply($INPUT, 1, FUN = sum, na.rm = $NARM)
+    - pattern: apply($INPUT, MARGIN = 1, FUN = sum, na.rm = $NARM)
+fix: rowSums(~~INPUT~~, na.rm = ~~NARM~~)
+message: Use rowSums(x, na.rm = ~~NARM~~) rather than apply(x, 1, sum, na.rm = ~~NARM~~).
+
+---
+
+id: matrix_apply-5
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: apply($INPUT, 1, mean)
+    - pattern: apply($INPUT, MARGIN = 1, mean)
+    - pattern: apply($INPUT, 1, FUN = mean)
+    - pattern: apply($INPUT, MARGIN = 1, FUN = mean)
+fix: rowMeans(~~INPUT~~)
+message: Use rowMeans(x) rather than apply(x, 1, mean).
+
+---
+
+id: matrix_apply-6
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: apply($INPUT, 1, mean, na.rm = $NARM)
+    - pattern: apply($INPUT, MARGIN = 1, mean, na.rm = $NARM)
+    - pattern: apply($INPUT, 1, FUN = mean, na.rm = $NARM)
+    - pattern: apply($INPUT, MARGIN = 1, FUN = mean, na.rm = $NARM)
+fix: rowMeans(~~INPUT~~, na.rm = ~~NARM~~)
+message: Use rowMeans(x, na.rm = ~~NARM~~) rather than apply(x, 1, mean, na.rm = ~~NARM~~).
+
+---
+
+id: matrix_apply-7
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: apply($INPUT, 2, mean)
+    - pattern: apply($INPUT, MARGIN = 2, mean)
+    - pattern: apply($INPUT, 2, FUN = mean)
+    - pattern: apply($INPUT, MARGIN = 2, FUN = mean)
+fix: colMeans(~~INPUT~~)
+message: Use colMeans(x) rather than apply(x, 2, mean).
+
+---
+
+id: matrix_apply-8
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: apply($INPUT, 2, mean, na.rm = $NARM)
+    - pattern: apply($INPUT, MARGIN = 2, mean, na.rm = $NARM)
+    - pattern: apply($INPUT, 2, FUN = mean, na.rm = $NARM)
+    - pattern: apply($INPUT, MARGIN = 2, FUN = mean, na.rm = $NARM)
+fix: colMeans(~~INPUT~~, na.rm = ~~NARM~~)
+message: Use colMeans(x, na.rm = ~~NARM~~) rather than apply(x, 2, mean, na.rm = ~~NARM~~).
+
diff --git a/flint/rules/missing_argument.yml b/flint/rules/missing_argument.yml
new file mode 100644
index 00000000..9f47d17a
--- /dev/null
+++ b/flint/rules/missing_argument.yml
@@ -0,0 +1,44 @@
+id: missing_argument-1
+language: r
+severity: warning
+rule:
+  kind: arguments
+  has:
+    kind: comma
+    any:
+      - precedes:
+          stopBy: neighbor
+          any:
+            - regex: '^\)$'
+            - kind: comma
+      - follows:
+          any:
+            - regex: '^\($'
+            - kind: argument
+              regex: '=$'
+  follows:
+    kind: identifier
+    not:
+      regex: '^(quote|switch|alist)$'
+    inside:
+      kind: call
+message: Missing argument in function call.
+
+---
+
+id: missing_argument-2
+language: r
+severity: warning
+rule:
+  kind: arguments
+  regex: '=(\s+|)\)$'
+  follows:
+    any:
+      - kind: identifier
+      - kind: extract_operator
+      - kind: namespace_operator
+    not:
+      regex: '^(quote|switch|alist)$'
+    inside:
+      kind: call
+message: Missing argument in function call.
diff --git a/flint/rules/nested_ifelse.yml b/flint/rules/nested_ifelse.yml
new file mode 100644
index 00000000..64dcb08e
--- /dev/null
+++ b/flint/rules/nested_ifelse.yml
@@ -0,0 +1,29 @@
+id: nested_ifelse-1
+language: r
+severity: warning
+rule:
+  pattern: $FUN($COND, $TRUE, $FALSE)
+constraints:
+  FALSE:
+    regex: ^(ifelse|if_else|fifelse)
+  FUN:
+    regex: ^(ifelse|if_else|fifelse)
+message: |
+  Don't use nested ~~FUN~~() calls; instead, try (1) data.table::fcase;
+  (2) dplyr::case_when; or (3) using a lookup table.
+
+---
+
+id: nested_ifelse-2
+language: r
+severity: warning
+rule:
+  pattern: $FUN($COND, $TRUE, $FALSE)
+constraints:
+  TRUE:
+    regex: ^(ifelse|if_else|fifelse)
+  FUN:
+    regex: ^(ifelse|if_else|fifelse)
+message: |
+  Don't use nested ~~FUN~~() calls; instead, try (1) data.table::fcase;
+  (2) dplyr::case_when; or (3) using a lookup table.
diff --git a/flint/rules/numeric_leading_zero.yml b/flint/rules/numeric_leading_zero.yml
new file mode 100644
index 00000000..51807870
--- /dev/null
+++ b/flint/rules/numeric_leading_zero.yml
@@ -0,0 +1,11 @@
+id: numeric_leading_zero_1
+language: r
+severity: warning
+rule:
+  pattern: $VALUE
+  any:
+    - kind: float
+    - kind: identifier
+  regex: ^\.[0-9]
+fix: 0~~VALUE~~
+message: Include the leading zero for fractional numeric constants.
diff --git a/flint/rules/outer_negation.yml b/flint/rules/outer_negation.yml
new file mode 100644
index 00000000..ca377de3
--- /dev/null
+++ b/flint/rules/outer_negation.yml
@@ -0,0 +1,29 @@
+id: outer_negation-1
+language: r
+severity: warning
+rule:
+  pattern: all(!$VAR)
+constraints:
+  VAR:
+    not:
+      regex: '^!'
+fix: '!any(~~VAR~~)'
+message: |
+  !any(x) is better than all(!x). The former applies negation only once after
+  aggregation instead of many times for each element of x.
+
+---
+
+id: outer_negation-2
+language: r
+severity: warning
+rule:
+  pattern: any(! $VAR)
+constraints:
+  VAR:
+    not:
+      regex: '^!'
+fix: '!all(~~VAR~~)'
+message: |
+  !all(x) is better than any(!x). The former applies negation only once after
+  aggregation instead of many times for each element of x.
diff --git a/flint/rules/package_hooks.yml b/flint/rules/package_hooks.yml
new file mode 100644
index 00000000..f4dfa756
--- /dev/null
+++ b/flint/rules/package_hooks.yml
@@ -0,0 +1,127 @@
+id: package_hooks-1
+language: r
+severity: warning
+rule:
+  pattern: packageStartupMessage($$$)
+  inside:
+    stopBy: end
+    kind: binary_operator
+    has:
+      stopBy: end
+      field: lhs
+      pattern: .onLoad
+message: Put packageStartupMessage() calls in .onAttach(), not .onLoad().
+
+---
+
+id: package_hooks-2
+language: r
+severity: warning
+rule:
+  pattern: library.dynam($$$)
+  inside:
+    stopBy: end
+    kind: binary_operator
+    has:
+      stopBy: end
+      field: lhs
+      pattern: .onAttach
+message: Put library.dynam() calls in .onLoad(), not .onAttach().
+
+---
+
+id: package_hooks-3
+language: r
+severity: warning
+rule:
+  pattern: $FN($$$)
+  inside:
+    stopBy: end
+    kind: binary_operator
+    has:
+      stopBy: end
+      field: lhs
+      pattern: .onLoad
+constraints:
+  FN:
+    regex: '^(cat|installed.packages|message|packageStartupMessage|print|writeLines)$'
+message: Don't use ~~FN~~() in .onLoad().
+
+---
+
+id: package_hooks-4
+language: r
+severity: warning
+rule:
+  pattern: $FN($$$)
+  inside:
+    stopBy: end
+    kind: binary_operator
+    has:
+      stopBy: end
+      field: lhs
+      pattern: .onAttach
+constraints:
+  FN:
+    # library.dynam already has its own linter
+    regex: '^(cat|installed.packages|message|print|writeLines)$'
+message: Don't use ~~FN~~() in .onAttach().
+
+---
+
+id: package_hooks-5
+language: r
+severity: warning
+rule:
+  pattern: $FN($$$)
+  inside:
+    stopBy: end
+    kind: binary_operator
+    has:
+      stopBy: end
+      field: lhs
+      pattern: $LOAD
+constraints:
+  LOAD:
+    regex: '^(\.onAttach|\.onLoad)$'
+  FN:
+    regex: '^(require|library)$'
+message: Don't alter the search() path in ~~LOAD~~() by calling ~~FN~~().
+
+---
+
+id: package_hooks-6
+language: r
+severity: warning
+rule:
+  pattern: installed.packages($$$)
+  inside:
+    stopBy: end
+    kind: binary_operator
+    has:
+      stopBy: end
+      field: lhs
+      pattern: $LOAD
+constraints:
+  LOAD:
+    regex: '^(\.onAttach|\.onLoad)$'
+message: Don't slow down package load by running installed.packages() in ~~LOAD~~().
+
+---
+
+id: package_hooks-7
+language: r
+severity: warning
+rule:
+  pattern: library.dynam.unload($$$)
+  inside:
+    stopBy: end
+    kind: binary_operator
+    has:
+      stopBy: end
+      field: lhs
+      pattern: $LOAD
+constraints:
+  LOAD:
+    regex: '^(\.onDetach|\.Last\.lib)$'
+message: Use library.dynam.unload() calls in .onUnload(), not ~~LOAD~~().
diff --git a/flint/rules/paste.yml b/flint/rules/paste.yml
new file mode 100644
index 00000000..0d4faed3
--- /dev/null
+++ b/flint/rules/paste.yml
@@ -0,0 +1,75 @@
+id: paste_1
+language: r
+severity: warning
+rule:
+  pattern:
+    context: paste($$$CONTENT sep = "" $$$CONTENT2)
+    strictness: ast
+# fix: paste0($$$CONTENT)
+message: paste0(...) is better than paste(..., sep = "").
+
+---
+
+id: paste_2
+language: r
+severity: warning
+rule:
+  any:
+    - pattern:
+        context: paste($CONTENT, collapse = ", ")
+        strictness: ast
+    - pattern:
+        context: paste(collapse = ", ", $CONTENT)
+        strictness: ast
+# fix: paste0($$$CONTENT)
+message: toString(.) is more expressive than paste(., collapse = ", ").
+
+---
+
+id: paste_3
+language: r
+severity: warning
+rule:
+  pattern:
+    context: paste0($$$CONTENT sep = $USELESS $$$CONTENT2)
+    strictness: ast
+# fix: paste0($$$CONTENT)
+message: |
+  sep= is not a formal argument to paste0(); did you mean to use paste(), or
+  collapse=?
+
+---
+
+id: paste_4
+language: r
+severity: warning
+rule:
+  any:
+    - pattern:
+        context: paste0($CONTENT, collapse = $FOO)
+        strictness: ast
+    - pattern:
+        context: paste0(collapse = $FOO, $CONTENT)
+        strictness: ast
+  not:
+    has:
+      regex: sep
+      kind: argument
+# fix: paste0($$$CONTENT)
+message: |
+  Use paste(), not paste0(), to collapse a character vector when sep= is not used.
+
+# ---
+#
+# id: paste_5
+# language: r
+# severity: warning
+# rule:
+#   pattern:
+#     context: paste0(rep($VAR, $TIMES), collapse = "")
+#     strictness: ast
+# constraints:
+#   VAR:
+#     kind: string
+# fix: strrep(~~VAR~~, ~~TIMES~~)
+# message: strrep(x, times) is better than paste0(rep(x, times), collapse = "").
diff --git a/flint/rules/redundant_equals.yml b/flint/rules/redundant_equals.yml
new file mode 100644
index 00000000..79a6abcf
--- /dev/null
+++ b/flint/rules/redundant_equals.yml
@@ -0,0 +1,29 @@
+id: redundant_equals-1
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: $VAR == TRUE
+    - pattern: TRUE == $VAR
+    - pattern: $VAR == FALSE
+    - pattern: FALSE == $VAR
+message: |
+  Using == on a logical vector is redundant. Well-named logical vectors can be
+  used directly in filtering. For data.table's `i` argument, wrap the column
+  name in (), like `DT[(is_treatment)]`.
+
+---
+
+id: redundant_equals-2
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: $VAR != TRUE
+    - pattern: TRUE != $VAR
+    - pattern: $VAR != FALSE
+    - pattern: FALSE != $VAR
+message: |
+  Using != on a logical vector is redundant. Well-named logical vectors can be
+  used directly in filtering. For data.table's `i` argument, wrap the column
+  name in (), like `DT[(is_treatment)]`.
diff --git a/flint/rules/redundant_ifelse.yml b/flint/rules/redundant_ifelse.yml
new file mode 100644
index 00000000..e2528cfd
--- /dev/null
+++ b/flint/rules/redundant_ifelse.yml
@@ -0,0 +1,67 @@
+id: redundant_ifelse_1
+language: r
+severity: warning
+rule:
+  pattern: $FUN($COND, $VAL1, $VAL2)
+constraints:
+  VAL1:
+    regex: ^TRUE$
+  VAL2:
+    regex: ^FALSE$
+  FUN:
+    regex: ^(ifelse|fifelse|if_else)$
+fix: ~~COND~~
+message: |
+  Use ~~COND~~ directly instead of calling ~~FUN~~(~~COND~~, TRUE, FALSE).
+
+---
+
+id: redundant_ifelse_2
+language: r
+severity: warning
+rule:
+  pattern: $FUN($COND, $VAL1, $VAL2)
+constraints:
+  VAL1:
+    regex: ^FALSE$
+  VAL2:
+    regex: ^TRUE$
+  FUN:
+    regex: ^(ifelse|fifelse|if_else)$
+fix: !(~~COND~~)
+message: |
+  Use !(~~COND~~) directly instead of calling ~~FUN~~(~~COND~~, FALSE, TRUE).
+
+---
+
+id: redundant_ifelse_3
+language: r
+severity: warning
+rule:
+  pattern: $FUN($COND, $VAL1, $VAL2)
+constraints:
+  VAL1:
+    regex: ^(1|1L)$
+  VAL2:
+    regex: ^(0|0L)$
+  FUN:
+    regex: ^(ifelse|fifelse|if_else)$
+fix: as.integer(~~COND~~)
+message: Prefer as.integer(~~COND~~) to ~~FUN~~(~~COND~~, ~~VAL1~~, ~~VAL2~~).
+
+---
+
+id: redundant_ifelse_4
+language: r
+severity: warning
+rule:
+  pattern: $FUN($COND, $VAL1, $VAL2)
+constraints:
+  VAL1:
+    regex: ^(0|0L)$
+  VAL2:
+    regex: ^(1|1L)$
+  FUN:
+    regex: ^(ifelse|fifelse|if_else)$
+fix: as.integer(!(~~COND~~))
+message: Prefer as.integer(!(~~COND~~)) to ~~FUN~~(~~COND~~, ~~VAL1~~, ~~VAL2~~).
diff --git a/flint/rules/right_assignment.yml b/flint/rules/right_assignment.yml
new file mode 100644
index 00000000..76b736e9
--- /dev/null
+++ b/flint/rules/right_assignment.yml
@@ -0,0 +1,10 @@
+id: right_assignment
+language: r
+severity: hint
+rule:
+  pattern: $RHS -> $LHS
+  has:
+    field: rhs
+    kind: identifier
+fix: ~~LHS~~<- ~~RHS~~
+message: Use <-, not ->, for assignment.
diff --git a/flint/rules/semicolon.yml b/flint/rules/semicolon.yml
new file mode 100644
index 00000000..ff2e63b4
--- /dev/null
+++ b/flint/rules/semicolon.yml
@@ -0,0 +1,10 @@
+id: semicolon_1
+language: r
+severity: warning
+rule:
+  regex: ;\s+$
+  not:
+    inside:
+      kind: string
+      stopBy: end
+message: Trailing semicolons are not needed.
diff --git a/flint/rules/seq.yml b/flint/rules/seq.yml
new file mode 100644
index 00000000..87f39689
--- /dev/null
+++ b/flint/rules/seq.yml
@@ -0,0 +1,121 @@
+id: seq_1
+language: r
+severity: warning
+rule:
+  pattern: seq(length($VAR))
+fix: seq_along(~~VAR~~)
+message: |
+  seq(length(...)) is likely to be wrong in the empty edge case. Use seq_along(...) instead.
+
+---
+
+id: seq_2
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: 1:nrow($VAR)
+    - pattern: 1L:nrow($VAR)
+  regex: ^1
+fix: seq_len(nrow(~~VAR~~))
+message: |
+  1:nrow(...) is likely to be wrong in the empty edge case. Use seq_len(nrow(...)) instead.
+
+---
+
+id: seq_3
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: 1:n()
+    - pattern: 1L:n()
+  regex: ^1
+fix: seq_len(n())
+message: |
+  1:n() is likely to be wrong in the empty edge case. Use seq_len(n()) instead.
+
+---
+
+id: seq_4
+language: r
+severity: warning
+rule:
+  pattern: seq(nrow($VAR))
+fix: seq_len(nrow(~~VAR~~))
+message: |
+  seq(nrow(...)) is likely to be wrong in the empty edge case. Use seq_len(nrow(...)) instead.
+
+---
+
+id: seq_5
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: 1:length($VAR)
+    - pattern: 1L:length($VAR)
+  regex: ^1
+fix: seq_along(~~VAR~~)
+message: |
+  1:length(...) is likely to be wrong in the empty edge case. Use seq_along(...) instead.
+
+---
+
+id: seq_6
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: 1:ncol($VAR)
+    - pattern: 1L:ncol($VAR)
+  regex: ^1
+fix: seq_len(ncol(~~VAR~~))
+message: |
+  1:ncol(...) is likely to be wrong in the empty edge case. Use seq_len(ncol(...)) instead.
+
+---
+
+id: seq_7
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: 1:NCOL($VAR)
+    - pattern: 1L:NCOL($VAR)
+  regex: ^1
+fix: seq_len(NCOL(~~VAR~~))
+message: |
+  1:NCOL(...) is likely to be wrong in the empty edge case. Use seq_len(NCOL(...)) instead.
+
+---
+
+id: seq_8
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: 1:NROW($VAR)
+    - pattern: 1L:NROW($VAR)
+  regex: ^1
+fix: seq_len(NROW(~~VAR~~))
+message: |
+  1:NROW(...) is likely to be wrong in the empty edge case. Use seq_len(NROW(...)) instead.
+
+
+---
+
+id: seq_9
+language: r
+severity: warning
+rule:
+  pattern: seq(1, $VAL)
+  not:
+    pattern: seq(1, 0)
+constraints:
+  VAL:
+    regex: ^\d+(|L)$
+fix: seq_len(~~VAL~~)
+message: seq_len(~~VAL~~) is more efficient than seq(1, ~~VAL~~).
+
+
diff --git a/flint/rules/sort.yml b/flint/rules/sort.yml
new file mode 100644
index 00000000..930f5c6d
--- /dev/null
+++ b/flint/rules/sort.yml
@@ -0,0 +1,85 @@
+id: sort-1
+language: r
+severity: warning
+rule:
+  pattern: $OBJ[order($OBJ)]
+fix: sort(~~OBJ~~, na.last = TRUE)
+message: sort(~~OBJ~~, na.last = TRUE) is better than ~~OBJ~~[order(~~OBJ~~)].
+
+---
+
+id: sort-2
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: $OBJ[order($OBJ, decreasing = $DECREASING)]
+    - pattern: $OBJ[order(decreasing = $DECREASING, $OBJ)]
+constraints:
+  DECREASING:
+    regex: ^(TRUE|FALSE)$
+fix: sort(~~OBJ~~, decreasing = ~~DECREASING~~, na.last = TRUE)
+message: |
+  sort(~~OBJ~~, decreasing = ~~DECREASING~~, na.last = TRUE) is better than
+  ~~OBJ~~[order(~~OBJ~~, decreasing = ~~DECREASING~~)].
+
+---
+
+id: sort-3
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: $OBJ[order($OBJ, na.last = $NALAST)]
+    - pattern: $OBJ[order(na.last = $NALAST, $OBJ)]
+constraints:
+  NALAST:
+    regex: ^(TRUE|FALSE)$
+fix: sort(~~OBJ~~, na.last = ~~NALAST~~, na.last = TRUE)
+message: |
+  sort(~~OBJ~~, na.last = ~~NALAST~~, na.last = TRUE) is better than
+  ~~OBJ~~[order(~~OBJ~~, na.last = ~~NALAST~~)].
+
+---
+
+id: sort-4
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: $OBJ[order($OBJ, decreasing = TRUE, na.last = FALSE)]
+    - pattern: $OBJ[order($OBJ, na.last = FALSE, decreasing = TRUE)]
+    - pattern: $OBJ[order(decreasing = TRUE, $OBJ, na.last = FALSE)]
+    - pattern: $OBJ[order(decreasing = TRUE, na.last = FALSE, $OBJ)]
+    - pattern: $OBJ[order(na.last = FALSE, decreasing = TRUE, $OBJ)]
+    - pattern: $OBJ[order(na.last = FALSE, $OBJ, decreasing = TRUE)]
+fix: sort(~~OBJ~~, decreasing = TRUE, na.last = FALSE)
+message: |
+  sort(~~OBJ~~, decreasing = TRUE, na.last = FALSE) is better than
+  ~~OBJ~~[order(~~OBJ~~, na.last = FALSE, decreasing = TRUE)].
+
+---
+
+id: sort-5
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: sort($OBJ) == $OBJ
+    - pattern: $OBJ == sort($OBJ)
+fix: !is.unsorted(~~OBJ~~)
+message: |
+  Use !is.unsorted(~~OBJ~~) to test the sortedness of a vector.
+
+---
+
+id: sort-6
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: sort($OBJ) != $OBJ
+    - pattern: $OBJ != sort($OBJ)
+fix: is.unsorted(~~OBJ~~)
+message: |
+  Use is.unsorted(~~OBJ~~) to test the unsortedness of a vector.
diff --git a/flint/rules/todo_comment.yml b/flint/rules/todo_comment.yml
new file mode 100644
index 00000000..83d86edf
--- /dev/null
+++ b/flint/rules/todo_comment.yml
@@ -0,0 +1,7 @@
+id: todo_comment-1
+language: r
+severity: warning
+rule:
+  kind: comment
+  regex: '(?i)#(|\s+)\b(todo|fixme)\b'
+message: Remove TODO comments.
diff --git a/flint/rules/undesirable_function.yml b/flint/rules/undesirable_function.yml
new file mode 100644
index 00000000..c9b17562
--- /dev/null
+++ b/flint/rules/undesirable_function.yml
@@ -0,0 +1,13 @@
+id: undesirable_function-1
+language: r
+severity: warning
+rule:
+  pattern: $FUN
+  kind: identifier
+  not:
+    inside:
+      kind: argument
+constraints:
+  FUN:
+    regex: ^(\.libPaths|attach|browser|debug|debugcall|debugonce|detach|par|setwd|structure|Sys\.setenv|Sys\.setlocale|trace|undebug|untrace)$
+message: Function "~~FUN~~()" is undesirable.
diff --git a/flint/rules/undesirable_operator.yml b/flint/rules/undesirable_operator.yml
new file mode 100644
index 00000000..7d635137
--- /dev/null
+++ b/flint/rules/undesirable_operator.yml
@@ -0,0 +1,29 @@
+id: undesirable_operator-1
+language: r
+severity: warning
+rule:
+  any:
+    - pattern: $X <<- $Y
+    - pattern: $X ->> $Y
+message: |
+  Avoid undesirable operators `<<-` and `->>`. They assign outside the current
+  environment in a way that can be hard to reason about. Prefer fully-encapsulated
+  functions wherever possible, or, if necessary, assign to a specific environment
+  with assign(). Recall that you can create an environment at the desired scope
+  with new.env().
+
+---
+
+id: undesirable_operator-2
+language: r
+severity: warning
+rule:
+  kind: namespace_operator
+  has:
+    pattern: ':::'
+message: |
+  Operator `:::` is undesirable. It accesses non-exported functions inside
+  packages. Code relying on these is likely to break in future versions of the
+  package because the functions are not part of the public interface and may be
+  changed or removed by the maintainers without notice. Use public functions
+  via :: instead.
diff --git a/flint/rules/unnecessary_nesting.yml b/flint/rules/unnecessary_nesting.yml
new file mode 100644
index 00000000..ac08090b
--- /dev/null
+++ b/flint/rules/unnecessary_nesting.yml
@@ -0,0 +1,31 @@
+id: unnecessary_nesting-1
+language: r
+severity: warning
+rule:
+  kind: if_statement
+  any:
+    - has:
+        kind: 'braced_expression'
+        field: consequence
+        has:
+          kind: if_statement
+          stopBy: neighbor
+        not:
+          any:
+            - has:
+                nthChild: 2
+            - precedes:
+                regex: "^else$"
+    - has:
+        kind: if_statement
+        field: consequence
+        stopBy: neighbor
+  # Can be in if(), but not else if()
+  not:
+    inside:
+      field: alternative
+      kind: if_statement
+message: |
+  Don't use nested `if` statements, where a single `if` with the combined
+  conditional expression will do. For example, instead of `if (x) { if (y) { ... }}`,
+  use `if (x && y) { ... }`.
diff --git a/flint/rules/unreachable_code.yml b/flint/rules/unreachable_code.yml
new file mode 100644
index 00000000..56eb4974
--- /dev/null
+++ b/flint/rules/unreachable_code.yml
@@ -0,0 +1,64 @@
+id: unreachable_code-1
+language: r
+severity: warning
+rule:
+  regex: '[^}]+'
+  not:
+    regex: 'else'
+  follows:
+    any:
+      - pattern: return($$$A)
+      - pattern: stop($$$A)
+    not:
+      precedes:
+        regex: 'else'
+    stopBy: end
+message: Code and comments coming after a return() or stop() should be removed.
+
+---
+
+id: unreachable_code-2
+language: r
+severity: warning
+rule:
+  regex: '[^}]+'
+  not:
+    regex: 'else'
+  follows:
+    any:
+      - pattern: next
+      - pattern: break
+    stopBy: end
+message: Remove code and comments coming after `next` or `break`
+
+---
+
+id: unreachable_code-3
+language: r
+severity: warning
+rule:
+  inside:
+    any:
+      - kind: if_statement
+        pattern: if (FALSE)
+      - kind: while_statement
+        pattern: while (FALSE)
+    stopBy: end
+message: Remove code inside a conditional loop with a deterministically false condition.
+
+---
+
+id: unreachable_code-4
+language: r
+severity: warning
+rule:
+  inside:
+    any:
+      - kind: if_statement
+        pattern: if (TRUE)
+      - kind: while_statement
+        pattern: while (TRUE)
+    stopBy: end
+message: |
+  One branch has a a deterministically true condition. The other branches can
+  be removed.