Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cursor position #273

Merged
merged 2 commits into from
Jun 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
)
}
}
13 changes: 10 additions & 3 deletions helix-tui/src/backend/crossterm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ use crate::{
buffer::Cell,
layout::Rect,
style::{Color, Modifier},
terminal::CursorKind,
};
use crossterm::{
cursor::{Hide, MoveTo, Show},
cursor::{CursorShape, Hide, MoveTo, SetCursorShape, Show},
execute, queue,
style::{
Attribute as CAttribute, Color as CColor, Print, SetAttribute, SetBackgroundColor,
Expand Down Expand Up @@ -93,8 +94,14 @@ where
map_error(execute!(self.buffer, Hide))
}

fn show_cursor(&mut self) -> io::Result<()> {
map_error(execute!(self.buffer, Show))
fn show_cursor(&mut self, kind: CursorKind) -> io::Result<()> {
let shape = match kind {
CursorKind::Block => CursorShape::Block,
CursorKind::Bar => CursorShape::Line,
CursorKind::Underline => CursorShape::UnderScore,
CursorKind::Hidden => unreachable!(),
};
map_error(execute!(self.buffer, Show, SetCursorShape(shape)))
}

fn get_cursor(&mut self) -> io::Result<(u16, u16)> {
Expand Down
3 changes: 2 additions & 1 deletion helix-tui/src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::io;

use crate::buffer::Cell;
use crate::layout::Rect;
use crate::terminal::CursorKind;

#[cfg(feature = "crossterm")]
mod crossterm;
Expand All @@ -16,7 +17,7 @@ pub trait Backend {
where
I: Iterator<Item = (u16, u16, &'a Cell)>;
fn hide_cursor(&mut self) -> Result<(), io::Error>;
fn show_cursor(&mut self) -> Result<(), io::Error>;
fn show_cursor(&mut self, kind: CursorKind) -> Result<(), io::Error>;
fn get_cursor(&mut self) -> Result<(u16, u16), io::Error>;
fn set_cursor(&mut self, x: u16, y: u16) -> Result<(), io::Error>;
fn clear(&mut self) -> Result<(), io::Error>;
Expand Down
3 changes: 2 additions & 1 deletion helix-tui/src/backend/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::{
backend::Backend,
buffer::{Buffer, Cell},
layout::Rect,
terminal::CursorKind,
};
use std::{fmt::Write, io};
use unicode_width::UnicodeWidthStr;
Expand Down Expand Up @@ -122,7 +123,7 @@ impl Backend for TestBackend {
Ok(())
}

fn show_cursor(&mut self) -> Result<(), io::Error> {
fn show_cursor(&mut self, _kind: CursorKind) -> Result<(), io::Error> {
self.cursor = true;
Ok(())
}
Expand Down
38 changes: 28 additions & 10 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 @@ -57,7 +70,7 @@ where
fn drop(&mut self) {
// Attempt to restore the cursor state
if self.hidden_cursor {
if let Err(err) = self.show_cursor() {
if let Err(err) = self.show_cursor(CursorKind::Block) {
eprintln!("Failed to show the cursor: {}", err);
}
}
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::Hidden => self.hide_cursor()?,
kind => self.show_cursor(kind)?,
}

// Swap buffers
Expand All @@ -185,8 +203,8 @@ where
Ok(())
}

pub fn show_cursor(&mut self) -> io::Result<()> {
self.backend.show_cursor()?;
pub fn show_cursor(&mut self, kind: CursorKind) -> io::Result<()> {
self.backend.show_cursor(kind)?;
self.hidden_cursor = false;
Ok(())
}
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
}
}