Allow overriding verbosity default via env var KORAP_VERBOSE

Change-Id: I8a2e32f24c22f2039b335cd000c610ba5ff3da08
diff --git a/NEWS.md b/NEWS.md
index 7e56600..b3ccfa3 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -3,6 +3,7 @@
 - `fetchAnnotations()` method added to `KorAPQuery` class, to fetch annotations for all collected matches
 - regional demo updated and extended with interactive highcharter plot
 - automatic documentation tests introduced (via copromted Readme.md and different LLMs)
+- allow overriding `KorAPConnection(verbose=)` default via env var `KORAP_VERBOSE` or R option `rkorap.verbose` (explicit argument still wins)
 
 # RKorAPClient 1.1.0
 
@@ -218,4 +219,3 @@
 - Fix reporting cached results in verbose mode.
 - Add demo for comparing frequencies in spoken vs. written virtual corpora. See `demo("writtenVsSpoken")`
 - Don't invalidate cache on patch level increments.
-
diff --git a/R/KorAPConnection.R b/R/KorAPConnection.R
index 2f1a809..f7b6af8 100644
--- a/R/KorAPConnection.R
+++ b/R/KorAPConnection.R
@@ -82,7 +82,9 @@
 #' @param userAgent user agent string. Defaults to "R-KorAP-Client".
 #' @param timeout timeout in seconds for API requests (this does not influence server internal timeouts). Defaults to 240 seconds.
 #' @param verbose logical that decides whether following operations will default to
-#'   be verbose. Defaults to FALSE.
+#'   be verbose. Defaults to FALSE. If not explicitly provided, this can be overridden
+#'   via environment variable `KORAP_VERBOSE` (accepted true-ish values: 1, true, yes, on)
+#'   or R option `rkorap.verbose` (logical).
 #' @param cache logical that decides if API calls are cached locally. You can clear
 #'   the cache with [clearCache()]. Defaults to TRUE.
 #'
@@ -148,6 +150,16 @@
   .Object@oauthScope <- oauthScope
   .Object@authorizationSupported <- authorizationSupported
   .Object@timeout <- timeout
+  # Allow environment/option override only if user did not pass `verbose`
+  if (missing(verbose)) {
+    ev <- Sys.getenv("KORAP_VERBOSE", unset = "")
+    if (nzchar(ev)) {
+      verbose <- tolower(ev) %in% c("1", "true", "t", "yes", "y", "on")
+    } else {
+      opt <- getOption("rkorap.verbose", NULL)
+      if (!is.null(opt)) verbose <- isTRUE(opt)
+    }
+  }
   .Object@verbose <- verbose
   .Object@cache <- cache
   .Object@welcome <- apiCall(.Object, .Object@apiUrl, json = FALSE, cache = FALSE, getHeaders = TRUE)
diff --git a/Readme.md b/Readme.md
index fe4835f..5c69ad7 100644
--- a/Readme.md
+++ b/Readme.md
@@ -24,6 +24,21 @@
 KorAPConnection(verbose=TRUE) |> corpusQuery("Hello world") |> fetchAll()
 ```
 
+### Verbose output without changing code
+
+You can turn on verbose logging globally without changing calls by setting an environment variable (or an R option):
+
+```r
+# Environment variable (recommended for sessions / ~/.Renviron)
+Sys.setenv(KORAP_VERBOSE = "true")
+KorAPConnection()  # uses verbose = TRUE
+
+# Alternatively, R option
+options(rkorap.verbose = TRUE)
+KorAPConnection()
+```
+Explicit `verbose` arguments still take precedence over these settings.
+
 ### Frequencies over time and domains using ggplot2
 
 ```r
diff --git a/man/KorAPConnection-class.Rd b/man/KorAPConnection-class.Rd
index ab0b7a1..3ccaae2 100644
--- a/man/KorAPConnection-class.Rd
+++ b/man/KorAPConnection-class.Rd
@@ -62,7 +62,9 @@
 \item{timeout}{timeout in seconds for API requests (this does not influence server internal timeouts). Defaults to 240 seconds.}
 
 \item{verbose}{logical that decides whether following operations will default to
-be verbose. Defaults to FALSE.}
+be verbose. Defaults to FALSE. If not explicitly provided, this can be overridden
+via environment variable \code{KORAP_VERBOSE} (accepted true-ish values: 1, true, yes, on)
+or R option \code{rkorap.verbose} (logical).}
 
 \item{cache}{logical that decides if API calls are cached locally. You can clear
 the cache with \code{\link[=clearCache]{clearCache()}}. Defaults to TRUE.}
diff --git a/tests/testthat/test-verbose-env.R b/tests/testthat/test-verbose-env.R
new file mode 100644
index 0000000..141c0dc
--- /dev/null
+++ b/tests/testthat/test-verbose-env.R
@@ -0,0 +1,21 @@
+test_that("KORAP_VERBOSE overrides verbose default and is restorable", {
+  old <- Sys.getenv("KORAP_VERBOSE", unset = NA_character_)
+  on.exit({
+    if (is.na(old)) Sys.unsetenv("KORAP_VERBOSE") else Sys.setenv(KORAP_VERBOSE = old)
+  }, add = TRUE)
+
+  # Turn on via env var
+  Sys.setenv(KORAP_VERBOSE = "true")
+  k1 <- KorAPConnection(accessToken = NULL)
+  expect_true(k1@verbose)
+
+  # Explicit argument takes precedence
+  k2 <- KorAPConnection(accessToken = NULL, verbose = FALSE)
+  expect_false(k2@verbose)
+
+  # Turn off via env var
+  Sys.setenv(KORAP_VERBOSE = "false")
+  k3 <- KorAPConnection(accessToken = NULL)
+  expect_false(k3@verbose)
+})
+