aboutsummaryrefslogtreecommitdiff
path: root/helix-term/src/line.rs
diff options
context:
space:
mode:
Diffstat (limited to 'helix-term/src/line.rs')
-rw-r--r--helix-term/src/line.rs111
1 files changed, 111 insertions, 0 deletions
diff --git a/helix-term/src/line.rs b/helix-term/src/line.rs
new file mode 100644
index 00000000..90fb5e6f
--- /dev/null
+++ b/helix-term/src/line.rs
@@ -0,0 +1,111 @@
+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(())
+}