1pub use super::highlight::{HighlightDebugSpan, debug_highlight};
33pub(crate) use super::history_store::expand_history;
34pub use super::history_store::{
35 HistoryConfig, HistoryConfigBuilder, HistoryEntry, HistoryShellContext, SharedHistory,
36};
37use crate::completion::CompletionTree;
38use anyhow::Result;
39
40mod adapter;
41mod config;
42mod debug;
43mod editor;
44mod overlay;
45mod session;
46
47pub(crate) use adapter::{
48 CompletionTraceEvent, CompletionTraceMenuState, trace_completion, trace_completion_enabled,
49};
50#[cfg(test)]
51pub(crate) use adapter::{
52 ReplCompleter, ReplHistoryCompleter, build_repl_highlighter, expand_home, path_suggestions,
53 split_path_stub,
54};
55pub use adapter::{color_from_style_spec, default_pipe_verbs};
56pub use config::{
57 LineProjection, LineProjector, PromptRightRenderer, ReplAppearance, ReplAppearanceBuilder,
58 ReplInputMode, ReplLineResult, ReplPrompt, ReplReloadKind, ReplRunConfig, ReplRunConfigBuilder,
59 ReplRunResult,
60};
61pub use debug::{
62 CompletionDebug, CompletionDebugFrame, CompletionDebugMatch, CompletionDebugOptions, DebugStep,
63 debug_completion, debug_completion_steps, debug_history_menu, debug_history_menu_steps,
64};
65#[cfg(test)]
66use editor::{
67 AutoCompleteEmacs, contains_cursor_position_report, is_cursor_position_error,
68 parse_cursor_position_report,
69};
70pub(crate) use editor::{BasicInputReason, OspPrompt, basic_input_reason};
71#[cfg(test)]
72use overlay::{build_history_menu, build_history_picker_options, history_picker_items};
73use session::{InteractiveLoopConfig, SubmissionContext, run_repl_basic, run_repl_interactive};
74#[cfg(test)]
75use session::{SubmissionResult, process_submission};
76
77const COMPLETION_MENU_NAME: &str = "completion_menu";
78const HISTORY_MENU_NAME: &str = "history_menu";
79const HOST_COMMAND_HISTORY_PICKER: &str = "\u{0}osp-repl-history-picker";
80
81struct ReplRunContext {
82 prompt: OspPrompt,
83 completion_words: Vec<String>,
84 completion_tree: Option<CompletionTree>,
85 appearance: ReplAppearance,
86 line_projector: Option<LineProjector>,
87 history_store: SharedHistory,
88}
89
90pub fn run_repl<F>(config: ReplRunConfig, mut execute: F) -> Result<ReplRunResult>
92where
93 F: FnMut(&str, &SharedHistory) -> Result<ReplLineResult>,
94{
95 let ReplRunConfig {
96 prompt,
97 completion_words,
98 completion_tree,
99 appearance,
100 history_config,
101 input_mode,
102 prompt_right,
103 line_projector,
104 } = config;
105 let history_store = SharedHistory::new(history_config)?;
106 let mut submission = SubmissionContext {
107 history_store: &history_store,
108 execute: &mut execute,
109 };
110 let prompt = OspPrompt::new(prompt.left, prompt.indicator, prompt_right);
111 let basic_reason = basic_input_reason(input_mode);
112
113 run_repl_with_reason(
114 ReplRunContext {
115 prompt,
116 completion_words,
117 completion_tree,
118 appearance,
119 line_projector,
120 history_store: history_store.clone(),
121 },
122 basic_reason,
123 &mut submission,
124 run_repl_basic,
125 run_repl_interactive,
126 )
127}
128
129fn run_repl_with_reason<F, B, I>(
130 context: ReplRunContext,
131 basic_reason: Option<BasicInputReason>,
132 submission: &mut SubmissionContext<'_, F>,
133 mut run_basic_fn: B,
134 mut run_interactive_fn: I,
135) -> Result<ReplRunResult>
136where
137 F: FnMut(&str, &SharedHistory) -> Result<ReplLineResult>,
138 B: FnMut(&OspPrompt, &mut SubmissionContext<'_, F>) -> Result<()>,
139 I: FnMut(
140 InteractiveLoopConfig<'_>,
141 SharedHistory,
142 &mut SubmissionContext<'_, F>,
143 ) -> Result<ReplRunResult>,
144{
145 let ReplRunContext {
146 prompt,
147 completion_words,
148 completion_tree,
149 appearance,
150 line_projector,
151 history_store,
152 } = context;
153
154 if let Some(reason) = basic_reason {
155 match reason {
156 BasicInputReason::NotATerminal => {
157 eprintln!("Warning: Input is not a terminal (fd=0).");
158 }
159 BasicInputReason::CursorProbeUnsupported => {
160 eprintln!(
161 "Warning: terminal does not support cursor position requests; using basic input mode."
162 );
163 }
164 BasicInputReason::Explicit => {}
165 }
166 run_basic_fn(&prompt, submission)?;
167 return Ok(ReplRunResult::Exit(0));
168 }
169
170 run_interactive_fn(
171 InteractiveLoopConfig {
172 prompt: &prompt,
173 completion_words,
174 completion_tree,
175 appearance,
176 line_projector,
177 },
178 history_store,
179 submission,
180 )
181}
182
183#[cfg(test)]
184mod tests;