From e8b86fe01b83a56631837ac439142460fb008e84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Mon, 15 Jul 2019 12:22:49 +0100 Subject: [PATCH] Document r_session$debug() --- R/r-session.R | 68 ++++++++++++++++++++++++++++++++++++++++++ R/utils.R | 4 +-- inst/WORDLIST | 2 ++ man/r_session.Rd | 8 +++++ man/r_session_debug.Rd | 60 +++++++++++++++++++++++++++++++++++++ 5 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 man/r_session_debug.Rd diff --git a/R/r-session.R b/R/r-session.R index e0cf96e4..641f1097 100644 --- a/R/r-session.R +++ b/R/r-session.R @@ -25,6 +25,8 @@ #' rs$close(grace = 1000) #' #' rs$traceback() +#' rs$debug() +#' rs$attach() #' ``` #' #' @section Arguments: @@ -84,6 +86,12 @@ #' equivalent to the [traceback()] call, but it is performed in the #' subprocess. #' +#' `rs$debug()` is an interactive debugger to inspect the dumped frames +#' in the subprocess, after an error. See more at [r_session_debug]. +#' +#' `rs$attach()` is an experimental function that provides a REPL +#' (Read-Eval-Print-Loop) to the subprocess. +#' #' @name r_session #' @examples #' \dontrun{ @@ -710,3 +718,63 @@ r_session_options_default <- function() { extra = list() ) } + +#' Interactive debugging of persistent R sessions +#' +#' The `r_session$debug()` method is an interactive debugger to inspect +#' the stack of the background process after an error. +#' +#' `$debug()` starts a REPL (Read-Eval-Print-Loop), that evaluates R +#' expressions in the subprocess. It is similar to [browser()] and +#' [debugger()] and also has some extra commands: +#' +#' * `.help` prints a short help message. +#' * `.where` prints the complete stack trace of the error. (The same as +#' the `$traceback()` method. +#' * `.inspect ` switches the "focus" to frame ``. Frame 0 is the +#' global environment, so `.inspect 0` will switch back to that. +#' +#' To exit the debugger, press the usual interrupt key, i.e. `CTRL+c` or +#' `ESC` in some GUIs. +#' +#' Here is an example session that uses `$debug()` (some output is omitted +#' for brevity): +#' +#' ``` +#' # ---------------------------------------------------------------------- +#' > rs <- r_session$new() +#' > rs$run(function() knitr::knit("no-such-file")) +#' Error in rs_run(self, private, func, args) : +#' callr subprocess failed: cannot open the connection +#' +#' > rs$debug() +#' Debugging in process 87361, press CTRL+C (ESC) to quit. Commands: +#' .where -- print stack trace +#' .inspect -- inspect a frame, 0 resets to .GlobalEnv +#' .help -- print this message +#' -- run in frame or .GlobalEnv +#' +#' 3: file(con, "r") +#' 2: readLines(input2, encoding = "UTF-8", warn = FALSE) +#' 1: knitr::knit("no-such-file") at #1 +#' +#' RS 87361 > .inspect 1 +#' +#' RS 87361 (frame 1) > ls() +#' [1] "encoding" "envir" "ext" "in.file" "input" "input.dir" +#' [7] "input2" "ocode" "oconc" "oenvir" "oopts" "optc" +#' [13] "optk" "otangle" "out.purl" "output" "quiet" "tangle" +#' [19] "text" +#' +#' RS 87361 (frame 1) > input +#' [1] "no-such-file" +#' +#' RS 87361 (frame 1) > file.exists(input) +#' [1] FALSE +#' +#' RS 87361 (frame 1) > # +#' # ---------------------------------------------------------------------- +#' ``` +#' +#' @name r_session_debug +NULL diff --git a/R/utils.R b/R/utils.R index c90a33ae..763a7ca1 100644 --- a/R/utils.R +++ b/R/utils.R @@ -108,7 +108,7 @@ bold <- function(x) { update_history <- function(cmd) { tmp <- tempfile() on.exit(unlink(tmp, recursive = TRUE)) - savehistory(tmp) + utils::savehistory(tmp) cat(cmd, "\n", sep = "", file = tmp, append = TRUE) - loadhistory(tmp) + utils::loadhistory(tmp) } diff --git a/inst/WORDLIST b/inst/WORDLIST index 37d0606d..96494015 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -1,5 +1,6 @@ cliapp CMD +Eval finalizer igraph interruptible @@ -7,6 +8,7 @@ macOS pkgdown pollable processx +REPL subcommand subprocess subprocesses diff --git a/man/r_session.Rd b/man/r_session.Rd index 25c54823..29620b0f 100644 --- a/man/r_session.Rd +++ b/man/r_session.Rd @@ -28,6 +28,8 @@ rs$read() rs$close(grace = 1000) rs$traceback() +rs$debug() +rs$attach() } } @@ -94,6 +96,12 @@ The session object will be in \code{"finished"} state after this. `rs$traceback() can be used after an error in the R subprocess. It is equivalent to the \code{\link[=traceback]{traceback()}} call, but it is performed in the subprocess. + +\code{rs$debug()} is an interactive debugger to inspect the dumped frames +in the subprocess, after an error. See more at \link{r_session_debug}. + +\code{rs$attach()} is an experimental function that provides a REPL +(Read-Eval-Print-Loop) to the subprocess. } \examples{ diff --git a/man/r_session_debug.Rd b/man/r_session_debug.Rd new file mode 100644 index 00000000..8bb59f80 --- /dev/null +++ b/man/r_session_debug.Rd @@ -0,0 +1,60 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/r-session.R +\name{r_session_debug} +\alias{r_session_debug} +\title{Interactive debugging of persistent R sessions} +\description{ +The \code{r_session$debug()} method is an interactive debugger to inspect +the stack of the background process after an error. +} +\details{ +\code{$debug()} starts a REPL (Read-Eval-Print-Loop), that evaluates R +expressions in the subprocess. It is similar to \code{\link[=browser]{browser()}} and +\code{\link[=debugger]{debugger()}} and also has some extra commands: +\itemize{ +\item \code{.help} prints a short help message. +\item \code{.where} prints the complete stack trace of the error. (The same as +the \code{$traceback()} method. +\item \code{.inspect } switches the "focus" to frame \code{}. Frame 0 is the +global environment, so \code{.inspect 0} will switch back to that. +} + +To exit the debugger, press the usual interrupt key, i.e. \code{CTRL+c} or +\code{ESC} in some GUIs. + +Here is an example session that uses \code{$debug()} (some output is omitted +for brevity):\preformatted{# ---------------------------------------------------------------------- +> rs <- r_session$new() +> rs$run(function() knitr::knit("no-such-file")) +Error in rs_run(self, private, func, args) : + callr subprocess failed: cannot open the connection + +> rs$debug() +Debugging in process 87361, press CTRL+C (ESC) to quit. Commands: + .where -- print stack trace + .inspect -- inspect a frame, 0 resets to .GlobalEnv + .help -- print this message + -- run in frame or .GlobalEnv + +3: file(con, "r") +2: readLines(input2, encoding = "UTF-8", warn = FALSE) +1: knitr::knit("no-such-file") at #1 + +RS 87361 > .inspect 1 + +RS 87361 (frame 1) > ls() + [1] "encoding" "envir" "ext" "in.file" "input" "input.dir" + [7] "input2" "ocode" "oconc" "oenvir" "oopts" "optc" +[13] "optk" "otangle" "out.purl" "output" "quiet" "tangle" +[19] "text" + +RS 87361 (frame 1) > input +[1] "no-such-file" + +RS 87361 (frame 1) > file.exists(input) +[1] FALSE + +RS 87361 (frame 1) > # +# ---------------------------------------------------------------------- +} +}