From 7162632eb739557ededaee902b23e48a577817b4 Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Thu, 25 Feb 2021 18:07:47 +0900 Subject: lsp: Hover documentation draft. --- helix-term/src/ui/editor.rs | 7 ++-- helix-term/src/ui/mod.rs | 2 + helix-term/src/ui/popup.rs | 95 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 4 deletions(-) create mode 100644 helix-term/src/ui/popup.rs (limited to 'helix-term/src/ui') diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index af9d0414..b071292c 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -100,6 +100,7 @@ impl EditorView { let mut spans = Vec::new(); let mut visual_x = 0; let mut line = 0u16; + let text = view.doc.text(); 'outer: for event in highlights { match event.unwrap() { @@ -113,7 +114,6 @@ impl EditorView { // TODO: filter out spans out of viewport for now.. // TODO: do these before iterating - let text = view.doc.text(); let start = text.byte_to_char(start); let end = text.byte_to_char(end); @@ -160,8 +160,7 @@ impl EditorView { let grapheme = Cow::from(grapheme); let width = grapheme_width(&grapheme) as u16; - // ugh, improve with a traverse method - // or interleave highlight spans with selection and diagnostic spans + // ugh,interleave highlight spans with diagnostic spans let is_diagnostic = view.doc.diagnostics.iter().any(|diagnostic| { diagnostic.range.0 <= char_index && diagnostic.range.1 > char_index }); @@ -191,12 +190,12 @@ impl EditorView { // render selections if is_focused { - let text = view.doc.text().slice(..); let screen = { let start = text.line_to_char(view.first_line); let end = text.line_to_char(last_line + 1); Range::new(start, end) }; + let text = text.slice(..); let cursor_style = Style::default().bg(Color::Rgb(255, 255, 255)); // cedar diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index e1899144..ea1d22ab 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -1,11 +1,13 @@ mod editor; mod menu; mod picker; +mod popup; mod prompt; pub use editor::EditorView; pub use menu::Menu; pub use picker::Picker; +pub use popup::Popup; pub use prompt::{Prompt, PromptEvent}; pub use tui::layout::Rect; diff --git a/helix-term/src/ui/popup.rs b/helix-term/src/ui/popup.rs new file mode 100644 index 00000000..ca860707 --- /dev/null +++ b/helix-term/src/ui/popup.rs @@ -0,0 +1,95 @@ +use crate::compositor::{Component, Compositor, Context, EventResult}; +use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers}; +use tui::buffer::Buffer as Surface; +use tui::{ + layout::Rect, + style::{Color, Style}, + widgets::{Block, Borders}, +}; + +use std::borrow::Cow; + +use helix_core::Position; +use helix_view::Editor; + +pub struct Popup { + contents: String, + position: Position, +} + +impl Popup { + // TODO: it's like a slimmed down picker, share code? (picker = menu + prompt with different + // rendering) + pub fn new(contents: String) -> Self { + Self { + contents, + position: Position::default(), + } + } + + pub fn set_position(&mut self, pos: Position) { + self.position = pos; + } +} + +impl Component for Popup { + fn handle_event(&mut self, event: Event, cx: &mut Context) -> EventResult { + let event = match event { + Event::Key(event) => event, + _ => return EventResult::Ignored, + }; + + let close_fn = EventResult::Consumed(Some(Box::new( + |compositor: &mut Compositor, editor: &mut Editor| { + // remove the layer + compositor.pop(); + }, + ))); + + match event { + // esc or ctrl-c aborts the completion and closes the menu + KeyEvent { + code: KeyCode::Esc, .. + } + | KeyEvent { + code: KeyCode::Char('c'), + modifiers: KeyModifiers::CONTROL, + } => { + return close_fn; + } + _ => (), + } + // for some events, we want to process them but send ignore, specifically all input except + // tab/enter/ctrl-k or whatever will confirm the selection/ ctrl-n/ctrl-p for scroll. + // EventResult::Consumed(None) + EventResult::Consumed(None) + } + fn render(&self, area: Rect, surface: &mut Surface, cx: &mut Context) { + // render a box at x, y. Width equal to max width of item. + const MAX: usize = 15; + let rows = std::cmp::min(self.contents.lines().count(), MAX) as u16; // inefficient + let area = Rect::new(self.position.col as u16, self.position.row as u16, 80, rows); + + // clear area + let background = cx.editor.theme.get("ui.popup"); + for y in area.top()..area.bottom() { + for x in area.left()..area.right() { + let cell = surface.get_mut(x, y); + cell.reset(); + // cell.symbol.clear(); + cell.set_style(background); + } + } + + // -- Render the contents: + + let style = Style::default().fg(Color::Rgb(164, 160, 232)); // lavender + + use tui::text::Text; + use tui::widgets::{Paragraph, Widget, Wrap}; + let contents = Text::from(self.contents.clone()); + let par = Paragraph::new(contents).wrap(Wrap { trim: false }); + + par.render(area, surface); + } +} -- cgit v1.2.3-70-g09d2