mirror of https://github.com/helix-editor/helix
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
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…
Reference in New Issue