mod banner;
mod editor_setup;
pub(super) mod history;
mod history_runtime;
mod meta_command;
mod pager_ui;
mod prompt;
mod r_mainloop;
mod read_console;
pub(crate) mod reprex;
mod shell;
mod signals;
mod standalone;
pub(crate) mod state;
mod terminal;
use crate::completion::completer::CombinedCompleter;
use crate::completion::menu::{FunctionAwareMenu, StateSyncHistoryMenu};
use crate::completion::shell::ShellCompleter;
use crate::config::{
AutoSuggestions, Config, ConfigFileInfo, EditorMode, FormatterBackend, HelpViewer,
ModeIndicatorPosition, RSourceStatus, ReprexMode, ResolvedHistoryLocation,
};
use crate::editor::hinter::RLanguageHinter;
use crate::editor::mode::new_editor_state_ref;
use crate::editor::prompt::PromptFormatter;
use crate::highlighter::{CombinedHighlighter, MetaCommandHighlighter};
use crate::history::HistoryRuntime;
use anyhow::Result;
use crossterm::{ExecutableCommand, style::Stylize};
use nu_ansi_term::{Color, Style};
use reedline::{
AutoPairs, DefaultHinter, HistorySessionId, IdeMenu, ListMenu, MenuBuilder, Reedline,
ReedlineMenu, Signal,
};
use std::cell::RefCell;
use std::collections::HashMap;
use std::io;
use crate::editor::validator::RValidator;
use banner::format_banner;
use history::finalize_history;
#[cfg(test)]
#[allow(unused_imports)]
use history::setup_history;
use meta_command::{
MetaAction, MetaCommandContext, SessionInfoContext, handle_meta_command_result,
process_meta_command,
};
use prompt::RPrompt;
use read_console::read_console_callback;
use reprex::ReprexRuntime;
use reprex::{clear_input_lines, strip_reprex_output};
use shell::execute_shell_command;
pub(crate) use signals::install_r_interrupt_handler;
#[cfg(unix)]
pub(crate) use signals::restore_default_sigint_handler;
use state::{PendingHistoryContext, PromptRuntimeConfig, ReplState};
use terminal::sync_r_width;
thread_local! {
pub(super) static REPL_STATE: RefCell<Option<ReplState>> = const { RefCell::new(None) };
}
pub(crate) const ARF_PREFIX: &str = "# [arf]";
macro_rules! arf_println {
($($arg:tt)*) => {
println!("{} {}", $crate::repl::ARF_PREFIX, format_args!($($arg)*))
};
}
macro_rules! arf_eprintln {
($($arg:tt)*) => {
eprintln!("{} {}", $crate::repl::ARF_PREFIX, format_args!($($arg)*))
};
}
pub(crate) use arf_eprintln;
pub(crate) use arf_println;
pub struct Repl {
config: Config,
history_location: ResolvedHistoryLocation,
formatter_backend: Option<FormatterBackend>,
config_file_info: ConfigFileInfo,
r_source_status: RSourceStatus,
override_notice: Option<String>,
r_home: Option<std::path::PathBuf>,
r_initialized: bool,
prompt_formatter: PromptFormatter,
session_id: Option<HistorySessionId>,
prepared_r_history: Option<HistoryRuntime>,
prepared_shell_history: Option<HistoryRuntime>,
}
impl Repl {
pub fn new(
config: Config,
config_file_info: ConfigFileInfo,
r_source_status: RSourceStatus,
override_notice: Option<String>,
r_home: Option<std::path::PathBuf>,
session_id: Option<HistorySessionId>,
) -> Result<Self> {
let history_location = crate::config::resolved_history_location(&config.history.mode);
let formatter_backend =
crate::external::formatter::resolve_formatter(config.reprex.formatter);
let r_initialized = arf_libr::r_library().is_ok();
let prompt_formatter = PromptFormatter::new();
if config.startup.reprex != ReprexMode::Off {
arf_libr::set_reprex_mode(true, &config.reprex.comment);
}
Ok(Repl {
config,
history_location,
formatter_backend,
config_file_info,
r_source_status,
override_notice,
r_home,
r_initialized,
prompt_formatter,
session_id,
prepared_r_history: None,
prepared_shell_history: None,
})
}
pub(crate) fn r_home_for_ipc(&self) -> Option<String> {
self.r_home.as_ref().map(|path| path.display().to_string())
}
pub fn run(&mut self) -> Result<()> {
self.prepare_history();
if self.config.startup.show_banner {
let banner = format_banner(
&self.config,
self.r_initialized,
self.override_notice.as_deref(),
self.formatter_backend,
);
if !self.r_initialized {
for line in banner.lines() {
if line.contains("R is not initialized") {
println!(
"# {}",
"R is not initialized. Commands will not be evaluated.".yellow()
);
} else {
println!("{}", line);
}
}
} else {
print!("{}", banner);
}
} else if self.r_initialized
&& let Some(notice) = &self.override_notice
{
eprintln!("{notice}");
}
if self.r_initialized {
self.run_with_r_mainloop()?;
} else {
self.run_standalone()?;
}
Ok(())
}
}