@@ -0,0 +1,95 @@
1+use crate::compositor::{Component, Compositor, Context, EventResult};
2+use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
3+use tui::buffer::Buffer as Surface;
4+use tui::{
5+ layout::Rect,
6+ style::{Color, Style},
7+ widgets::{Block, Borders},
8+};
9+
10+use std::borrow::Cow;
11+
12+use helix_core::Position;
13+use helix_view::Editor;
14+
15+pub struct Popup {
16+ contents: String,
17+ position: Position,
18+}
19+
20+impl Popup {
21+ // TODO: it's like a slimmed down picker, share code? (picker = menu + prompt with different
22+ // rendering)
23+ pub fn new(contents: String) -> Self {
24+ Self {
25+ contents,
26+ position: Position::default(),
27+ }
28+ }
29+
30+ pub fn set_position(&mut self, pos: Position) {
31+ self.position = pos;
32+ }
33+}
34+
35+impl Component for Popup {
36+ fn handle_event(&mut self, event: Event, cx: &mut Context) -> EventResult {
37+ let event = match event {
38+ Event::Key(event) => event,
39+ _ => return EventResult::Ignored,
40+ };
41+
42+ let close_fn = EventResult::Consumed(Some(Box::new(
43+ |compositor: &mut Compositor, editor: &mut Editor| {
44+ // remove the layer
45+ compositor.pop();
46+ },
47+ )));
48+
49+ match event {
50+ // esc or ctrl-c aborts the completion and closes the menu
51+ KeyEvent {
52+ code: KeyCode::Esc, ..
53+ }
54+ | KeyEvent {
55+ code: KeyCode::Char('c'),
56+ modifiers: KeyModifiers::CONTROL,
57+ } => {
58+ return close_fn;
59+ }
60+ _ => (),
61+ }
62+ // for some events, we want to process them but send ignore, specifically all input except
63+ // tab/enter/ctrl-k or whatever will confirm the selection/ ctrl-n/ctrl-p for scroll.
64+ // EventResult::Consumed(None)
65+ EventResult::Consumed(None)
66+ }
67+ fn render(&self, area: Rect, surface: &mut Surface, cx: &mut Context) {
68+ // render a box at x, y. Width equal to max width of item.
69+ const MAX: usize = 15;
70+ let rows = std::cmp::min(self.contents.lines().count(), MAX) as u16; // inefficient
71+ let area = Rect::new(self.position.col as u16, self.position.row as u16, 80, rows);
72+
73+ // clear area
74+ let background = cx.editor.theme.get("ui.popup");
75+ for y in area.top()..area.bottom() {
76+ for x in area.left()..area.right() {
77+ let cell = surface.get_mut(x, y);
78+ cell.reset();
79+ // cell.symbol.clear();
80+ cell.set_style(background);
81+ }
82+ }
83+
84+ // -- Render the contents:
85+
86+ let style = Style::default().fg(Color::Rgb(164, 160, 232)); // lavender
87+
88+ use tui::text::Text;
89+ use tui::widgets::{Paragraph, Widget, Wrap};
90+ let contents = Text::from(self.contents.clone());
91+ let par = Paragraph::new(contents).wrap(Wrap { trim: false });
92+
93+ par.render(area, surface);
94+ }
95+}