Skip to main content

shrub_core/shell/
readline.rs

1//! Readline edit buffer support for shell instances.
2
3use crate::variables::ShellVariable;
4use crate::{error, extensions};
5
6impl<SE: extensions::ShellExtensions> crate::Shell<SE> {
7    /// Updates the shell state to reflect the given edit buffer contents.
8    ///
9    /// # Arguments
10    ///
11    /// * `contents` - The contents of the edit buffer.
12    /// * `cursor` - The cursor position in the edit buffer.
13    ///
14    /// # Errors
15    ///
16    /// Returns [`crate::error::ErrorKind::MissingScopeForNewVariable`] if the
17    /// environment has no global scope to hold `READLINE_LINE` and
18    /// `READLINE_POINT`.
19    pub fn set_edit_buffer(&mut self, contents: String, cursor: usize) -> Result<(), error::Error> {
20        self.env
21            .set_global("READLINE_LINE", ShellVariable::new(contents))?;
22
23        self.env
24            .set_global("READLINE_POINT", ShellVariable::new(cursor.to_string()))?;
25
26        Ok(())
27    }
28
29    /// Returns the contents of the shell's edit buffer, if any. The buffer
30    /// state is cleared from the shell.
31    ///
32    /// # Errors
33    ///
34    /// Returns [`crate::error::ErrorKind::ReadonlyVariable`] if `READLINE_LINE`
35    /// or `READLINE_POINT` is readonly and so cannot be unset.
36    pub fn pop_edit_buffer(&mut self) -> Result<Option<(String, usize)>, error::Error> {
37        let line = self
38            .env
39            .unset("READLINE_LINE")?
40            .map(|line| line.value().to_cow_str(self).to_string());
41
42        let point = self
43            .env
44            .unset("READLINE_POINT")?
45            .and_then(|point| point.value().to_cow_str(self).parse::<usize>().ok())
46            .unwrap_or(0);
47
48        if let Some(line) = line {
49            Ok(Some((line, point)))
50        } else {
51            Ok(None)
52        }
53    }
54}