mirror of
https://github.com/helix-editor/helix
synced 2024-11-10 10:34:45 +01:00
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.
This commit is contained in:
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
Block a user