Skip to content

Commit

Permalink
Support drawing popup frame
Browse files Browse the repository at this point in the history
  • Loading branch information
ath3 committed Mar 14, 2023
1 parent 75ebc1f commit badbff3
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 33 deletions.
1 change: 1 addition & 0 deletions book/src/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ signal to the Helix process on Unix operating systems, such as by using the comm
| `bufferline` | Renders a line at the top of the editor displaying open buffers. Can be `always`, `never` or `multiple` (only shown if more than one buffer is in use) | `never` |
| `color-modes` | Whether to color the mode indicator with different colors depending on the mode itself | `false` |
| `text-width` | Maximum line length. Used for the `:reflow` command and soft-wrapping if `soft-wrap.wrap_at_text_width` is set | `80` |
| `popup-border` | Draw border around `popup`, `menu`, `all`, or `none` | `none` |

### `[editor.statusline]` Section

Expand Down
18 changes: 16 additions & 2 deletions helix-term/src/commands/lsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ use super::{align_view, push_jump, Align, Context, Editor, Open};
use helix_core::{path, text_annotations::InlineAnnotation, Selection};
use helix_view::{
document::{DocumentInlayHints, DocumentInlayHintsId, Mode},
editor::Action,
editor::{Action, PopupBorderConfig},
graphics::Margin,
theme::Style,
Document, View,
};
Expand Down Expand Up @@ -664,7 +665,20 @@ pub fn code_action(cx: &mut Context) {
});
picker.move_down(); // pre-select the first item

let popup = Popup::new("code-action", picker).with_scrollbar(false);
let border_config = &editor.config().popup_border;

let margin = if border_config == &PopupBorderConfig::All
|| border_config == &PopupBorderConfig::Menu
{
Margin::vertical(1)
} else {
Margin::none()
};

let popup = Popup::new("code-action", picker)
.with_scrollbar(false)
.margin(margin);

compositor.replace_or_push("code-action", popup);
},
)
Expand Down
26 changes: 24 additions & 2 deletions helix-term/src/ui/completion.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::compositor::{Component, Context, Event, EventResult};
use helix_view::{
document::SavePoint,
editor::CompleteAction,
editor::{CompleteAction, PopupBorderConfig},
graphics::Margin,
theme::{Modifier, Style},
ViewId,
};
Expand Down Expand Up @@ -292,9 +293,22 @@ impl Completion {
}
};
});

let border_config = &editor.config().popup_border;

let margin = if border_config == &PopupBorderConfig::All
|| border_config == &PopupBorderConfig::Menu
{
Margin::vertical(1)
} else {
Margin::none()
};

let popup = Popup::new(Self::ID, menu)
.with_scrollbar(false)
.ignore_escape_key(true);
.ignore_escape_key(true)
.margin(margin);

let mut completion = Self {
popup,
start_offset,
Expand Down Expand Up @@ -525,6 +539,14 @@ impl Component for Completion {
// clear area
let background = cx.editor.theme.get("ui.popup");
surface.clear_with(doc_area, background);

let border_config = &cx.editor.config().popup_border;

if border_config == &PopupBorderConfig::All || border_config == &PopupBorderConfig::Popup {
use tui::widgets::{Block, Borders, Widget};
Widget::render(Block::default().borders(Borders::ALL), doc_area, surface);
}

markdown_doc.render(doc_area, surface, cx);
}
}
9 changes: 8 additions & 1 deletion helix-term/src/ui/lsp.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::sync::Arc;

use helix_core::syntax;
use helix_view::editor::PopupBorderConfig;
use helix_view::graphics::{Margin, Rect, Style};
use tui::buffer::Buffer;
use tui::widgets::{BorderType, Paragraph, Widget, Wrap};
Expand Down Expand Up @@ -92,7 +93,13 @@ impl Component for SignatureHelp {
Some(doc) => Markdown::new(doc.clone(), Arc::clone(&self.config_loader)),
};
let sig_doc = sig_doc.parse(Some(&cx.editor.theme));
let sig_doc_area = area.clip_top(sig_text_area.height + 2);
let mut sig_doc_area = area.clip_top(sig_text_area.height + 2);

