on master help sign in
Add cursor kind to separate hidden cursor from pos

Now IME cursor position should be correct since we can still set cursor position without drawing the cursor.

commit124514aa7024b0cf40bf01def54d280fcc86897c authorIvan Tham <pickfire@riseup.net> dateTue 15 Jun 2021, 13:03 (5 years ago) parent6bdf609
7 files changed+58−34
helix-term/src/compositor.rs+11−11 helix-term/src/ui/editor.rs+3−5 helix-term/src/ui/picker.rs+3−2 helix-term/src/ui/popup.rs+1−1 helix-term/src/ui/prompt.rs+9−5 helix-tui/src/terminal.rs+25−7 helix-view/src/editor.rs+6−3
helix-term/src/compositor.rs+11−11
@@ -4,7 +4,7 @@
44
55use crossterm::event::Event;
66use helix_core::Position;
7−use tui::{buffer::Buffer as Surface, layout::Rect};
7+use tui::{buffer::Buffer as Surface, layout::Rect, terminal::CursorKind};
88
99pub type Callback = Box<dyn FnOnce(&mut Compositor)>;
1010
@@ -47,8 +47,9 @@ pub trait Component: Any + AnyComponent {
4747 /// Render the component onto the provided surface.
4848 fn render(&self, area: Rect, frame: &mut Surface, ctx: &mut Context);
4949
50− fn cursor_position(&self, area: Rect, ctx: &Editor) -> Option<Position> {
51− None
50+ /// Get cursor position and cursor kind.
51+ fn cursor(&self, area: Rect, ctx: &Editor) -> (Option<Position>, CursorKind) {
52+ (None, CursorKind::Hidden)
5253 }
5354
5455 /// May be used by the parent component to compute the child area.
@@ -137,20 +138,19 @@ impl Compositor {
137138 layer.render(area, surface, cx)
138139 }
139140
140− let pos = self
141− .cursor_position(area, cx.editor)
142− .map(|pos| (pos.col as u16, pos.row as u16));
141+ let (pos, kind) = self.cursor(area, cx.editor);
142+ let pos = pos.map(|pos| (pos.col as u16, pos.row as u16));
143143
144− self.terminal.draw(pos);
144+ self.terminal.draw(pos, kind);
145145 }
146146
147− pub fn cursor_position(&self, area: Rect, editor: &Editor) -> Option<Position> {
147+ pub fn cursor(&self, area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
148148 for layer in self.layers.iter().rev() {
149− if let Some(pos) = layer.cursor_position(area, editor) {
150− return Some(pos);
149+ if let (Some(pos), kind) = layer.cursor(area, editor) {
150+ return (Some(pos), kind);
151151 }
152152 }
153− None
153+ (None, CursorKind::Hidden)
154154 }
155155
156156 pub fn find(&mut self, type_name: &str) -> Option<&mut dyn Component> {
helix-term/src/ui/editor.rs+3−5
@@ -26,6 +26,7 @@ use tui::{
2626 buffer::Buffer as Surface,
2727 layout::Rect,
2828 style::{Color, Modifier, Style},
29+ terminal::CursorKind,
2930};
3031
3132pub struct EditorView {
@@ -739,15 +740,12 @@ impl Component for EditorView {
739740 }
740741 }
741742
742− fn cursor_position(&self, area: Rect, editor: &Editor) -> Option<Position> {
743+ fn cursor(&self, area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
743744 // match view.doc.mode() {
744745 // Mode::Insert => write!(stdout, "\x1B[6 q"),
745746 // mode => write!(stdout, "\x1B[2 q"),
746747 // };
747− // return editor.cursor_position()
748−
749− // It's easier to just not render the cursor and use selection rendering instead.
750− None
748+ editor.cursor()
751749 }
752750}
753751
helix-term/src/ui/picker.rs+3−2
@@ -16,6 +16,7 @@ use crate::ui::{Prompt, PromptEvent};
1616use helix_core::Position;
1717use helix_view::editor::Action;
1818use helix_view::Editor;
19+use tui::terminal::CursorKind;
1920
2021pub struct Picker<T> {
2122 options: Vec<T>,
@@ -304,7 +305,7 @@ impl<T: 'static> Component for Picker<T> {
304305 }
305306 }
306307
307− fn cursor_position(&self, area: Rect, editor: &Editor) -> Option<Position> {
308+ fn cursor(&self, area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
308309 // TODO: this is mostly duplicate code
309310 let area = inner_rect(area);
310311 let block = Block::default().borders(Borders::ALL);
@@ -314,6 +315,6 @@ impl<T: 'static> Component for Picker<T> {
314315 // prompt area
315316 let area = Rect::new(inner.x + 1, inner.y, inner.width - 1, 1);
316317
317− self.prompt.cursor_position(area, editor)
318+ self.prompt.cursor(area, editor)
318319 }
319320}
helix-term/src/ui/popup.rs+1−1
@@ -116,7 +116,7 @@ impl<T: Component> Component for Popup<T> {
116116
117117 let position = self
118118 .position
119− .or_else(|| cx.editor.cursor_position())
119+ .or_else(|| cx.editor.cursor().0)
120120 .unwrap_or_default();
121121
122122 let (width, height) = self.size;
helix-term/src/ui/prompt.rs+9−5
@@ -4,6 +4,7 @@ use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
44use helix_core::Position;
55use helix_view::{Editor, Theme};
66use std::{borrow::Cow, ops::RangeFrom};
7+use tui::terminal::CursorKind;
78
89pub type Completion = (RangeFrom<usize>, Cow<'static, str>);
910
@@ -342,11 +343,14 @@ impl Component for Prompt {
342343 self.render_prompt(area, surface, cx)
343344 }
344345
345− fn cursor_position(&self, area: Rect, editor: &Editor) -> Option<Position> {
346+ fn cursor(&self, area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
346347 let line = area.height as usize - 1;
347− Some(Position::new(
348− area.y as usize + line,
349− area.x as usize + self.prompt.len() + self.cursor,
350− ))
348+ (
349+ Some(Position::new(
350+ area.y as usize + line,
351+ area.x as usize + self.prompt.len() + self.cursor,
352+ )),
353+ CursorKind::Block,
354+ )
351355 }
352356}
helix-tui/src/terminal.rs+25−7
@@ -8,6 +8,19 @@ enum ResizeBehavior {
88 Auto,
99}
1010
11+#[derive(Debug)]
12+/// UNSTABLE
13+pub enum CursorKind {
14+ /// █
15+ Block,
16+ /// |
17+ // Bar,
18+ /// _
19+ // Underline,
20+ /// Hidden cursor, can set cursor position with this to let IME have correct cursor position.
21+ Hidden,
22+}
23+
1124#[derive(Debug, Clone, PartialEq)]
1225/// UNSTABLE
1326pub struct Viewport {
@@ -147,7 +160,11 @@ where
147160
148161 /// Synchronizes terminal size, calls the rendering closure, flushes the current internal state
149162 /// and prepares for the next draw call.
150− pub fn draw(&mut self, cursor_position: Option<(u16, u16)>) -> io::Result<()> {
163+ pub fn draw(
164+ &mut self,
165+ cursor_position: Option<(u16, u16)>,
166+ cursor_kind: CursorKind,
167+ ) -> io::Result<()> {
151168 // // Autoresize - otherwise we get glitches if shrinking or potential desync between widgets
152169 // // and the terminal (if growing), which may OOB.
153170 // self.autoresize()?;
@@ -162,12 +179,13 @@ where
162179 // Draw to stdout
163180 self.flush()?;
164181
165− match cursor_position {
166− None => self.hide_cursor()?,
167− Some((x, y)) => {
168− self.show_cursor()?;
169− self.set_cursor(x, y)?;
170− }
182+ if let Some((x, y)) = cursor_position {
183+ self.set_cursor(x, y)?;
184+ }
185+
186+ match cursor_kind {
187+ CursorKind::Block => self.show_cursor()?,
188+ CursorKind::Hidden => self.hide_cursor()?,
171189 }
172190
173191 // Swap buffers
helix-view/src/editor.rs+6−3
@@ -1,5 +1,6 @@
11use crate::{theme::Theme, tree::Tree, Document, DocumentId, RegisterSelection, View, ViewId};
22use tui::layout::Rect;
3+use tui::terminal::CursorKind;
34
45use std::path::PathBuf;
56
@@ -9,6 +10,7 @@ use anyhow::Error;
910
1011pub use helix_core::diagnostic::Severity;
1112pub use helix_core::register::Registers;
13+use helix_core::Position;
1214
1315#[derive(Debug)]
1416pub struct Editor {
@@ -276,7 +278,7 @@ impl Editor {
276278 // let doc = &mut editor.documents[id];
277279 // }
278280
279− pub fn cursor_position(&self) -> Option<helix_core::Position> {
281+ pub fn cursor(&self) -> (Option<Position>, CursorKind) {
280282 const OFFSET: u16 = 7; // 1 diagnostic + 5 linenr + 1 gutter
281283 let view = self.view();
282284 let doc = &self.documents[view.doc];
@@ -284,8 +286,9 @@ impl Editor {
284286 if let Some(mut pos) = view.screen_coords_at_pos(doc, doc.text().slice(..), cursor) {
285287 pos.col += view.area.x as usize + OFFSET as usize;
286288 pos.row += view.area.y as usize;
287− return Some(pos);
289+ (Some(pos), CursorKind::Hidden)
290+ } else {
291+ (None, CursorKind::Hidden)
288292 }
289− None
290293 }
291294}