on master help sign in
Add cursor kind to separate hidden cursor from pos
124514aIvan Tham
helix-term/src/compositor.rs+11−11
@@ -4,7 +4,7 @@
4
4
5use crossterm::event::Event;
5use crossterm::event::Event;
6use helix_core::Position;
6use helix_core::Position;
7−use tui::{buffer::Buffer as Surface, layout::Rect};
7+use tui::{buffer::Buffer as Surface, layout::Rect, terminal::CursorKind};
8
8
9pub type Callback = Box<dyn FnOnce(&mut Compositor)>;
9pub type Callback = Box<dyn FnOnce(&mut Compositor)>;
10
10
@@ -47,8 +47,9 @@ pub trait Component: Any + AnyComponent {
47 /// Render the component onto the provided surface.
47 /// Render the component onto the provided surface.
48 fn render(&self, area: Rect, frame: &mut Surface, ctx: &mut Context);
48 fn render(&self, area: Rect, frame: &mut Surface, ctx: &mut Context);
49
49
50+ /// Get cursor position and cursor kind.
50− fn cursor_position(&self, area: Rect, ctx: &Editor) -> Option<Position> {
51+ fn cursor(&self, area: Rect, ctx: &Editor) -> (Option<Position>, CursorKind) {
51− None
52+ (None, CursorKind::Hidden)
52 }
53 }
53
54
54 /// May be used by the parent component to compute the child area.
55 /// May be used by the parent component to compute the child area.
@@ -137,20 +138,19 @@ impl Compositor {
137 layer.render(area, surface, cx)
138 layer.render(area, surface, cx)
138 }
139 }
139
140
140− let pos = self
141+ let (pos, kind) = self.cursor(area, cx.editor);
141− .cursor_position(area, cx.editor)
142− .map(|pos| (pos.col as u16, pos.row as u16));
142+ let pos = pos.map(|pos| (pos.col as u16, pos.row as u16));
143
143
144− self.terminal.draw(pos);
144+ self.terminal.draw(pos, kind);
145 }
145 }
146
146
147− pub fn cursor_position(&self, area: Rect, editor: &Editor) -> Option<Position> {
147+ pub fn cursor(&self, area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
148 for layer in self.layers.iter().rev() {
148 for layer in self.layers.iter().rev() {
149− if let Some(pos) = layer.cursor_position(area, editor) {
149+ if let (Some(pos), kind) = layer.cursor(area, editor) {
150− return Some(pos);
150+ return (Some(pos), kind);
151 }
151 }
152 }
152 }
153− None
153+ (None, CursorKind::Hidden)
154 }
154 }
155
155
156 pub fn find(&mut self, type_name: &str) -> Option<&mut dyn Component> {
156 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::{
26 buffer::Buffer as Surface,
26 buffer::Buffer as Surface,
27 layout::Rect,
27 layout::Rect,
28 style::{Color, Modifier, Style},
28 style::{Color, Modifier, Style},
29+ terminal::CursorKind,
29};
30};
30
31
31pub struct EditorView {
32pub struct EditorView {
@@ -739,15 +740,12 @@ impl Component for EditorView {
739 }
740 }
740 }
741 }
741
742
742− fn cursor_position(&self, area: Rect, editor: &Editor) -> Option<Position> {
743+ fn cursor(&self, area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
743 // match view.doc.mode() {
744 // match view.doc.mode() {
744 // Mode::Insert => write!(stdout, "\x1B[6 q"),
745 // Mode::Insert => write!(stdout, "\x1B[6 q"),
745 // mode => write!(stdout, "\x1B[2 q"),
746 // mode => write!(stdout, "\x1B[2 q"),
746 // };
747 // };
747− // return editor.cursor_position()
748+ editor.cursor()
748−
749− // It's easier to just not render the cursor and use selection rendering instead.
750− None
751 }
749 }
752}
750}
753
751
helix-term/src/ui/picker.rs+3−2
@@ -16,6 +16,7 @@ use crate::ui::{Prompt, PromptEvent};
16use helix_core::Position;
16use helix_core::Position;
17use helix_view::editor::Action;
17use helix_view::editor::Action;
18use helix_view::Editor;
18use helix_view::Editor;
19+use tui::terminal::CursorKind;
19
20
20pub struct Picker<T> {
21pub struct Picker<T> {
21 options: Vec<T>,
22 options: Vec<T>,
@@ -304,7 +305,7 @@ impl<T: 'static> Component for Picker<T> {
304 }
305 }
305 }
306 }
306
307
307− fn cursor_position(&self, area: Rect, editor: &Editor) -> Option<Position> {
308+ fn cursor(&self, area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
308 // TODO: this is mostly duplicate code
309 // TODO: this is mostly duplicate code
309 let area = inner_rect(area);
310 let area = inner_rect(area);
310 let block = Block::default().borders(Borders::ALL);
311 let block = Block::default().borders(Borders::ALL);
@@ -314,6 +315,6 @@ impl<T: 'static> Component for Picker<T> {
314 // prompt area
315 // prompt area
315 let area = Rect::new(inner.x + 1, inner.y, inner.width - 1, 1);
316 let area = Rect::new(inner.x + 1, inner.y, inner.width - 1, 1);
316
317
317− self.prompt.cursor_position(area, editor)
318+ self.prompt.cursor(area, editor)
318 }
319 }
319}
320}
helix-term/src/ui/popup.rs+1−1
@@ -116,7 +116,7 @@ impl<T: Component> Component for Popup<T> {
116
116
117 let position = self
117 let position = self
118 .position
118 .position
119− .or_else(|| cx.editor.cursor_position())
119+ .or_else(|| cx.editor.cursor().0)
120 .unwrap_or_default();
120 .unwrap_or_default();
121
121
122 let (width, height) = self.size;
122 let (width, height) = self.size;
helix-term/src/ui/prompt.rs+9−5
@@ -4,6 +4,7 @@ use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
4use helix_core::Position;
4use helix_core::Position;
5use helix_view::{Editor, Theme};
5use helix_view::{Editor, Theme};
6use std::{borrow::Cow, ops::RangeFrom};
6use std::{borrow::Cow, ops::RangeFrom};
7+use tui::terminal::CursorKind;
7
8
8pub type Completion = (RangeFrom<usize>, Cow<'static, str>);
9pub type Completion = (RangeFrom<usize>, Cow<'static, str>);
9
10
@@ -342,11 +343,14 @@ impl Component for Prompt {
342 self.render_prompt(area, surface, cx)
343 self.render_prompt(area, surface, cx)
343 }
344 }
344
345
345− fn cursor_position(&self, area: Rect, editor: &Editor) -> Option<Position> {
346+ fn cursor(&self, area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
346 let line = area.height as usize - 1;
347 let line = area.height as usize - 1;
348+ (
347− Some(Position::new(
349+ Some(Position::new(
348− area.y as usize + line,
350+ area.y as usize + line,
349− area.x as usize + self.prompt.len() + self.cursor,
351+ area.x as usize + self.prompt.len() + self.cursor,
352+ )),
353+ CursorKind::Block,
350− ))
354+ )
351 }
355 }
352}
356}
helix-tui/src/terminal.rs+25−7
@@ -8,6 +8,19 @@ enum ResizeBehavior {
8 Auto,
8 Auto,
9}
9}
10
10
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+
11#[derive(Debug, Clone, PartialEq)]
24#[derive(Debug, Clone, PartialEq)]
12/// UNSTABLE
25/// UNSTABLE
13pub struct Viewport {
26pub struct Viewport {
@@ -147,7 +160,11 @@ where
147
160
148 /// Synchronizes terminal size, calls the rendering closure, flushes the current internal state
161 /// Synchronizes terminal size, calls the rendering closure, flushes the current internal state
149 /// and prepares for the next draw call.
162 /// and prepares for the next draw call.
163+ pub fn draw(
164+ &mut self,
150− pub fn draw(&mut self, cursor_position: Option<(u16, u16)>) -> io::Result<()> {
165+ cursor_position: Option<(u16, u16)>,
166+ cursor_kind: CursorKind,
167+ ) -> io::Result<()> {
151 // // Autoresize - otherwise we get glitches if shrinking or potential desync between widgets
168 // // Autoresize - otherwise we get glitches if shrinking or potential desync between widgets
152 // // and the terminal (if growing), which may OOB.
169 // // and the terminal (if growing), which may OOB.
153 // self.autoresize()?;
170 // self.autoresize()?;
@@ -162,12 +179,13 @@ where
162 // Draw to stdout
179 // Draw to stdout
163 self.flush()?;
180 self.flush()?;
164
181
165− match cursor_position {
182+ if let Some((x, y)) = cursor_position {
166− None => self.hide_cursor()?,
167− Some((x, y)) => {
168− self.show_cursor()?;
169− self.set_cursor(x, y)?;
183+ self.set_cursor(x, y)?;
170− }
184+ }
185+
186+ match cursor_kind {
187+ CursorKind::Block => self.show_cursor()?,
188+ CursorKind::Hidden => self.hide_cursor()?,
171 }
189 }
172
190
173 // Swap buffers
191 // Swap buffers
helix-view/src/editor.rs+6−3
@@ -1,5 +1,6 @@
1use crate::{theme::Theme, tree::Tree, Document, DocumentId, RegisterSelection, View, ViewId};
1use crate::{theme::Theme, tree::Tree, Document, DocumentId, RegisterSelection, View, ViewId};
2use tui::layout::Rect;
2use tui::layout::Rect;
3+use tui::terminal::CursorKind;
3
4
4use std::path::PathBuf;
5use std::path::PathBuf;
5
6
@@ -9,6 +10,7 @@ use anyhow::Error;
9
10
10pub use helix_core::diagnostic::Severity;
11pub use helix_core::diagnostic::Severity;
11pub use helix_core::register::Registers;
12pub use helix_core::register::Registers;
13+use helix_core::Position;
12
14
13#[derive(Debug)]
15#[derive(Debug)]
14pub struct Editor {
16pub struct Editor {
@@ -276,7 +278,7 @@ impl Editor {
276 // let doc = &mut editor.documents[id];
278 // let doc = &mut editor.documents[id];
277 // }
279 // }
278
280
279− pub fn cursor_position(&self) -> Option<helix_core::Position> {
281+ pub fn cursor(&self) -> (Option<Position>, CursorKind) {
280 const OFFSET: u16 = 7; // 1 diagnostic + 5 linenr + 1 gutter
282 const OFFSET: u16 = 7; // 1 diagnostic + 5 linenr + 1 gutter
281 let view = self.view();
283 let view = self.view();
282 let doc = &self.documents[view.doc];
284 let doc = &self.documents[view.doc];
@@ -284,8 +286,9 @@ impl Editor {
284 if let Some(mut pos) = view.screen_coords_at_pos(doc, doc.text().slice(..), cursor) {
286 if let Some(mut pos) = view.screen_coords_at_pos(doc, doc.text().slice(..), cursor) {
285 pos.col += view.area.x as usize + OFFSET as usize;
287 pos.col += view.area.x as usize + OFFSET as usize;
286 pos.row += view.area.y as usize;
288 pos.row += view.area.y as usize;
287− return Some(pos);
289+ (Some(pos), CursorKind::Hidden)
290+ } else {
291+ (None, CursorKind::Hidden)
288 }
292 }
289− None
290 }
293 }
291}
294}