From 8985c58fd328cde512df0ac7bc577bd8a8c949a0 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Sat, 19 Jun 2021 23:54:37 +0800 Subject: Add infobox --- helix-term/src/ui/editor.rs | 7 +++++-- helix-term/src/ui/info.rs | 24 ++++++++++++++++++++++++ helix-term/src/ui/mod.rs | 1 + 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 helix-term/src/ui/info.rs (limited to 'helix-term/src/ui') diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 14c34493..8b7c92de 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -717,6 +717,10 @@ impl Component for EditorView { self.render_view(doc, view, area, surface, &cx.editor.theme, is_focused); } + if let Some(info) = std::mem::take(&mut cx.editor.autoinfo) { + info.render(area, surface, cx); + } + // render status msg if let Some((status_msg, severity)) = &cx.editor.status_msg { use helix_view::editor::Severity; @@ -735,8 +739,7 @@ impl Component for EditorView { } if let Some(completion) = &self.completion { - completion.render(area, surface, cx) - // render completion here + completion.render(area, surface, cx); } } diff --git a/helix-term/src/ui/info.rs b/helix-term/src/ui/info.rs new file mode 100644 index 00000000..085a2d9b --- /dev/null +++ b/helix-term/src/ui/info.rs @@ -0,0 +1,24 @@ +use crate::compositor::{Component, Context}; +use helix_view::graphics::{Margin, Rect, Style}; +use helix_view::info::Info; +use tui::buffer::Buffer as Surface; +use tui::widgets::{Block, Borders, Widget}; + +impl Component for Info { + fn render(&self, viewport: Rect, surface: &mut Surface, cx: &mut Context) { + let block = Block::default().title(self.title).borders(Borders::ALL); + let Info { width, height, .. } = self; + let (w, h) = (*width + 2, *height + 2); + // -2 to subtract command line + statusline. a bit of a hack, because of splits. + let area = Rect::new(viewport.width - w, viewport.height - h - 2, w, h); + let margin = Margin { + vertical: 1, + horizontal: 1, + }; + let Rect { x, y, .. } = area.inner(&margin); + for (y, line) in (y..).zip(self.text.lines()) { + surface.set_string(x, y, line, Style::default()); + } + block.render(area, surface); + } +} diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 7111c968..288d3d2e 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -1,5 +1,6 @@ mod completion; mod editor; +mod info; mod markdown; mod menu; mod picker; -- cgit v1.2.3-70-g09d2 From 9effe71b7d2133f18545d182cef384ea3fd1c0ff Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Wed, 30 Jun 2021 00:17:16 +0800 Subject: Apply suggestions from blaz for infobox --- Cargo.lock | 2 -- helix-term/src/ui/info.rs | 6 +----- helix-tui/Cargo.toml | 1 - helix-tui/src/backend/test.rs | 2 +- helix-tui/src/buffer.rs | 2 +- helix-tui/src/text.rs | 2 +- helix-tui/src/widgets/paragraph.rs | 2 +- helix-tui/src/widgets/reflow.rs | 2 +- helix-tui/src/widgets/table.rs | 2 +- helix-view/Cargo.toml | 1 - helix-view/src/info.rs | 2 +- helix-view/src/input.rs | 5 +++-- 12 files changed, 11 insertions(+), 18 deletions(-) (limited to 'helix-term/src/ui') diff --git a/Cargo.lock b/Cargo.lock index 59eb894e..2cd202f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -396,7 +396,6 @@ dependencies = [ "helix-view", "serde", "unicode-segmentation", - "unicode-width", ] [[package]] @@ -419,7 +418,6 @@ dependencies = [ "slotmap", "tokio", "toml", - "unicode-width", "url", "which", ] diff --git a/helix-term/src/ui/info.rs b/helix-term/src/ui/info.rs index 085a2d9b..c5709356 100644 --- a/helix-term/src/ui/info.rs +++ b/helix-term/src/ui/info.rs @@ -11,11 +11,7 @@ impl Component for Info { let (w, h) = (*width + 2, *height + 2); // -2 to subtract command line + statusline. a bit of a hack, because of splits. let area = Rect::new(viewport.width - w, viewport.height - h - 2, w, h); - let margin = Margin { - vertical: 1, - horizontal: 1, - }; - let Rect { x, y, .. } = area.inner(&margin); + let Rect { x, y, .. } = block.inner(area); for (y, line) in (y..).zip(self.text.lines()) { surface.set_string(x, y, line, Style::default()); } diff --git a/helix-tui/Cargo.toml b/helix-tui/Cargo.toml index dde2eafe..7f98144c 100644 --- a/helix-tui/Cargo.toml +++ b/helix-tui/Cargo.toml @@ -19,7 +19,6 @@ default = ["crossterm"] bitflags = "1.0" cassowary = "0.3" unicode-segmentation = "1.2" -unicode-width = "0.1" crossterm = { version = "0.20", optional = true } serde = { version = "1", "optional" = true, features = ["derive"]} helix-view = { version = "0.3", path = "../helix-view", features = ["term"] } diff --git a/helix-tui/src/backend/test.rs b/helix-tui/src/backend/test.rs index a03bcd8e..3f56b49c 100644 --- a/helix-tui/src/backend/test.rs +++ b/helix-tui/src/backend/test.rs @@ -2,9 +2,9 @@ use crate::{ backend::Backend, buffer::{Buffer, Cell}, }; +use helix_core::unicode::width::UnicodeWidthStr; use helix_view::graphics::{CursorKind, Rect}; use std::{fmt::Write, io}; -use unicode_width::UnicodeWidthStr; /// A backend used for the integration tests. #[derive(Debug)] diff --git a/helix-tui/src/buffer.rs b/helix-tui/src/buffer.rs index 3a7ad144..377e3e39 100644 --- a/helix-tui/src/buffer.rs +++ b/helix-tui/src/buffer.rs @@ -1,7 +1,7 @@ use crate::text::{Span, Spans}; +use helix_core::unicode::width::UnicodeWidthStr; use std::cmp::min; use unicode_segmentation::UnicodeSegmentation; -use unicode_width::UnicodeWidthStr; use helix_view::graphics::{Color, Modifier, Rect, Style}; diff --git a/helix-tui/src/text.rs b/helix-tui/src/text.rs index 4af6b09d..b8e52479 100644 --- a/helix-tui/src/text.rs +++ b/helix-tui/src/text.rs @@ -47,10 +47,10 @@ //! ]); //! ``` use helix_core::line_ending::str_is_line_ending; +use helix_core::unicode::width::UnicodeWidthStr; use helix_view::graphics::Style; use std::borrow::Cow; use unicode_segmentation::UnicodeSegmentation; -use unicode_width::UnicodeWidthStr; /// A grapheme associated to a style. #[derive(Debug, Clone, PartialEq)] diff --git a/helix-tui/src/widgets/paragraph.rs b/helix-tui/src/widgets/paragraph.rs index bdfb5b9a..fee35d25 100644 --- a/helix-tui/src/widgets/paragraph.rs +++ b/helix-tui/src/widgets/paragraph.rs @@ -7,9 +7,9 @@ use crate::{ Block, Widget, }, }; +use helix_core::unicode::width::UnicodeWidthStr; use helix_view::graphics::{Rect, Style}; use std::iter; -use unicode_width::UnicodeWidthStr; fn get_line_offset(line_width: u16, text_area_width: u16, alignment: Alignment) -> u16 { match alignment { diff --git a/helix-tui/src/widgets/reflow.rs b/helix-tui/src/widgets/reflow.rs index ae561a4f..21847783 100644 --- a/helix-tui/src/widgets/reflow.rs +++ b/helix-tui/src/widgets/reflow.rs @@ -1,7 +1,7 @@ use crate::text::StyledGrapheme; use helix_core::line_ending::str_is_line_ending; +use helix_core::unicode::width::UnicodeWidthStr; use unicode_segmentation::UnicodeSegmentation; -use unicode_width::UnicodeWidthStr; const NBSP: &str = "\u{00a0}"; diff --git a/helix-tui/src/widgets/table.rs b/helix-tui/src/widgets/table.rs index ee5147b7..1ee4286a 100644 --- a/helix-tui/src/widgets/table.rs +++ b/helix-tui/src/widgets/table.rs @@ -9,9 +9,9 @@ use cassowary::{ WeightedRelation::*, {Expression, Solver}, }; +use helix_core::unicode::width::UnicodeWidthStr; use helix_view::graphics::{Rect, Style}; use std::collections::HashMap; -use unicode_width::UnicodeWidthStr; /// A [`Cell`] contains the [`Text`] to be displayed in a [`Row`] of a [`Table`]. /// diff --git a/helix-view/Cargo.toml b/helix-view/Cargo.toml index b6816d71..cb2032de 100644 --- a/helix-view/Cargo.toml +++ b/helix-view/Cargo.toml @@ -31,7 +31,6 @@ slotmap = "1" encoding_rs = "0.8" chardetng = "0.1" -unicode-width = "0.1" serde = { version = "1.0", features = ["derive"] } toml = "0.5" diff --git a/helix-view/src/info.rs b/helix-view/src/info.rs index eef8d3a1..0eaab783 100644 --- a/helix-view/src/info.rs +++ b/helix-view/src/info.rs @@ -1,6 +1,6 @@ use crate::input::KeyEvent; +use helix_core::unicode::width::UnicodeWidthStr; use std::fmt::Write; -use unicode_width::UnicodeWidthStr; #[derive(Debug)] /// Info box used in editor. Rendering logic will be in other crate. diff --git a/helix-view/src/input.rs b/helix-view/src/input.rs index 6e8292e9..2847bb69 100644 --- a/helix-view/src/input.rs +++ b/helix-view/src/input.rs @@ -1,5 +1,6 @@ //! Input event handling, currently backed by crossterm. use anyhow::{anyhow, Error}; +use helix_core::unicode::width::UnicodeWidthStr; use serde::de::{self, Deserialize, Deserializer}; use std::fmt; @@ -90,9 +91,9 @@ impl fmt::Display for KeyEvent { } } -impl unicode_width::UnicodeWidthStr for KeyEvent { +impl UnicodeWidthStr for KeyEvent { fn width(&self) -> usize { - use unicode_width::UnicodeWidthChar; + use helix_core::unicode::width::UnicodeWidthChar; let mut width = match self.code { KeyCode::Backspace => keys::BACKSPACE.len(), KeyCode::Enter => keys::ENTER.len(), -- cgit v1.2.3-70-g09d2 From 6710855eac4826ffdc77d22901b010ae20bbaf3e Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Wed, 30 Jun 2021 21:39:21 +0800 Subject: Fix rendering issues for infobox --- helix-term/src/commands.rs | 6 ++++-- helix-term/src/ui/editor.rs | 1 + helix-term/src/ui/info.rs | 9 +++++++-- 3 files changed, 12 insertions(+), 4 deletions(-) (limited to 'helix-term/src/ui') diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index ddeded2d..854c34d3 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3422,6 +3422,7 @@ macro_rules! mode_info { ], )); $cx.on_next_key(move |cx, event| { + cx.editor.autoinfo = None; match event { $( $keyp => $func(cx), @@ -3441,8 +3442,8 @@ fn space_mode(cx: &mut Context) { key!('w'); key!('w') => window_mode; "window mode", key!('y'); key!('y') => yank_joined_to_clipboard; "yank joined to clipboard", key!('Y'); key!('Y') => yank_main_selection_to_clipboard; "yank main selection to clipboard", - key!('p'); key!('p') => paste_clipboard_after; "paste clipboard after", - key!('P'); key!('P') => paste_clipboard_before; "paste clipboard before", + key!('p'); key!('p') => paste_clipboard_after; "paste system clipboard after selections", + key!('P'); key!('P') => paste_clipboard_before; "paste system clipboard before selections", key!('R'); key!('R') => replace_selections_with_clipboard; "replace selections with clipboard", key!(' '); key!(' ') => keep_primary_selection; "keep primary selection", } @@ -3466,6 +3467,7 @@ fn space_mode(cx: &mut Context) { // ], // )); // cx.on_next_key(move |cx, event| { +// cx.editor.autoinfo = None; // match event { // key!('f') => file_picker(cx), // key!('b') => buffer_picker(cx), diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 8b7c92de..ad4f73bc 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -719,6 +719,7 @@ impl Component for EditorView { if let Some(info) = std::mem::take(&mut cx.editor.autoinfo) { info.render(area, surface, cx); + cx.editor.autoinfo = Some(info); } // render status msg diff --git a/helix-term/src/ui/info.rs b/helix-term/src/ui/info.rs index c5709356..87c2c213 100644 --- a/helix-term/src/ui/info.rs +++ b/helix-term/src/ui/info.rs @@ -6,14 +6,19 @@ use tui::widgets::{Block, Borders, Widget}; impl Component for Info { fn render(&self, viewport: Rect, surface: &mut Surface, cx: &mut Context) { - let block = Block::default().title(self.title).borders(Borders::ALL); + let style = cx.editor.theme.get("ui.popup"); + let block = Block::default() + .title(self.title) + .borders(Borders::ALL) + .border_style(style); let Info { width, height, .. } = self; let (w, h) = (*width + 2, *height + 2); // -2 to subtract command line + statusline. a bit of a hack, because of splits. let area = Rect::new(viewport.width - w, viewport.height - h - 2, w, h); + surface.clear_with(area, style); let Rect { x, y, .. } = block.inner(area); for (y, line) in (y..).zip(self.text.lines()) { - surface.set_string(x, y, line, Style::default()); + surface.set_string(x, y, line, style); } block.render(area, surface); } -- cgit v1.2.3-70-g09d2 From 5977b07e197cc6ef9051dd34a28b9fe28e01e966 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Fri, 2 Jul 2021 09:46:28 +0800 Subject: Reduce calculation and improve pattern in infobox - switch to use static OnceCell to calculate Info once - pass Vec<(&[KeyEvent], &str)> rather than Vec<(Vec, &str)> - expr -> tt to allow using | as separator, make it more like match --- helix-term/src/commands.rs | 21 ++++++++++----------- helix-term/src/keymap.rs | 7 ++----- helix-term/src/ui/info.rs | 2 +- helix-view/src/editor.rs | 2 +- helix-view/src/info.rs | 8 ++++---- 5 files changed, 18 insertions(+), 22 deletions(-) (limited to 'helix-term/src/ui') diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index b6f3c11f..351ec1fb 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -34,7 +34,6 @@ use movement::Movement; use crate::{ compositor::{self, Component, Compositor}, - key, ui::{self, Picker, Popup, Prompt, PromptEvent}, }; @@ -48,7 +47,7 @@ use std::{ path::{Path, PathBuf}, }; -use once_cell::sync::Lazy; +use once_cell::sync::{Lazy, OnceCell}; use serde::de::{self, Deserialize, Deserializer}; pub struct Context<'a> { @@ -3414,13 +3413,11 @@ fn select_register(cx: &mut Context) { } macro_rules! mode_info { - // TODO: how to use one expr for both pat and expr? - // TODO: how to use replaced function name as str at compile time? - // TODO: extend to support multiple keys, but first solve the other two + // TODO: reuse $mode for $stat (@join $first:expr $(,$rest:expr)*) => { concat!($first, $(", ", $rest),*) }; - {$mode:ident, $name:literal, $(#[doc = $desc:literal] $($key:expr),+ => $func:expr),+,} => { + {$mode:ident, $stat:ident, $name:literal, $(#[doc = $desc:literal] $($key:tt)|+ => $func:expr),+,} => { #[doc = $name] #[doc = ""] #[doc = ""] @@ -3439,12 +3436,14 @@ macro_rules! mode_info { )+ #[doc = "
keydesc
"] pub fn $mode(cx: &mut Context) { - cx.editor.autoinfo = Some(Info::key( + static $stat: OnceCell = OnceCell::new(); + cx.editor.autoinfo = Some($stat.get_or_init(|| Info::key( $name, - vec![$((vec![$($key.parse().unwrap()),+], $desc)),+], - )); + vec![$((&[$($key.parse().unwrap()),+], $desc)),+], + ))); use helix_core::hashmap; - let mut map = hashmap! { + // TODO: try and convert this to match later + let map = hashmap! { $($($key.parse::().unwrap() => $func as for<'r, 's> fn(&'r mut Context<'s>)),+),* }; cx.on_next_key_mode(map); @@ -3453,7 +3452,7 @@ macro_rules! mode_info { } mode_info! { - space_mode, "space mode", + space_mode, SPACE_MODE, "space mode", /// file picker "f" => file_picker, /// buffer picker diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index ef4a2138..3cd540ea 100644 --- a/helix-term/src/keymap.rs +++ b/helix-term/src/keymap.rs @@ -1,11 +1,7 @@ pub use crate::commands::Command; use crate::config::Config; use helix_core::hashmap; -use helix_view::{ - document::Mode, - input::KeyEvent, - keyboard::{KeyCode, KeyModifiers}, -}; +use helix_view::{document::Mode, input::KeyEvent}; use serde::Deserialize; use std::{ collections::HashMap, @@ -352,6 +348,7 @@ pub fn merge_keys(mut config: Config) -> Config { #[test] fn merge_partial_keys() { + use helix_view::keyboard::{KeyCode, KeyModifiers}; let config = Config { keys: Keymaps(hashmap! { Mode::Normal => hashmap! { diff --git a/helix-term/src/ui/info.rs b/helix-term/src/ui/info.rs index 87c2c213..c6f8db43 100644 --- a/helix-term/src/ui/info.rs +++ b/helix-term/src/ui/info.rs @@ -1,5 +1,5 @@ use crate::compositor::{Component, Context}; -use helix_view::graphics::{Margin, Rect, Style}; +use helix_view::graphics::Rect; use helix_view::info::Info; use tui::buffer::Buffer as Surface; use tui::widgets::{Block, Borders, Widget}; diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index b006a124..4f01cce4 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -33,7 +33,7 @@ pub struct Editor { pub syn_loader: Arc, pub theme_loader: Arc, - pub autoinfo: Option, + pub autoinfo: Option<&'static Info>, pub status_msg: Option<(String, Severity)>, } diff --git a/helix-view/src/info.rs b/helix-view/src/info.rs index 0eaab783..92c10351 100644 --- a/helix-view/src/info.rs +++ b/helix-view/src/info.rs @@ -16,7 +16,7 @@ pub struct Info { } impl Info { - pub fn key(title: &'static str, body: Vec<(Vec, &'static str)>) -> Info { + pub fn key(title: &'static str, body: Vec<(&[KeyEvent], &'static str)>) -> Info { let keymaps_width: u16 = body .iter() .map(|r| r.0.iter().map(|e| e.width() as u16 + 2).sum::() - 2) @@ -25,11 +25,11 @@ impl Info { let mut text = String::new(); let mut width = 0; let height = body.len() as u16; - for (mut keyevents, desc) in body { - let keyevent = keyevents.remove(0); + for (keyevents, desc) in body { + let keyevent = keyevents[0]; let mut left = keymaps_width - keyevent.width() as u16; write!(text, "{}", keyevent).ok(); - for keyevent in keyevents { + for keyevent in &keyevents[1..] { write!(text, ", {}", keyevent).ok(); left -= 2 + keyevent.width() as u16; } -- cgit v1.2.3-70-g09d2 From d02bbb7baec13e4d3c7ae0094431f2a20526cf18 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Sun, 4 Jul 2021 20:05:01 +0800 Subject: Fix info panic on small terminal --- helix-term/src/ui/info.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'helix-term/src/ui') diff --git a/helix-term/src/ui/info.rs b/helix-term/src/ui/info.rs index c6f8db43..e5f20562 100644 --- a/helix-term/src/ui/info.rs +++ b/helix-term/src/ui/info.rs @@ -14,7 +14,12 @@ impl Component for Info { let Info { width, height, .. } = self; let (w, h) = (*width + 2, *height + 2); // -2 to subtract command line + statusline. a bit of a hack, because of splits. - let area = Rect::new(viewport.width - w, viewport.height - h - 2, w, h); + let area = viewport.intersection(Rect::new( + viewport.width.saturating_sub(w), + viewport.height.saturating_sub(h + 2), + w, + h, + )); surface.clear_with(area, style); let Rect { x, y, .. } = block.inner(area); for (y, line) in (y..).zip(self.text.lines()) { -- cgit v1.2.3-70-g09d2 From 4952d6f80154665b50f23d055a4f3bc0ab8ac330 Mon Sep 17 00:00:00 2001 From: Nathan Vegdahl Date: Mon, 5 Jul 2021 00:11:07 -0700 Subject: Fix phantom lines in some CRLF files. Fixes #415. The issue was that cursor highlighting wasn't extending to encompass the entire CRLF grapheme, and therefore ended up splitting it. This presumably was messing up other grapheme rendering as well, and this fixes that as well. --- helix-term/src/ui/editor.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'helix-term/src/ui') diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index ad4f73bc..ef13004c 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -8,7 +8,7 @@ use crate::{ use helix_core::{ coords_at_pos, - graphemes::ensure_grapheme_boundary, + graphemes::{ensure_grapheme_boundary, next_grapheme_boundary}, syntax::{self, HighlightEvent}, LineEnding, Position, Range, }; @@ -187,19 +187,24 @@ impl EditorView { (cursor_scope, selection_scope) }; + let cursor_end = next_grapheme_boundary(text, range.head); // Used in every case below. + if range.head == range.anchor { - spans.push((cursor_scope, range.head..range.head + 1)); + spans.push((cursor_scope, range.head..cursor_end)); continue; } let reverse = range.head < range.anchor; if reverse { - spans.push((cursor_scope, range.head..range.head + 1)); - spans.push((selection_scope, range.head + 1..range.anchor + 1)); + spans.push((cursor_scope, range.head..cursor_end)); + spans.push(( + selection_scope, + cursor_end..next_grapheme_boundary(text, range.anchor), + )); } else { spans.push((selection_scope, range.anchor..range.head)); - spans.push((cursor_scope, range.head..range.head + 1)); + spans.push((cursor_scope, range.head..cursor_end)); } } -- cgit v1.2.3-70-g09d2