@@ -16,28 +16,28 @@ use helix_view::Editor;
16// a width/height hint. maybe Popup(Box<Component>)
16// a width/height hint. maybe Popup(Box<Component>)
18pub struct Popup {
18pub struct Popup {
19− contents: String,
19+ contents: Box<dyn Component>,
20− position: Position,
20+ position: Option<Position>,
23impl Popup {
23impl Popup {
24 // TODO: it's like a slimmed down picker, share code? (picker = menu + prompt with different
24 // TODO: it's like a slimmed down picker, share code? (picker = menu + prompt with different
25 // rendering)
25 // rendering)
26− pub fn new(contents: String) -> Self {
26+ pub fn new(contents: Box<dyn Component>) -> Self {
29− position: Position::default(),
29+ position: None,
33− pub fn set_position(&mut self, pos: Position) {
33+ pub fn set_position(&mut self, pos: Option<Position>) {
34 self.position = pos;
34 self.position = pos;
38impl Component for Popup {
38impl Component for Popup {
39 fn handle_event(&mut self, event: Event, cx: &mut Context) -> EventResult {
39 fn handle_event(&mut self, event: Event, cx: &mut Context) -> EventResult {
40− let event = match event {
40+ let key = match event {
41 Event::Key(event) => event,
41 Event::Key(event) => event,
42 _ => return EventResult::Ignored,
42 _ => return EventResult::Ignored,
@@ -49,7 +49,7 @@ impl Component for Popup {
52− match event {
52+ match key {
53 // esc or ctrl-c aborts the completion and closes the menu
53 // esc or ctrl-c aborts the completion and closes the menu
54 KeyEvent {
54 KeyEvent {
55 code: KeyCode::Esc, ..
55 code: KeyCode::Esc, ..
@@ -60,29 +60,37 @@ impl Component for Popup {
61 return close_fn;
61 return close_fn;
63− _ => (),
63+ _ => self.contents.handle_event(event, cx),
65 // for some events, we want to process them but send ignore, specifically all input except
65 // for some events, we want to process them but send ignore, specifically all input except
66 // tab/enter/ctrl-k or whatever will confirm the selection/ ctrl-n/ctrl-p for scroll.
66 // tab/enter/ctrl-k or whatever will confirm the selection/ ctrl-n/ctrl-p for scroll.
67− // EventResult::Consumed(None)
68− EventResult::Consumed(None)
70 fn render(&self, viewport: Rect, surface: &mut Surface, cx: &mut Context) {
68 fn render(&self, viewport: Rect, surface: &mut Surface, cx: &mut Context) {
71 use tui::text::Text;
69 use tui::text::Text;
72 use tui::widgets::{Paragraph, Widget, Wrap};
70 use tui::widgets::{Paragraph, Widget, Wrap};
74− let contents = Text::from(self.contents.clone());
72+ let position = self
74+ .or_else(|| cx.editor.cursor_position())
75+ .unwrap_or_default();
77+ let (width, height) = self
76− let width = contents.width().min(150) as u16;
78+ .contents
80+ .expect("Component needs size_hint implemented in order to be embedded in a popup");
82+ let width = width.min(150) as u16;
77− let height = contents.height().min(13) as u16;
83+ let height = height.min(13) as u16;
79 // -- make sure frame doesn't stick out of bounds
85 // -- make sure frame doesn't stick out of bounds
80− let mut rel_x = self.position.col as u16;
86+ let mut rel_x = position.col as u16;
81− let mut rel_y = self.position.row as u16;
87+ let mut rel_y = position.row as u16;
82 if viewport.width <= rel_x + width {
88 if viewport.width <= rel_x + width {
83 rel_x -= ((rel_x + width) - viewport.width)
89 rel_x -= ((rel_x + width) - viewport.width)
92+ // TODO: be able to specify orientation preference. We want above for most popups, below
93+ // for menus/autocomplete.
86 if height <= rel_y {
94 if height <= rel_y {
87 rel_y -= height // position above point
95 rel_y -= height // position above point
@@ -104,13 +112,6 @@ impl Component for Popup {
107− // -- Render the contents:
109− let style = Style::default().fg(Color::Rgb(164, 160, 232)); // lavender
111− let par = Paragraph::new(contents).wrap(Wrap { trim: false });
112− // .scroll(x, y) offsets
114− par.render(area, surface);
115+ self.contents.render(area, surface, cx);