mirror of
https://github.com/wez/wezterm.git
synced 2024-11-24 07:46:59 +03:00
79007d9c33
This restructures the LineEditor to allow the hosting application to override key presses and apply custom edits to the editor buffer. Methods for performing predefined actions and for accessing the line buffer and cursor position have been provided/exposed to support this. One consequence of this change is that the editor instance needs to be passed through to the host trait impl and that means that the LineEditor can no longer be generic over `Terminal`. Instead we now take `&mut dyn Terminal` which was how the majority of non-example code was using it in any case. This simplifies a bit of boilerplate in wezterm but adds an extra line to the most basic examples.
112 lines
3.6 KiB
Rust
112 lines
3.6 KiB
Rust
use termwiz::cell::AttributeChange;
|
|
use termwiz::color::{AnsiColor, ColorAttribute, RgbColor};
|
|
use termwiz::lineedit::*;
|
|
|
|
#[derive(Default)]
|
|
struct Host {
|
|
history: BasicHistory,
|
|
}
|
|
|
|
impl LineEditorHost for Host {
|
|
// Render the prompt with a darkslateblue background color if
|
|
// the terminal supports true color, otherwise render it with
|
|
// a navy blue ansi color.
|
|
fn render_prompt(&self, prompt: &str) -> Vec<OutputElement> {
|
|
vec![
|
|
OutputElement::Attribute(AttributeChange::Background(
|
|
ColorAttribute::TrueColorWithPaletteFallback(
|
|
RgbColor::from_named("darkslateblue").unwrap(),
|
|
AnsiColor::Navy.into(),
|
|
),
|
|
)),
|
|
OutputElement::Text(prompt.to_owned()),
|
|
]
|
|
}
|
|
|
|
fn history(&mut self) -> &mut dyn History {
|
|
&mut self.history
|
|
}
|
|
|
|
/// Demo of the completion API for words starting with "h" or "he"
|
|
fn complete(&self, line: &str, cursor_position: usize) -> Vec<CompletionCandidate> {
|
|
let mut candidates = vec![];
|
|
if let Some((range, word)) = word_at_cursor(line, cursor_position) {
|
|
let words = &["hello", "help", "he-man"];
|
|
|
|
for w in words {
|
|
if w.starts_with(word) {
|
|
candidates.push(CompletionCandidate {
|
|
range: range.clone(),
|
|
text: w.to_string(),
|
|
});
|
|
}
|
|
}
|
|
}
|
|
candidates
|
|
}
|
|
}
|
|
|
|
/// This is a conceptually simple function that computes the bounds
|
|
/// of the whitespace delimited word at the specified cursor position
|
|
/// in the supplied line string.
|
|
/// It returns the range and the corresponding slice out of the line.
|
|
/// This function is sufficient for example purposes; in a real application
|
|
/// the equivalent function would need to be aware of quoting and other
|
|
/// application specific context.
|
|
fn word_at_cursor(line: &str, cursor_position: usize) -> Option<(std::ops::Range<usize>, &str)> {
|
|
let char_indices: Vec<(usize, char)> = line.char_indices().collect();
|
|
if char_indices.is_empty() {
|
|
return None;
|
|
}
|
|
let char_position = char_indices
|
|
.iter()
|
|
.position(|(idx, _)| *idx == cursor_position)
|
|
.unwrap_or(char_indices.len());
|
|
|
|
// Look back until we find whitespace
|
|
let mut start_position = char_position;
|
|
while start_position > 0
|
|
&& start_position <= char_indices.len()
|
|
&& !char_indices[start_position - 1].1.is_whitespace()
|
|
{
|
|
start_position -= 1;
|
|
}
|
|
|
|
// Look forwards until we find whitespace
|
|
let mut end_position = char_position;
|
|
while end_position < char_indices.len() && !char_indices[end_position].1.is_whitespace() {
|
|
end_position += 1;
|
|
}
|
|
|
|
if end_position > start_position {
|
|
let range = char_indices[start_position].0
|
|
..char_indices
|
|
.get(end_position)
|
|
.map(|c| c.0 + 1)
|
|
.unwrap_or(line.len());
|
|
Some((range.clone(), &line[range]))
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
fn main() -> anyhow::Result<()> {
|
|
println!("Type `exit` to quit this example, or start a word with `h` and press Tab.");
|
|
let mut terminal = line_editor_terminal()?;
|
|
let mut editor = LineEditor::new(&mut terminal);
|
|
|
|
let mut host = Host::default();
|
|
loop {
|
|
if let Some(line) = editor.read_line(&mut host)? {
|
|
println!("read line: {:?}", line);
|
|
if line == "exit" {
|
|
break;
|
|
}
|
|
|
|
host.history().add(&line);
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|