let border_config = &cx.editor.config().popup_border;

if border_config == &PopupBorderConfig::All || border_config == &PopupBorderConfig::Popup {
sig_doc_area = sig_doc_area.clip_bottom(1);
}
let sig_doc_para = Paragraph::new(sig_doc)
.wrap(Wrap { trim: false })
.scroll((cx.scroll.unwrap_or_default() as u16, 0));
Expand Down
58 changes: 41 additions & 17 deletions helix-term/src/ui/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,21 @@ use crate::{
compositor::{Callback, Component, Compositor, Context, Event, EventResult},
ctrl, key, shift,
};
use tui::{buffer::Buffer as Surface, widgets::Table};
use tui::{
buffer::Buffer as Surface,
widgets::{Block, Borders, Table, Widget},
};

pub use tui::widgets::{Cell, Row};

use fuzzy_matcher::skim::SkimMatcherV2 as Matcher;
use fuzzy_matcher::FuzzyMatcher;

use helix_view::{graphics::Rect, Editor};
use helix_view::{
editor::PopupBorderConfig,
graphics::{Margin, Rect},
Editor,
};
use tui::layout::Constraint;

pub trait Item {
Expand Down Expand Up @@ -310,6 +317,18 @@ impl<T: Item + 'static> Component for Menu<T> {
let selected = theme.get("ui.menu.selected");
surface.clear_with(area, style);

let border_config = &cx.editor.config().popup_border;

let render_borders =
border_config == &PopupBorderConfig::All || border_config == &PopupBorderConfig::Menu;

let inner = if render_borders {
Widget::render(Block::default().borders(Borders::ALL), area, surface);
area.inner(&Margin::vertical(1))
} else {
area
};

let scroll = self.scroll;

let options: Vec<_> = self
Expand All @@ -323,7 +342,7 @@ impl<T: Item + 'static> Component for Menu<T> {

let len = options.len();

let win_height = area.height as usize;
let win_height = inner.height as usize;

const fn div_ceil(a: usize, b: usize) -> usize {
(a + b - 1) / b
Expand All @@ -341,23 +360,25 @@ impl<T: Item + 'static> Component for Menu<T> {
use tui::widgets::TableState;

table.render_table(
area.clip_left(Self::LEFT_PADDING as u16).clip_right(1),
inner.clip_left(Self::LEFT_PADDING as u16).clip_right(1),
surface,
&mut TableState {
offset: scroll,
selected: self.cursor,
},
);

if let Some(cursor) = self.cursor {
let offset_from_top = cursor - scroll;
let left = &mut surface[(area.left(), area.y + offset_from_top as u16)];
left.set_style(selected);
let right = &mut surface[(
area.right().saturating_sub(1),
area.y + offset_from_top as u16,
)];
right.set_style(selected);
if !render_borders {
if let Some(cursor) = self.cursor {
let offset_from_top = cursor - scroll;
let left = &mut surface[(inner.left(), inner.y + offset_from_top as u16)];
left.set_style(selected);
let right = &mut surface[(
inner.right().saturating_sub(1),
inner.y + offset_from_top as u16,
)];
right.set_style(selected);
}
}

let fits = len <= win_height;
Expand All @@ -370,14 +391,17 @@ impl<T: Item + 'static> Component for Menu<T> {

let mut cell;
for i in 0..win_height {
cell = &mut surface[(area.right() - 1, area.top() + i as u16)];

cell.set_symbol("▐"); // right half block
cell = &mut surface[(inner.right() - 1, inner.top() + i as u16)];

if scroll_line <= i && i < scroll_line + scroll_height {
// Draw scroll thumb
if render_borders {
cell.set_symbol("▌"); // left half block
} else {
cell.set_symbol("▐"); // right half block
}
cell.set_fg(scroll_style.fg.unwrap_or(helix_view::theme::Color::Reset));
} else {
} else if !render_borders {
// Draw scroll track
cell.set_fg(scroll_style.bg.unwrap_or(helix_view::theme::Color::Reset));
}
Expand Down
39 changes: 30 additions & 9 deletions helix-term/src/ui/popup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@ use crate::{
compositor::{Callback, Component, Context, Event, EventResult},
ctrl, key,
};
use tui::buffer::Buffer as Surface;
use tui::{
buffer::Buffer as Surface,
widgets::{Block, Borders, Widget},
};

use helix_core::Position;
use helix_view::graphics::{Margin, Rect};
use helix_view::{
editor::PopupBorderConfig,
graphics::{Margin, Rect},
};

// TODO: share logic with Menu, it's essentially Popup(render_fn), but render fn needs to return
// a width/height hint. maybe Popup(Box<Component>)
Expand Down Expand Up @@ -246,13 +252,25 @@ impl<T: Component> Component for Popup<T> {
let background = cx.editor.theme.get("ui.popup");
surface.clear_with(area, background);

let inner = area.inner(&self.margin);
let border_config = &cx.editor.config().popup_border;

let render_borders =
border_config == &PopupBorderConfig::All || border_config == &PopupBorderConfig::Popup;

let (inner, border) = if render_borders {
Widget::render(Block::default().borders(Borders::ALL), area, surface);
(area, 1)
} else {
let inner = area.inner(&self.margin);
(inner, 0)
};

self.contents.render(inner, surface, cx);

// render scrollbar if contents do not fit
if self.has_scrollbar {
let win_height = inner.height as usize;
let len = self.child_size.1 as usize;
let win_height = inner.height as usize - 2 * border;
let len = self.child_size.1 as usize - 2 * border;
let fits = len <= win_height;
let scroll = self.scroll;
let scroll_style = cx.editor.theme.get("ui.menu.scroll");
Expand All @@ -268,14 +286,17 @@ impl<T: Component> Component for Popup<T> {

let mut cell;
for i in 0..win_height {
cell = &mut surface[(inner.right() - 1, inner.top() + i as u16)];

cell.set_symbol("▐"); // right half block
cell = &mut surface[(inner.right() - 1, inner.top() + (border + i) as u16)];

if scroll_line <= i && i < scroll_line + scroll_height {
// Draw scroll thumb
if render_borders {
cell.set_symbol("▌"); // left half block
} else {
cell.set_symbol("▐"); // right half block
}
cell.set_fg(scroll_style.fg.unwrap_or(helix_view::theme::Color::Reset));
} else {
} else if !render_borders {
// Draw scroll track
cell.set_fg(scroll_style.bg.unwrap_or(helix_view::theme::Color::Reset));
}
Expand Down
15 changes: 13 additions & 2 deletions helix-view/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,8 @@ pub use helix_core::register::Registers;
use helix_core::{
auto_pairs::AutoPairs,
syntax::{self, AutoPairConfig, SoftWrap},
Change,
Change, Position, Selection,
};
use helix_core::{Position, Selection};
use helix_dap as dap;
use helix_lsp::lsp;

Expand Down Expand Up @@ -281,6 +280,8 @@ pub struct Config {
/// Whether to color modes with different colors. Defaults to `false`.
pub color_modes: bool,
pub soft_wrap: SoftWrap,
/// Draw border around popups.
pub popup_border: PopupBorderConfig,
}

#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
Expand Down Expand Up @@ -712,6 +713,15 @@ impl Default for IndentGuidesConfig {
}
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum PopupBorderConfig {
None,
All,
Popup,
Menu,
}

impl Default for Config {
fn default() -> Self {
Self {
Expand Down Expand Up @@ -751,6 +761,7 @@ impl Default for Config {
soft_wrap: SoftWrap::default(),
text_width: 80,
completion_replace: false,
popup_border: PopupBorderConfig::None,
}
}
}
Expand Down

0 comments on commit badbff3

Please sign in to comment.