Skip to content

Commit

Permalink
Support drawing popup border
Browse files Browse the repository at this point in the history
  • Loading branch information
ath3 committed Oct 25, 2022
1 parent e16c632 commit 56ce875
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 17 deletions.
1 change: 1 addition & 0 deletions book/src/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ on unix operating systems.
| `rulers` | List of column positions at which to display the rulers. Can be overridden by language specific `rulers` in `languages.toml` file. | `[]` |
| `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` |
| `popup-border` | Draw border around `popup`, `menu`, `all`, or `none` | `none` |

### `[editor.statusline]` Section

Expand Down
6 changes: 6 additions & 0 deletions helix-term/src/ui/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,12 @@ impl Component for Completion {
// clear area
let background = cx.editor.theme.get("ui.popup");
surface.clear_with(area, background);
if cx.editor.config().popup_border == helix_view::editor::PopupBorderConfig::All
|| cx.editor.config().popup_border == helix_view::editor::PopupBorderConfig::Popup
{
use tui::widgets::{Block, Borders, Widget};
Widget::render(Block::default().borders(Borders::ALL), area, surface);
}
markdown_doc.render(area, surface, cx);
}
}
Expand Down
7 changes: 6 additions & 1 deletion helix-term/src/ui/lsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,12 @@ 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);
if cx.editor.config().popup_border == helix_view::editor::PopupBorderConfig::All
|| cx.editor.config().popup_border == helix_view::editor::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
51 changes: 38 additions & 13 deletions helix-term/src/ui/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,13 +291,24 @@ impl<T: Item + 'static> Component for Menu<T> {
Some(self.size)
}

fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
fn render(&mut self, mut area: Rect, surface: &mut Surface, cx: &mut Context) {
let theme = &cx.editor.theme;
let style = theme
.try_get("ui.menu")
.unwrap_or_else(|| theme.get("ui.text"));
let selected = theme.get("ui.menu.selected");
surface.clear_with(area, style);

let borders = cx.editor.config().popup_border == helix_view::editor::PopupBorderConfig::All
|| cx.editor.config().popup_border == helix_view::editor::PopupBorderConfig::Menu;
if borders {
area.height += 2 as u16;
// If the menu is drawn above the current line, it would hide the line
if cx.editor.cursor().0.unwrap().row > area.y as usize && area.y >= 2 {
area.y -= 2;
}
}

area = surface.area.intersection(area);

let scroll = self.scroll;

Expand All @@ -310,6 +321,14 @@ impl<T: Item + 'static> Component for Menu<T> {
})
.collect();

surface.clear_with(area, style);

if borders {
use tui::widgets::{Block, Borders, Widget};
Widget::render(Block::default().borders(Borders::ALL), area, surface);

area = area.clip_top(1).clip_bottom(1);
}
let len = options.len();

let win_height = area.height as usize;
Expand Down Expand Up @@ -341,15 +360,17 @@ impl<T: Item + 'static> Component for Menu<T> {
},
);

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 !borders {
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);
}
}

let fits = len <= win_height;
Expand All @@ -358,16 +379,20 @@ impl<T: Item + 'static> Component for Menu<T> {
for (i, _) in (scroll..(scroll + win_height).min(len)).enumerate() {
let cell = &mut surface[(area.x + area.width - 1, area.y + i as u16)];

if !fits {
if !(fits || borders) {
// Draw scroll track
cell.set_symbol("▐"); // right half block
cell.set_fg(scroll_style.bg.unwrap_or(helix_view::theme::Color::Reset));
}

let is_marked = i >= scroll_line && i < scroll_line + scroll_height;

if !fits && is_marked {
// Draw scroll thumb
if 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));
}
}
Expand Down
14 changes: 11 additions & 3 deletions helix-term/src/ui/popup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,14 +220,22 @@ impl<T: Component> Component for Popup<T> {
let (rel_x, rel_y) = self.get_rel_position(viewport, cx);

// clip to viewport
let area = viewport.intersection(Rect::new(rel_x, rel_y, self.size.0, self.size.1));
let mut area = viewport.intersection(Rect::new(rel_x, rel_y, self.size.0, self.size.1));

// clear area
let background = cx.editor.theme.get("ui.popup");
surface.clear_with(area, background);

let inner = area.inner(&self.margin);
self.contents.render(inner, surface, cx);
if cx.editor.config().popup_border == helix_view::editor::PopupBorderConfig::All
|| cx.editor.config().popup_border == helix_view::editor::PopupBorderConfig::Popup
{
use tui::widgets::{Block, Borders, Widget};
Widget::render(Block::default().borders(Borders::ALL), area, surface);
} else {
area = area.inner(&self.margin);
}

self.contents.render(area, surface, cx);
}

fn id(&self) -> Option<&'static str> {
Expand Down
12 changes: 12 additions & 0 deletions helix-view/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ pub struct Config {
pub indent_guides: IndentGuidesConfig,
/// Whether to color modes with different colors. Defaults to `false`.
pub color_modes: bool,
/// Draw border around popups.
pub popup_border: PopupBorderConfig,
}

#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
Expand Down Expand Up @@ -571,6 +573,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 @@ -605,6 +616,7 @@ impl Default for Config {
bufferline: BufferLine::default(),
indent_guides: IndentGuidesConfig::default(),
color_modes: false,
popup_border: PopupBorderConfig::None,
}
}
}
Expand Down

0 comments on commit 56ce875

Please sign in to comment.