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.
pull/260/head
Ivan Tham 3 years ago
parent 6bdf609caa
commit 124514aa70

@ -4,7 +4,7 @@
use crossterm::event::Event;
use helix_core::Position;
use tui::{buffer::Buffer as Surface, layout::Rect};
use tui::{buffer::Buffer as Surface, layout::Rect, terminal::CursorKind};
pub type Callback = Box<dyn FnOnce(&mut Compositor)>;
@ -47,8 +47,9 @@ pub trait Component: Any + AnyComponent {
/// Render the component onto the provided surface.
fn render(&self, area: Rect, frame: &mut Surface, ctx: &mut Context);
fn cursor_position(&self, area: Rect, ctx: &Editor) -> Option<Position> {
None
/// Get cursor position and cursor kind.
fn cursor(&self, area: Rect, ctx: &Editor) -> (Option<Position>, CursorKind) {
(None, CursorKind::Hidden)
}
/// May be used by the parent component to compute the child area.
@ -137,20 +138,19 @@ impl Compositor {
layer.render(area, surface, cx)
}
let pos = self
.cursor_position(area, cx.editor)
.map(|pos| (pos.col as u16, pos.row as u16));
let (pos, kind) = self.cursor(area, cx.editor);
let pos = pos.map(|pos| (pos.col as u16, pos.row as u16));
self.terminal.draw(pos);
self.terminal.draw(pos, kind);
}
pub fn cursor_position(&self, area: Rect, editor: &Editor) -> Option<Position> {
pub fn cursor(&self, area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
for layer in self.layers.iter().rev() {
if let Some(pos) = layer.cursor_position(area, editor) {
return Some(pos);
if let (Some(pos), kind) = layer.cursor(area, editor) {
return (Some(pos), kind);
}
}
None
(None, CursorKind::Hidden)
}
pub fn find(&mut self, type_name: &str) -> Option<&mut dyn Component> {

@ -26,6 +26,7 @@ use tui::{
buffer::Buffer as Surface,
layout::Rect,
style::{Color, Modifier, Style},
terminal::CursorKind,
};
pub struct EditorView {
@ -739,15 +740,12 @@ impl Component for EditorView {
}
}
fn cursor_position(&self, area: Rect, editor: &Editor) -> Option<Position> {
fn cursor(&self, area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
// match view.doc.mode() {
// Mode::Insert => write!(stdout, "\x1B[6 q"),
// mode => write!(stdout, "\x1B[2 q"),
// };
// return editor.cursor_position()
// It's easier to just not render the cursor and use selection rendering instead.
None
editor.cursor()
}
}

@ -16,6 +16,7 @@ use crate::ui::{Prompt, PromptEvent};
use helix_core::Position;
use helix_view::editor::Action;
use helix_view::Editor;
use tui::terminal::CursorKind;
pub struct Picker<T> {
options: Vec<T>,
@ -304,7 +305,7 @@ impl<T: 'static> Component for Picker<T> {
}
}
fn cursor_position(&self, area: Rect, editor: &Editor) -> Option<Position> {
fn cursor(&self, area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
// TODO: this is mostly duplicate code
let area = inner_rect(area);
let block = Block::default().borders(Borders::ALL);
@ -314,6 +315,6 @@ impl<T: 'static> Component for Picker<T> {
// prompt area
let area = Rect::new(inner.x + 1, inner.y, inner.width - 1, 1);
self.prompt.cursor_position(area, editor)
self.prompt.cursor(area, editor)
}
}

@ -116,7 +116,7 @@ impl<T: Component> Component for Popup<T> {
let position = self
.position
.or_else(|| cx.editor.cursor_position())
.or_else(|| cx.editor.cursor().0)
.unwrap_or_default();
let (width, height) = self.size;

@ -4,6 +4,7 @@ use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
use helix_core::Position;
use helix_view::{Editor, Theme};
use std::{borrow::Cow, ops::RangeFrom};
use tui::terminal::CursorKind;
pub type Completion = (RangeFrom<usize>, Cow<'static, str>);
@ -342,11 +343,14 @@ impl Component for Prompt {
self.render_prompt(area, surface, cx)
}
fn cursor_position(&self, area: Rect, editor: &Editor) -> Option<Position> {
fn cursor(&self, area: Rect, editor: &Editor) -> (Option<Position>, CursorKind) {
let line = area.height as usize - 1;
Some(Position::new(
area.y as usize + line,
area.x as usize + self.prompt.len() + self.cursor,
))
(
Some(Position::new(
area.y as usize + line,
area.x as usize + self.prompt.len() + self.cursor,
)),
CursorKind::Block,
)
}
}

@ -8,6 +8,19 @@ enum ResizeBehavior {
Auto,
}
#[derive(Debug)]
/// UNSTABLE
pub enum CursorKind {
/// █
Block,
/// |
// Bar,
/// _
// Underline,
/// Hidden cursor, can set cursor position with this to let IME have correct cursor position.
Hidden,
}
#[derive(Debug, Clone, PartialEq)]
/// UNSTABLE
pub struct Viewport {
@ -147,7 +160,11 @@ where
/// Synchronizes terminal size, calls the rendering closure, flushes the current internal state
/// and prepares for the next draw call.
pub fn draw(&mut self, cursor_position: Option<(u16, u16)>) -> io::Result<()> {
pub fn draw(
&mut self,
cursor_position: Option<(u16, u16)>,
cursor_kind: CursorKind,
) -> io::Result<()> {
// // Autoresize - otherwise we get glitches if shrinking or potential desync between widgets
// // and the terminal (if growing), which may OOB.
// self.autoresize()?;
@ -162,12 +179,13 @@ where
// Draw to stdout
self.flush()?;
match cursor_position {
None => self.hide_cursor()?,
Some((x, y)) => {
self.show_cursor()?;
self.set_cursor(x, y)?;
}
if let Some((x, y)) = cursor_position {
self.set_cursor(x, y)?;
}
match cursor_kind {
CursorKind::Block => self.show_cursor()?,
CursorKind::Hidden => self.hide_cursor()?,
}
// Swap buffers

@ -1,5 +1,6 @@
use crate::{theme::Theme, tree::Tree, Document, DocumentId, RegisterSelection, View, ViewId};
use tui::layout::Rect;
use tui::terminal::CursorKind;
use std::path::PathBuf;
@ -9,6 +10,7 @@ use anyhow::Error;
pub use helix_core::diagnostic::Severity;
pub use helix_core::register::Registers;
use helix_core::Position;
#[derive(Debug)]
pub struct Editor {
@ -276,7 +278,7 @@ impl Editor {
// let doc = &mut editor.documents[id];
// }
pub fn cursor_position(&self) -> Option<helix_core::Position> {
pub fn cursor(&self) -> (Option<Position>, CursorKind) {
const OFFSET: u16 = 7; // 1 diagnostic + 5 linenr + 1 gutter
let view = self.view();
let doc = &self.documents[view.doc];
@ -284,8 +286,9 @@ impl Editor {
if let Some(mut pos) = view.screen_coords_at_pos(doc, doc.text().slice(..), cursor) {
pos.col += view.area.x as usize + OFFSET as usize;
pos.row += view.area.y as usize;
return Some(pos);
(Some(pos), CursorKind::Hidden)
} else {
(None, CursorKind::Hidden)
}
None
}
}

Loading…
Cancel
Save