From f178a4406bd87554cf1982b2a4dfe5f9559b26f1 Mon Sep 17 00:00:00 2001
From: Sebastian Funk <sebastian.funk@lshtm.ac.uk>
Date: Fri, 10 May 2024 09:44:42 +0100
Subject: [PATCH 1/5] print line numbers

---
 R/model.R | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/R/model.R b/R/model.R
index f9b8241c..f2c133cc 100644
--- a/R/model.R
+++ b/R/model.R
@@ -302,7 +302,16 @@ CmdStanModel <- R6::R6Class(
       if (length(private$stan_code_) == 0) {
         stop("'$print()' cannot be used because the 'CmdStanModel' was not created with a Stan file.", call. = FALSE)
       }
-      cat(self$code(), sep = "\n")
+      lines <- self$code()
+      line_num_indent <- nchar(as.character(length(lines)))
+      line_nums <- vapply(seq_along(lines), function(y) {
+        paste0(
+          rep(" ", line_num_indent - nchar(as.character(y))), y, collapse = ""
+        )
+      }, character(1))
+      cat(
+        paste(paste(line_nums, lines, sep = ": "), collapse = "\n"), sep = "\n"
+      )
       invisible(self)
     },
     stan_file = function() {

From bde2ed55692d491257aaf734907898b8166f1c18 Mon Sep 17 00:00:00 2001
From: Sebastian Funk <sebastian.funk@lshtm.ac.uk>
Date: Fri, 10 May 2024 10:52:11 +0100
Subject: [PATCH 2/5] update tests

---
 .../testthat/answers/model-print-output.stan  | 22 +++++++++----------
 tests/testthat/test-model-code-print.R        |  4 ++--
 2 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/tests/testthat/answers/model-print-output.stan b/tests/testthat/answers/model-print-output.stan
index 3b6099fc..0b04c379 100644
--- a/tests/testthat/answers/model-print-output.stan
+++ b/tests/testthat/answers/model-print-output.stan
@@ -1,11 +1,11 @@
-data {
-  int<lower=0> N;
-  array[N] int<lower=0, upper=1> y;
-}
-parameters {
-  real<lower=0, upper=1> theta;
-}
-model {
-  theta ~ beta(1, 1); // uniform prior on interval 0,1
-  y ~ bernoulli(theta);
-}
+ 1: data {
+ 2:   int<lower=0> N;
+ 3:   array[N] int<lower=0, upper=1> y;
+ 4: }
+ 5: parameters {
+ 6:   real<lower=0, upper=1> theta;
+ 7: }
+ 8: model {
+ 9:   theta ~ beta(1, 1); // uniform prior on interval 0,1
+10:   y ~ bernoulli(theta);
+11: }
diff --git a/tests/testthat/test-model-code-print.R b/tests/testthat/test-model-code-print.R
index e3409ed9..09f8eb19 100644
--- a/tests/testthat/test-model-code-print.R
+++ b/tests/testthat/test-model-code-print.R
@@ -50,16 +50,16 @@ test_that("code() doesn't change when file changes (unless model is recreated)",
 
   mod <- cmdstan_model(stan_file_1, compile = FALSE)
   expect_identical(mod$code(), code_1_answer)
-  expect_identical(utils::capture.output(mod$print()), code_1_answer)
+  code_1_print <- utils::capture.output(mod$print())
 
   # overwrite with new code, but mod$code() shouldn't change
   file.copy(stan_file_2, stan_file_1, overwrite = TRUE)
   expect_identical(mod$code(), code_1_answer)
+  expect_identical(utils::capture.output(mod$print()), code_1_print)
 
   # recreate CmdStanModel object, now mod$code() should change
   mod <- cmdstan_model(stan_file_1, compile = FALSE)
   expect_identical(mod$code(), code_2_answer)
-  expect_identical(utils::capture.output(mod$print()), code_2_answer)
 })
 
 test_that("code() warns and print() errors if only exe and no Stan file", {

From a74e51af519700434c632cd283e95a46f6c8755f Mon Sep 17 00:00:00 2001
From: Sebastian Funk <sebastian.funk@lshtm.ac.uk>
Date: Mon, 13 May 2024 09:09:41 +0100
Subject: [PATCH 3/5] Revert "update tests"

This reverts commit bde2ed55692d491257aaf734907898b8166f1c18.
---
 .../testthat/answers/model-print-output.stan  | 22 +++++++++----------
 tests/testthat/test-model-code-print.R        |  4 ++--
 2 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/tests/testthat/answers/model-print-output.stan b/tests/testthat/answers/model-print-output.stan
index 0b04c379..3b6099fc 100644
--- a/tests/testthat/answers/model-print-output.stan
+++ b/tests/testthat/answers/model-print-output.stan
@@ -1,11 +1,11 @@
- 1: data {
- 2:   int<lower=0> N;
- 3:   array[N] int<lower=0, upper=1> y;
- 4: }
- 5: parameters {
- 6:   real<lower=0, upper=1> theta;
- 7: }
- 8: model {
- 9:   theta ~ beta(1, 1); // uniform prior on interval 0,1
-10:   y ~ bernoulli(theta);
-11: }
+data {
+  int<lower=0> N;
+  array[N] int<lower=0, upper=1> y;
+}
+parameters {
+  real<lower=0, upper=1> theta;
+}
+model {
+  theta ~ beta(1, 1); // uniform prior on interval 0,1
+  y ~ bernoulli(theta);
+}
diff --git a/tests/testthat/test-model-code-print.R b/tests/testthat/test-model-code-print.R
index 09f8eb19..e3409ed9 100644
--- a/tests/testthat/test-model-code-print.R
+++ b/tests/testthat/test-model-code-print.R
@@ -50,16 +50,16 @@ test_that("code() doesn't change when file changes (unless model is recreated)",
 
   mod <- cmdstan_model(stan_file_1, compile = FALSE)
   expect_identical(mod$code(), code_1_answer)
-  code_1_print <- utils::capture.output(mod$print())
+  expect_identical(utils::capture.output(mod$print()), code_1_answer)
 
   # overwrite with new code, but mod$code() shouldn't change
   file.copy(stan_file_2, stan_file_1, overwrite = TRUE)
   expect_identical(mod$code(), code_1_answer)
-  expect_identical(utils::capture.output(mod$print()), code_1_print)
 
   # recreate CmdStanModel object, now mod$code() should change
   mod <- cmdstan_model(stan_file_1, compile = FALSE)
   expect_identical(mod$code(), code_2_answer)
+  expect_identical(utils::capture.output(mod$print()), code_2_answer)
 })
 
 test_that("code() warns and print() errors if only exe and no Stan file", {

From 3eaa74e25079c361631d77386cbb0ba6fe00a294 Mon Sep 17 00:00:00 2001
From: Sebastian Funk <sebastian.funk@lshtm.ac.uk>
Date: Mon, 13 May 2024 09:43:17 +0100
Subject: [PATCH 4/5] make line number printing optional

---
 R/model.R | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/R/model.R b/R/model.R
index f2c133cc..9e9e2058 100644
--- a/R/model.R
+++ b/R/model.R
@@ -298,20 +298,21 @@ CmdStanModel <- R6::R6Class(
       }
       private$stan_code_
     },
-    print = function() {
+    print = function(line_numbers = getOption("cmdstanr_print_line_numbers", FALSE)) {
       if (length(private$stan_code_) == 0) {
         stop("'$print()' cannot be used because the 'CmdStanModel' was not created with a Stan file.", call. = FALSE)
       }
       lines <- self$code()
-      line_num_indent <- nchar(as.character(length(lines)))
-      line_nums <- vapply(seq_along(lines), function(y) {
-        paste0(
-          rep(" ", line_num_indent - nchar(as.character(y))), y, collapse = ""
-        )
-      }, character(1))
-      cat(
-        paste(paste(line_nums, lines, sep = ": "), collapse = "\n"), sep = "\n"
-      )
+      if (line_numbers) {
+        line_num_indent <- nchar(as.character(length(lines)))
+        line_nums <- vapply(seq_along(lines), function(y) {
+          paste0(
+            rep(" ", line_num_indent - nchar(as.character(y))), y, collapse = ""
+          )
+        }, character(1))
+        lines <- paste(paste(line_nums, lines, sep = ": "), collapse = "\n")
+      }
+      cat(lines, sep = "\n")
       invisible(self)
     },
     stan_file = function() {

From 8e8e0f4d222f035bcd01572782fb95f5c3141281 Mon Sep 17 00:00:00 2001
From: Sebastian Funk <sebastian.funk@lshtm.ac.uk>
Date: Mon, 13 May 2024 09:43:31 +0100
Subject: [PATCH 5/5] add example

---
 R/model.R                       | 3 +++
 man/CmdStanModel.Rd             | 3 +++
 man/cmdstan_model.Rd            | 3 +++
 man/cmdstanr-package.Rd         | 3 +++
 man/model-method-optimize.Rd    | 3 +++
 man/model-method-pathfinder.Rd  | 3 +++
 man/model-method-sample.Rd      | 3 +++
 man/model-method-variational.Rd | 3 +++
 8 files changed, 24 insertions(+)

diff --git a/R/model.R b/R/model.R
index 9e9e2058..0a1cb1c1 100644
--- a/R/model.R
+++ b/R/model.R
@@ -54,6 +54,9 @@
 #' file <- file.path(cmdstan_path(), "examples/bernoulli/bernoulli.stan")
 #' mod <- cmdstan_model(file)
 #' mod$print()
+#' # Print with line numbers. This can be set globally using the
+#' # `cmdstanr_print_line_numbers` option.
+#' mod$print(line_numbers = TRUE)
 #'
 #' # Data as a named list (like RStan)
 #' stan_data <- list(N = 10, y = c(0,1,0,0,0,0,0,0,0,1))
diff --git a/man/CmdStanModel.Rd b/man/CmdStanModel.Rd
index 55200357..8bb3fdaf 100644
--- a/man/CmdStanModel.Rd
+++ b/man/CmdStanModel.Rd
@@ -73,6 +73,9 @@ set_cmdstan_path(path = NULL)
 file <- file.path(cmdstan_path(), "examples/bernoulli/bernoulli.stan")
 mod <- cmdstan_model(file)
 mod$print()
+# Print with line numbers. This can be set globally using the
+# `cmdstanr_print_line_numbers` option.
+mod$print(line_numbers = TRUE)
 
 # Data as a named list (like RStan)
 stan_data <- list(N = 10, y = c(0,1,0,0,0,0,0,0,0,1))
diff --git a/man/cmdstan_model.Rd b/man/cmdstan_model.Rd
index b0432abc..bca22a30 100644
--- a/man/cmdstan_model.Rd
+++ b/man/cmdstan_model.Rd
@@ -59,6 +59,9 @@ set_cmdstan_path(path = NULL)
 file <- file.path(cmdstan_path(), "examples/bernoulli/bernoulli.stan")
 mod <- cmdstan_model(file)
 mod$print()
+# Print with line numbers. This can be set globally using the
+# `cmdstanr_print_line_numbers` option.
+mod$print(line_numbers = TRUE)
 
 # Data as a named list (like RStan)
 stan_data <- list(N = 10, y = c(0,1,0,0,0,0,0,0,0,1))
diff --git a/man/cmdstanr-package.Rd b/man/cmdstanr-package.Rd
index 739213ff..eb8ae80c 100644
--- a/man/cmdstanr-package.Rd
+++ b/man/cmdstanr-package.Rd
@@ -89,6 +89,9 @@ set_cmdstan_path(path = NULL)
 file <- file.path(cmdstan_path(), "examples/bernoulli/bernoulli.stan")
 mod <- cmdstan_model(file)
 mod$print()
+# Print with line numbers. This can be set globally using the
+# `cmdstanr_print_line_numbers` option.
+mod$print(line_numbers = TRUE)
 
 # Data as a named list (like RStan)
 stan_data <- list(N = 10, y = c(0,1,0,0,0,0,0,0,0,1))
diff --git a/man/model-method-optimize.Rd b/man/model-method-optimize.Rd
index 55d7758f..ac8f9f65 100644
--- a/man/model-method-optimize.Rd
+++ b/man/model-method-optimize.Rd
@@ -245,6 +245,9 @@ set_cmdstan_path(path = NULL)
 file <- file.path(cmdstan_path(), "examples/bernoulli/bernoulli.stan")
 mod <- cmdstan_model(file)
 mod$print()
+# Print with line numbers. This can be set globally using the
+# `cmdstanr_print_line_numbers` option.
+mod$print(line_numbers = TRUE)
 
 # Data as a named list (like RStan)
 stan_data <- list(N = 10, y = c(0,1,0,0,0,0,0,0,0,1))
diff --git a/man/model-method-pathfinder.Rd b/man/model-method-pathfinder.Rd
index c3a2044b..90578282 100644
--- a/man/model-method-pathfinder.Rd
+++ b/man/model-method-pathfinder.Rd
@@ -270,6 +270,9 @@ set_cmdstan_path(path = NULL)
 file <- file.path(cmdstan_path(), "examples/bernoulli/bernoulli.stan")
 mod <- cmdstan_model(file)
 mod$print()
+# Print with line numbers. This can be set globally using the
+# `cmdstanr_print_line_numbers` option.
+mod$print(line_numbers = TRUE)
 
 # Data as a named list (like RStan)
 stan_data <- list(N = 10, y = c(0,1,0,0,0,0,0,0,0,1))
diff --git a/man/model-method-sample.Rd b/man/model-method-sample.Rd
index bc5b2a8c..9b0b1ac4 100644
--- a/man/model-method-sample.Rd
+++ b/man/model-method-sample.Rd
@@ -348,6 +348,9 @@ set_cmdstan_path(path = NULL)
 file <- file.path(cmdstan_path(), "examples/bernoulli/bernoulli.stan")
 mod <- cmdstan_model(file)
 mod$print()
+# Print with line numbers. This can be set globally using the
+# `cmdstanr_print_line_numbers` option.
+mod$print(line_numbers = TRUE)
 
 # Data as a named list (like RStan)
 stan_data <- list(N = 10, y = c(0,1,0,0,0,0,0,0,0,1))
diff --git a/man/model-method-variational.Rd b/man/model-method-variational.Rd
index 3892d886..417a647a 100644
--- a/man/model-method-variational.Rd
+++ b/man/model-method-variational.Rd
@@ -245,6 +245,9 @@ set_cmdstan_path(path = NULL)
 file <- file.path(cmdstan_path(), "examples/bernoulli/bernoulli.stan")
 mod <- cmdstan_model(file)
 mod$print()
+# Print with line numbers. This can be set globally using the
+# `cmdstanr_print_line_numbers` option.
+mod$print(line_numbers = TRUE)
 
 # Data as a named list (like RStan)
 stan_data <- list(N = 10, y = c(0,1,0,0,0,0,0,0,0,1))