Skip to content

Commit c2f2e12

Browse files
authored
Declare that we are in debug mode if any frame is marked with RDEBUG (#346)
1 parent c89a528 commit c2f2e12

File tree

3 files changed

+46
-9
lines changed

3 files changed

+46
-9
lines changed

crates/ark/src/interface.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ use harp::routines::r_register_routines;
7272
use harp::session::r_traceback;
7373
use harp::utils::r_get_option;
7474
use harp::utils::r_is_data_frame;
75+
use harp::utils::r_pairlist_any;
7576
use harp::utils::r_poke_option_show_error_messages;
7677
use harp::R_MAIN_THREAD_ID;
7778
use libr::R_BaseNamespace;
@@ -745,15 +746,19 @@ impl RMain {
745746
let prompt_slice = unsafe { CStr::from_ptr(prompt_c) };
746747
let prompt = prompt_slice.to_string_lossy().into_owned();
747748

748-
// Detect browser prompts by inspecting the `RDEBUG` flag of the
749-
// last frame on the stack. This is not 100% infallible, for
750-
// instance `debug(readline)` followed by `n` will instantiate a
751-
// user request prompt that will look like a browser prompt
752-
// according to this heuristic. However it has the advantage of
753-
// correctly detecting that continue prompts are top-level browser
754-
// prompts in case of incomplete inputs within `browser()`.
755-
let frame = harp::session::r_sys_frame(n_frame).unwrap();
756-
let browser = harp::session::r_env_is_browsed(frame).unwrap();
749+
// Detect browser prompts by inspecting the `RDEBUG` flag of each
750+
// frame on the stack. If ANY of the frames are marked with `RDEBUG`,
751+
// then we assume we are in a debug state. We can't just check the
752+
// last frame, as sometimes frames are pushed onto the stack by lazy
753+
// evaluation of arguments or `tryCatch()` that aren't debug frames,
754+
// but we don't want to exit the debugger when we hit these, as R is
755+
// still inside a browser state. Should also handle cases like `debug(readline)`
756+
// followed by `n`.
757+
// https://github.com/posit-dev/positron/issues/2310
758+
let frames = RObject::from(harp::session::r_sys_frames().unwrap());
759+
let browser = r_pairlist_any(frames.sexp, |frame| {
760+
harp::session::r_env_is_browsed(frame).unwrap()
761+
});
757762

758763
// If there are frames on the stack and we're not in a browser prompt,
759764
// this means some user code is requesting input, e.g. via `readline()`

crates/harp/src/object.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,16 @@ pub fn r_alloc_list(size: R_xlen_t) -> SEXP {
266266
unsafe { Rf_allocVector(VECSXP, size) }
267267
}
268268

269+
pub fn r_node_car(x: SEXP) -> SEXP {
270+
unsafe { CAR(x) }
271+
}
272+
pub fn r_node_tag(x: SEXP) -> SEXP {
273+
unsafe { TAG(x) }
274+
}
275+
pub fn r_node_cdr(x: SEXP) -> SEXP {
276+
unsafe { CDR(x) }
277+
}
278+
269279
impl RObject {
270280
pub unsafe fn new(data: SEXP) -> Self {
271281
RObject {

crates/harp/src/utils.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ use crate::object::r_chr_get;
3030
use crate::object::r_chr_poke;
3131
use crate::object::r_dim;
3232
use crate::object::r_length;
33+
use crate::object::r_node_car;
34+
use crate::object::r_node_cdr;
3335
use crate::object::r_str_blank;
3436
use crate::object::r_str_na;
3537
use crate::object::RObject;
@@ -660,6 +662,26 @@ pub unsafe fn r_ns_env_name(env: SEXP) -> SEXP {
660662
STRING_ELT(spec, 0)
661663
}
662664

665+
/// Returns `true` if `f` returns `true` for any node of the pairlist
666+
pub fn r_pairlist_any<F>(x: SEXP, f: F) -> bool
667+
where
668+
F: Fn(SEXP) -> bool,
669+
{
670+
let mut node = x;
671+
672+
while node != r_null() {
673+
let elt = r_node_car(node);
674+
675+
if f(elt) {
676+
return true;
677+
}
678+
679+
node = r_node_cdr(node);
680+
}
681+
682+
return false;
683+
}
684+
663685
pub unsafe fn r_try_eval_silent(x: SEXP, env: SEXP) -> Result<SEXP> {
664686
let mut errc = 0;
665687

0 commit comments

Comments
 (0)