yash_prompt/
lib.rs

1// This file is part of yash, an extended POSIX shell.
2// Copyright (C) 2024 WATANABE Yuki
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program.  If not, see <https://www.gnu.org/licenses/>.
16
17//! This library crate provides functionalities to show a command prompt.
18//!
19//! # Overview
20//!
21//! The `yash-prompt` crate provides command prompt support for the `yash`
22//! shell. It includes functionalities to expand prompt strings and display them
23//! interactively.
24//!
25//! [`Prompter`] is a decorator struct that wraps an inner input source and
26//! displays a command prompt before reading input from the user. It can be
27//! used to create an interactive shell prompt. The prompter internally uses
28//! the following functions to expand prompt strings:
29//!
30//! - [`fetch_posix`]: Fetches the value of a variable defined by POSIX for
31//!   a prompt string.
32//! - [`expand_posix`]: Expands a prompt string in a POSIX-compliant manner.
33//! - `expand_ex`: Expands a prompt string with yash-specific expansions.
34//!   (This function is not yet implemented.)
35//!
36//! [`expand_posix`]: expand_posix()
37//!
38//! # Examples
39//!
40//! Construct an input source with a prompter and read input from the user:
41//!
42//! ```
43//! # use futures_util::future::FutureExt as _;
44//! # async {
45//! use std::cell::RefCell;
46//! use std::ops::ControlFlow::Continue;
47//! use yash_env::Env;
48//! use yash_env::input::FdReader;
49//! use yash_env::io::Fd;
50//! use yash_env::parser::Config;
51//! use yash_env::semantics::ExitStatus;
52//! use yash_env::source::Source;
53//! use yash_prompt::{ExpandText, Prompter};
54//! use yash_semantics::expansion::expand_text;
55//! use yash_semantics::read_eval_loop;
56//! use yash_syntax::parser::lex::Lexer;
57//!
58//! let mut env = Env::new_virtual();
59//! env.any.insert(Box::new(ExpandText(|env, text| {
60//!     Box::pin(async move { expand_text(env, text).await.ok() })
61//! })));
62//!
63//! let reader = FdReader::new(Fd::STDIN, env.system.clone());
64//! let mut ref_env = RefCell::new(&mut env);
65//! let input = Box::new(Prompter::new(reader, &ref_env));
66//! let mut config = Config::with_input(input);
67//! config.source = Some(Source::Stdin.into());
68//! let mut lexer = Lexer::from(config);
69//!
70//! let result = read_eval_loop(&ref_env, &mut lexer).await;
71//! drop(lexer);
72//! assert_eq!(result, Continue(()));
73//! assert_eq!(env.exit_status, ExitStatus::SUCCESS);
74//! # }.now_or_never().unwrap();
75//! ```
76
77mod expand_posix;
78pub use expand_posix::ExpandText;
79pub use expand_posix::expand_posix;
80
81// TODO Yash-specific prompt expansion
82
83mod prompter;
84pub use prompter::Prompter;
85pub use prompter::fetch_posix;
86
87#[cfg(test)]
88mod tests {
89    use super::ExpandText;
90    use yash_env::{Env, System, VirtualSystem};
91
92    pub(crate) fn env_with_expand_text_and_system(system: Box<dyn System>) -> Env {
93        let mut env = Env::with_system(system);
94        env.any.insert(Box::new(ExpandText(|env, text| {
95            Box::pin(async move { yash_semantics::expansion::expand_text(env, text).await.ok() })
96        })));
97        env
98    }
99
100    pub(crate) fn env_with_expand_text() -> Env {
101        env_with_expand_text_and_system(Box::new(VirtualSystem::new()))
102    }
103}