Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'helix-term/src/ui/prompt.rs')
| -rw-r--r-- | helix-term/src/ui/prompt.rs | 78 |
1 files changed, 67 insertions, 11 deletions
diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index f44020c5..5f9745be 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -30,6 +30,12 @@ pub struct Prompt { prompt: Cow<'static, str>, line: String, cursor: usize, + // Fields used for Component callbacks and rendering: + line_area: Rect, + anchor: usize, + truncate_start: bool, + truncate_end: bool, + // --- completion: Vec<Completion>, selection: Option<usize>, history_register: Option<char>, @@ -82,6 +88,10 @@ impl Prompt { prompt, line: String::new(), cursor: 0, + line_area: Rect::default(), + anchor: 0, + truncate_start: false, + truncate_end: false, completion: Vec::new(), selection: None, history_register, @@ -389,7 +399,7 @@ impl Prompt { const BASE_WIDTH: u16 = 30; impl Prompt { - pub fn render_prompt(&self, area: Rect, surface: &mut Surface, cx: &mut Context) { + pub fn render_prompt(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) { let theme = &cx.editor.theme; let prompt_color = theme.get("ui.text"); let completion_color = theme.get("ui.menu"); @@ -499,11 +509,20 @@ impl Prompt { // render buffer text surface.set_string(area.x, area.y + line, &self.prompt, prompt_color); - let line_area = area.clip_left(self.prompt.len() as u16).clip_top(line); + self.line_area = area + .clip_left(self.prompt.len() as u16) + .clip_top(line) + .clip_right(2); + if self.line.is_empty() { // Show the most recently entered value as a suggestion. if let Some(suggestion) = self.first_history_completion(cx.editor) { - surface.set_string(line_area.x, line_area.y, suggestion, suggestion_color); + surface.set_string( + self.line_area.x, + self.line_area.y, + suggestion, + suggestion_color, + ); } } else if let Some((language, loader)) = self.language.as_ref() { let mut text: ui::text::Text = crate::ui::markdown::highlighted_code_block( @@ -514,9 +533,34 @@ impl Prompt { None, ) .into(); - text.render(line_area, surface, cx); + text.render(self.line_area, surface, cx); } else { - surface.set_string(line_area.x, line_area.y, self.line.clone(), prompt_color); + if self.line.len() < self.line_area.width as usize { + self.anchor = 0; + } else if self.cursor < self.anchor { + self.anchor = self.cursor; + } else if self.cursor - self.anchor > self.line_area.width as usize { + self.anchor = self.cursor - self.line_area.width as usize; + } + + self.truncate_start = self.anchor > 0; + self.truncate_end = self.line.len() - self.anchor > self.line_area.width as usize; + + // if we keep inserting characters just before the end elipsis, we move the anchor + // so that those new characters are displayed + if self.truncate_end && self.cursor - self.anchor >= self.line_area.width as usize { + self.anchor += 1; + } + + surface.set_string_anchored( + self.line_area.x, + self.line_area.y, + self.truncate_start, + self.truncate_end, + &self.line.as_str()[self.anchor..], + self.line_area.width as usize - self.truncate_end as usize, + |_| prompt_color, + ); } } } @@ -686,14 +730,26 @@ impl Component for Prompt { } fn cursor(&self, area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) { + let area = area + .clip_left(self.prompt.len() as u16) + .clip_right(if self.prompt.len() > 0 { 0 } else { 2 }); + + let mut col = area.left() as usize + + UnicodeWidthStr::width(&self.line[self.anchor..self.cursor.max(self.anchor)]); + + // ensure the cursor does not go beyond elipses + if self.truncate_end && self.cursor - self.anchor >= self.line_area.width as usize { + col -= 1; + } + + if self.truncate_start && self.cursor == self.anchor { + col += 1; + } + let line = area.height as usize - 1; + ( - Some(Position::new( - area.y as usize + line, - area.x as usize - + self.prompt.len() - + UnicodeWidthStr::width(&self.line[..self.cursor]), - )), + Some(Position::new(area.y as usize + line, col)), editor.config().cursor_shape.from_mode(Mode::Insert), ) } |