Skip to content

Commit e8f1aff

Browse files
committed
Improve readline prompt detection in browser sessions
posit-dev/positron#4742
1 parent 70b5a59 commit e8f1aff

File tree

1 file changed

+15
-16
lines changed

1 file changed

+15
-16
lines changed

crates/ark/src/interface.rs

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ use harp::r_symbol;
7373
use harp::routines::r_register_routines;
7474
use harp::session::r_traceback;
7575
use harp::utils::r_is_data_frame;
76-
use harp::utils::r_pairlist_any;
7776
use harp::utils::r_typeof;
7877
use harp::R_MAIN_THREAD_ID;
7978
use libr::R_BaseNamespace;
@@ -121,6 +120,8 @@ use crate::startup;
121120
use crate::strings::lines;
122121
use crate::sys::console::console_to_utf8;
123122

123+
static RE_DEBUG_PROMPT: Lazy<Regex> = Lazy::new(|| Regex::new(r"Browse\[\d+\]").unwrap());
124+
124125
/// An enum representing the different modes in which the R session can run.
125126
#[derive(PartialEq, Clone)]
126127
pub enum SessionMode {
@@ -844,28 +845,26 @@ impl RMain {
844845
let prompt_slice = unsafe { CStr::from_ptr(prompt_c) };
845846
let prompt = prompt_slice.to_string_lossy().into_owned();
846847

847-
// Detect browser prompts by inspecting the `RDEBUG` flag of each
848-
// frame on the stack. If ANY of the frames are marked with `RDEBUG`,
849-
// then we assume we are in a debug state. We can't just check the
850-
// last frame, as sometimes frames are pushed onto the stack by lazy
851-
// evaluation of arguments or `tryCatch()` that aren't debug frames,
852-
// but we don't want to exit the debugger when we hit these, as R is
853-
// still inside a browser state. Should also handle cases like `debug(readline)`
854-
// followed by `n`.
855-
// https://github.com/posit-dev/positron/issues/2310
856-
let frames = harp::session::r_sys_frames().unwrap();
857-
let browser = r_pairlist_any(frames.sexp, |frame| {
858-
harp::session::r_env_is_browsed(frame).unwrap()
859-
});
848+
// Detect browser prompt by matching the prompt string
849+
// https://github.com/posit-dev/positron/issues/4742.
850+
// There are ways to break this detection, for instance setting
851+
// `options(prompt =, continue = ` to something that looks like
852+
// a browser prompt, or doing the same with `readline()`. We have
853+
// chosen to not support these edge cases.
854+
let browser = RE_DEBUG_PROMPT.is_match(&prompt);
860855

861856
// If there are frames on the stack and we're not in a browser prompt,
862857
// this means some user code is requesting input, e.g. via `readline()`
863858
let user_request = !browser && n_frame > 0;
864859

865860
// The request is incomplete if we see the continue prompt, except if
866-
// we're in a user request, e.g. `readline("+ ")`
861+
// we're in a user request, e.g. `readline("+ ")`. To guard against
862+
// this, we check that we are at top-level (call stack is empty or we
863+
// have a debug prompt).
867864
let continuation_prompt: String = harp::get_option("continue").try_into().unwrap();
868-
let incomplete = !user_request && prompt == continuation_prompt;
865+
let matches_continuation = prompt == continuation_prompt;
866+
let top_level = n_frame == 0 || browser;
867+
let incomplete = matches_continuation && top_level;
869868

870869
return PromptInfo {
871870
input_prompt: prompt,

0 commit comments

Comments
 (0)