Skip to content

Commit

Permalink
Use nframe() to detect prompts like readline()
Browse files Browse the repository at this point in the history
  • Loading branch information
lionel- committed Jun 23, 2023
1 parent 80180a1 commit 76b1027
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 8 deletions.
26 changes: 19 additions & 7 deletions crates/ark/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,17 +309,29 @@ pub struct PromptInfo {
}

fn prompt_info(prompt_c: *const c_char) -> PromptInfo {
let n_frame = unwrap!(harp::session::r_n_frame(), Err(err) => {
warn!("`r_n_frame()` failed: {}", err);
0
});
trace!("prompt_info(): n_frame = '{}'", n_frame);

let prompt_slice = unsafe { CStr::from_ptr(prompt_c) };
let prompt = prompt_slice.to_string_lossy().into_owned();

// The request is incomplete if we see the continue prompt
let continue_prompt = unsafe { r_get_option::<String>("continue").unwrap() };
let incomplete = prompt == continue_prompt;
// TODO: Detect with `env_is_browsed(sys.frame(sys.nframe()))`
let browser = false;

// If the current prompt doesn't match the default prompt, assume that
// we're reading use input, e.g. via 'readline()'.
let default_prompt = unsafe { r_get_option::<String>("prompt").unwrap() };
let user_request = !incomplete && prompt != default_prompt;
// If there are frames on the stack and we're not in a browser prompt,
// this means some user code is requesting input, e.g. via `readline()`
let user_request = !browser && n_frame > 0;

// The request is incomplete if we see the continue prompt, except if
// we're in a user request, e.g. `readline("+ ")`
let continue_prompt = unwrap!(unsafe { r_get_option::<String>("continue") }, Err(err) => {
warn!("`r_get_option()` failed: {}", err);
String::from("+ ")
});
let incomplete = !user_request && prompt == continue_prompt;

if incomplete {
trace!("Got R prompt '{}', marking request incomplete", prompt);
Expand Down
3 changes: 2 additions & 1 deletion crates/harp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub mod lock;
pub mod object;
pub mod protect;
pub mod routines;
pub mod session;
pub mod string;
pub mod symbol;
pub mod test;
Expand Down Expand Up @@ -162,7 +163,7 @@ macro_rules! r_lang {

($($tts:tt)*) => {{
let value = $crate::r_pairlist!($($tts)*);
libR_sys::SET_TYPEOF(value, LISTSXP as i32);
libR_sys::SET_TYPEOF(value, LANGSXP as i32);
value
}}

Expand Down
36 changes: 36 additions & 0 deletions crates/harp/src/session.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// session.rs
//
// Copyright (C) 2023 Posit Software, PBC. All rights reserved.
//
//

use std::sync::Once;

use libR_sys::*;

use crate::utils::r_try_eval_silent;
use crate::vector::integer_vector::IntegerVector;
use crate::vector::Vector;

pub fn r_n_frame() -> crate::error::Result<i32> {
SESSION_INIT.call_once(init_interface);

unsafe {
let ffi = r_try_eval_silent(NFRAME_CALL as SEXP, R_BaseEnv)?;
let n_frame = IntegerVector::new(ffi)?;
Ok(n_frame.get_unchecked_elt(0))
}
}

// Globals
static SESSION_INIT: Once = Once::new();
static mut NFRAME_CALL: usize = 0;

fn init_interface() {
unsafe {
let nframe_call = crate::r_lang!(crate::r_symbol!("sys.nframe"));
R_PreserveObject(nframe_call);
NFRAME_CALL = nframe_call as usize;
}
}

0 comments on commit 76b1027

Please sign in to comment.