pub use super::highlight::{HighlightDebugSpan, debug_highlight};
pub(crate) use super::history_store::expand_history;
pub use super::history_store::{
HistoryConfig, HistoryConfigBuilder, HistoryEntry, HistoryShellContext, SharedHistory,
};
use crate::completion::CompletionTree;
use anyhow::Result;
mod adapter;
mod config;
mod debug;
mod editor;
mod overlay;
mod session;
pub(crate) use adapter::{
CompletionTraceEvent, CompletionTraceMenuState, trace_completion, trace_completion_enabled,
};
#[cfg(test)]
pub(crate) use adapter::{
ReplCompleter, ReplHistoryCompleter, build_repl_highlighter, expand_home, path_suggestions,
split_path_stub,
};
pub use adapter::{color_from_style_spec, default_pipe_verbs};
pub use config::{
LineProjection, LineProjector, PromptRightRenderer, ReplAppearance, ReplAppearanceBuilder,
ReplInputMode, ReplLineResult, ReplPrompt, ReplReloadKind, ReplRunConfig, ReplRunConfigBuilder,
ReplRunResult,
};
pub use debug::{
CompletionDebug, CompletionDebugFrame, CompletionDebugMatch, CompletionDebugOptions, DebugStep,
debug_completion, debug_completion_steps, debug_history_menu, debug_history_menu_steps,
};
#[cfg(test)]
use editor::{
AutoCompleteEmacs, contains_cursor_position_report, is_cursor_position_error,
parse_cursor_position_report,
};
pub(crate) use editor::{BasicInputReason, OspPrompt, basic_input_reason};
#[cfg(test)]
use overlay::{build_history_menu, build_history_picker_options, history_picker_items};
use session::{InteractiveLoopConfig, SubmissionContext, run_repl_basic, run_repl_interactive};
#[cfg(test)]
use session::{SubmissionResult, evaluate_repl_submission};
const COMPLETION_MENU_NAME: &str = "completion_menu";
const HISTORY_MENU_NAME: &str = "history_menu";
const HOST_COMMAND_HISTORY_PICKER: &str = "\u{0}osp-repl-history-picker";
struct ReplRunContext {
prompt: OspPrompt,
completion_words: Vec<String>,
completion_tree: Option<CompletionTree>,
appearance: ReplAppearance,
line_projector: Option<LineProjector>,
history_store: SharedHistory,
}
pub fn run_repl<F>(config: ReplRunConfig, mut execute: F) -> Result<ReplRunResult>
where
F: FnMut(&str, &SharedHistory) -> Result<ReplLineResult>,
{
let ReplRunConfig {
prompt,
completion_words,
completion_tree,
appearance,
history_config,
input_mode,
prompt_right,
line_projector,
} = config;
let history_store = SharedHistory::new(history_config);
let mut submission = SubmissionContext {
history_store: &history_store,
execute: &mut execute,
};
let prompt = OspPrompt::new(prompt.left, prompt.indicator, prompt_right);
let basic_reason = basic_input_reason(input_mode);
run_repl_with_reason(
ReplRunContext {
prompt,
completion_words,
completion_tree,
appearance,
line_projector,
history_store: history_store.clone(),
},
basic_reason,
&mut submission,
run_repl_basic,
run_repl_interactive,
)
}
fn run_repl_with_reason<F, B, I>(
context: ReplRunContext,
basic_reason: Option<BasicInputReason>,
submission: &mut SubmissionContext<'_, F>,
mut run_basic_fn: B,
mut run_interactive_fn: I,
) -> Result<ReplRunResult>
where
F: FnMut(&str, &SharedHistory) -> Result<ReplLineResult>,
B: FnMut(&OspPrompt, &mut SubmissionContext<'_, F>) -> Result<ReplRunResult>,
I: FnMut(
InteractiveLoopConfig<'_>,
SharedHistory,
&mut SubmissionContext<'_, F>,
) -> Result<ReplRunResult>,
{
let ReplRunContext {
prompt,
completion_words,
completion_tree,
appearance,
line_projector,
history_store,
} = context;
if let Some(reason) = basic_reason {
match reason {
BasicInputReason::NotATerminal => {
eprintln!("Warning: Input is not a terminal (fd=0).");
}
BasicInputReason::CursorProbeUnsupported => {
eprintln!(
"Warning: terminal does not support cursor position requests; using basic input mode."
);
}
BasicInputReason::Explicit => {}
}
return run_basic_fn(&prompt, submission);
}
run_interactive_fn(
InteractiveLoopConfig {
prompt: &prompt,
completion_words,
completion_tree,
appearance,
line_projector,
},
history_store,
submission,
)
}
#[cfg(test)]
mod tests;