Skip to content

Commit

Permalink
Add cursor kind to separate hidden cursor from pos
Browse files Browse the repository at this point in the history
Now IME cursor position should be correct since we can still set cursor
position without drawing the cursor.
  • Loading branch information
pickfire committed Jun 15, 2021
1 parent 6bdf609 commit 1190ace
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 34 deletions.
22 changes: 11 additions & 11 deletions helix-term/src/compositor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)>;

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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> {
Expand Down
8 changes: 3 additions & 5 deletions helix-term/src/ui/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use tui::{
buffer::Buffer as Surface,
layout::Rect,
style::{Color, Modifier, Style},
terminal::CursorKind,
};

pub struct EditorView {
Expand Down Expand Up @@ -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()
}
}

Expand Down
5 changes: 3 additions & 2 deletions helix-term/src/ui/picker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down Expand Up @@ -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);
Expand 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)
}
}
2 changes: 1 addition & 1 deletion helix-term/src/ui/popup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
14 changes: 9 additions & 5 deletions helix-term/src/ui/prompt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>);

Expand Down Expand Up @@ -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,
)
}
}
32 changes: 25 additions & 7 deletions helix-tui/src/terminal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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()?;
Expand All @@ -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
Expand Down
9 changes: 6 additions & 3 deletions helix-view/src/editor.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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 {
Expand Down Expand Up @@ -276,16 +278,17 @@ 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];
let cursor = doc.selection(view.id).cursor();
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
}
}

0 comments on commit 1190ace

Please sign in to comment.