1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-25 14:22:37 +03:00
wezterm/termwiz/examples/line_editor.rs
Wez Furlong bc083ee470 termwiz: ColorSpec now allows for alpha to be tracked
This doesn't really change any behavior, but adjusts the types
such that CSIs that set colors have the potential to track the
alpha channel and that can make it through to the GUI/render layer.
2022-07-26 19:39:53 -07:00

113 lines
3.6 KiB
Rust

use std::str::FromStr;
use termwiz::cell::AttributeChange;
use termwiz::color::{AnsiColor, ColorAttribute, SrgbaTuple};
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(
SrgbaTuple::from_str("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() -> termwiz::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(())
}