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, evaluate_repl_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>
107where
108 F: FnMut(&str, &SharedHistory) -> Result<ReplLineResult>,
109{
110 let ReplRunConfig {
111 prompt,
112 completion_words,
113 completion_tree,
114 appearance,
115 history_config,
116 input_mode,
117 prompt_right,
118 line_projector,
119 } = config;
120 let history_store = SharedHistory::new(history_config);
121 let mut submission = SubmissionContext {
122 history_store: &history_store,
123 execute: &mut execute,
124 };
125 let prompt = OspPrompt::new(prompt.left, prompt.indicator, prompt_right);
126 let basic_reason = basic_input_reason(input_mode);
127
128 run_repl_with_reason(
129 ReplRunContext {
130 prompt,
131 completion_words,
132 completion_tree,
133 appearance,
134 line_projector,
135 history_store: history_store.clone(),
136 },
137 basic_reason,
138 &mut submission,
139 run_repl_basic,
140 run_repl_interactive,
141 )
142}
143
144fn run_repl_with_reason<F, B, I>(
145 context: ReplRunContext,
146 basic_reason: Option<BasicInputReason>,
147 submission: &mut SubmissionContext<'_, F>,
148 mut run_basic_fn: B,
149 mut run_interactive_fn: I,
150) -> Result<ReplRunResult>
151where
152 F: FnMut(&str, &SharedHistory) -> Result<ReplLineResult>,
153 B: FnMut(&OspPrompt, &mut SubmissionContext<'_, F>) -> Result<ReplRunResult>,
154 I: FnMut(
155 InteractiveLoopConfig<'_>,
156 SharedHistory,
157 &mut SubmissionContext<'_, F>,
158 ) -> Result<ReplRunResult>,
159{
160 let ReplRunContext {
161 prompt,
162 completion_words,
163 completion_tree,
164 appearance,
165 line_projector,
166 history_store,
167 } = context;
168
169 if let Some(reason) = basic_reason {
170 match reason {
171 BasicInputReason::NotATerminal => {
172 eprintln!("Warning: Input is not a terminal (fd=0).");
173 }
174 BasicInputReason::CursorProbeUnsupported => {
175 eprintln!(
176 "Warning: terminal does not support cursor position requests; using basic input mode."
177 );
178 }
179 BasicInputReason::Explicit => {}
180 }
181 return run_basic_fn(&prompt, submission);
182 }
183
184 run_interactive_fn(
185 InteractiveLoopConfig {
186 prompt: &prompt,
187 completion_words,
188 completion_tree,
189 appearance,
190 line_projector,
191 },
192 history_store,
193 submission,
194 )
195}
196
197#[cfg(test)]
198mod tests;