Perhaps not the most elegant, but this seems to do what I think you're asking for.
First, two notes:
I'm adding browser(); 1
, knowing it doesn't work right away. The ;1
is because browser()
will exit immediately if there is not some code after it. If there's something after the if/else
block then you might not need it, but it's there for this. (This is only necessary with emacs/ESS: https://github.com/emacs-ess/ESS/issues/178)
I added a variable within the foo
environment to demonstrate that we don't (then do) see it.
First, the failing attempt:
maybeBrowser <- function (msg) {
if (interactive()) {
cat(msg, "\n")
browser()
q
} else {
stop(msg)
}
}
foo <- function (cond, ...) {
cat(capture.output(environment()), "\n")
in_foo <- 1
if (cond) maybeBrowser("What a mess")
}
foo(TRUE)
# <environment: 0x000000001b2beba0>
# What a mess
# Called from: maybeBrowser("What a mess")
# Browse[1]>
debug at #5: q
# Browse[2]>
environment()
# <environment: 0x000000001b280030> <---- this is different
# Browse[2]>
ls()
# [1] "msg"
Now a tweak to the code, motivated by https://stackoverflow.com/a/23891089/3358272
maybeBrowser <- function (msg) {
if (interactive()) {
cat(msg, "\n")
return(evalq(browser(skipCalls=1), envir=parent.frame()))
} else {
stop(msg)
}
}
foo <- function (cond, ...) {
cat(capture.output(environment()), "\n")
in_foo <- 1
if (cond) maybeBrowser("What a mess")
}
foo(TRUE)
# <environment: 0x000000001b0b9d40>
# What a mess
# Called from: eval(quote({
# browser()
# 1
# ...
# Browse[1]>
debug at #4: [1] 1
# Browse[3]>
environment()
# <environment: 0x000000001b0b9d40> <---- this is now the same
# Browse[3]>
ls()
# [1] "cond" "in_foo"
However, this is not allowing you to continue, stepping through any following code in foo
, so it is an incomplete answer. I think unfortunately that that may not be feasible ... but perhaps a more internals-cognizant R bubba will have more clarity on this.