use super::*;
impl Repl {
pub(super) fn run_with_r_mainloop(&self) -> Result<()> {
let (line_editor, r_history_handle) = self.create_r_line_editor();
let (shell_line_editor, shell_history_handle) = self.create_shell_line_editor();
let prompt_config = PromptRuntimeConfig::builder(
self.prompt_formatter.clone(),
self.config.prompt.format.clone(),
self.config.prompt.continuation.clone(),
self.config.prompt.shell_format.clone(),
)
.mode_indicator_position(self.config.prompt.mode_indicator)
.indicators(self.config.prompt.indicators.clone())
.main_color(self.config.colors.prompt.main)
.continuation_color(self.config.colors.prompt.continuation)
.shell_color(self.config.colors.prompt.shell)
.mode_indicator_color(self.config.colors.prompt.indicator)
.status(
self.config.prompt.status.clone(),
self.config.colors.prompt.status.clone(),
)
.duration(
self.config.experimental.prompt_duration.clone(),
self.config.colors.prompt.duration,
)
.spinner(self.config.experimental.prompt_spinner.clone())
.vi(
self.config.prompt.vi.clone(),
self.config.colors.prompt.vi.clone(),
)
.build();
REPL_STATE.with(|state| {
*state.borrow_mut() = Some(ReplState {
line_editor,
shell_line_editor,
prompt_config,
reprex: ReprexRuntime::from_resolved(
self.config.startup.reprex,
self.config.reprex.comment.clone(),
self.config.reprex.formatter,
self.formatter_backend,
),
should_exit: false,
r_prompt_options_ambiguous: false,
config_file_info: self.config_file_info.clone(),
r_source_status: self.r_source_status.clone(),
r_home: self.r_home.clone(),
history_location: self.history_location.clone(),
forget_config: self.config.experimental.history_forget.clone(),
sponge_queue: state::SpongeQueue::new(),
dir_stack: Vec::new(),
history_session_id: if r_history_handle.is_available() {
self.session_id
} else {
None
},
r_history: r_history_handle,
shell_history: shell_history_handle,
pending_history_context: PendingHistoryContext::None,
error_handler_setup_attempted: false,
});
});
#[cfg(unix)]
{
let askpass_handler_code = arf_libr::askpass_handler_code();
match arf_harp::eval_string_with_visibility(askpass_handler_code) {
Ok(_) => {
log::info!("Askpass handler initialized");
}
Err(e) => {
log::warn!("Failed to initialize askpass handler: {:?}", e);
}
}
}
if self.config.r.auto_width {
sync_r_width();
}
if should_install_help_submit_wrapper(self.config.experimental.r_help.viewer) {
match arf_harp::help_bridge::install_help_submit_wrapper() {
Ok(arf_harp::help_bridge::HelpSubmitInstallOutcome::Installed) => {
log::info!("Native R help pager integration installed");
}
Ok(arf_harp::help_bridge::HelpSubmitInstallOutcome::SkippedExistingMethod) => {
log::info!(
"Native R help pager integration skipped: a custom print method is active"
);
}
Err(error) => {
log::warn!(
"Native R help pager integration unavailable; retaining R help output: {error:?}"
);
}
}
} else {
log::debug!("Native R help pager integration disabled by configuration");
}
arf_libr::set_read_console_callback(read_console_callback);
unsafe {
arf_libr::run_r_mainloop();
}
REPL_STATE.with(|state| {
if let Some(ref mut repl_state) = *state.borrow_mut()
&& repl_state.forget_config.enabled
&& !repl_state.sponge_queue.is_empty()
{
for id_to_delete in repl_state.sponge_queue.drain_failed_ids() {
if let Some(store) = repl_state.r_history.store() {
let _ = store.delete(id_to_delete);
}
}
if let Some(store) = repl_state.r_history.store() {
let _ = store.sync();
}
}
});
REPL_STATE.with(|state| {
*state.borrow_mut() = None;
});
println!("\nGoodbye!");
Ok(())
}
}
fn should_install_help_submit_wrapper(viewer: super::HelpViewer) -> bool {
viewer == super::HelpViewer::Auto
}
#[cfg(test)]
mod tests {
use super::should_install_help_submit_wrapper;
use crate::config::HelpViewer;
#[test]
fn r_help_viewer_does_not_install_native_submit_wrapper() {
assert!(!should_install_help_submit_wrapper(HelpViewer::R));
assert!(should_install_help_submit_wrapper(HelpViewer::Auto));
}
}