1
0
Fork 0
mirror of https://github.com/helix-editor/helix synced 2024-06-07 21:56:04 +02:00

Fix cursor positioning.

This commit is contained in:
Blaž Hrastnik 2020-12-13 13:29:34 +09:00
parent 8695415fbf
commit ef0d062b1f
5 changed files with 46 additions and 50 deletions

View File

@ -9,7 +9,6 @@
use log::{debug, info};
use std::{
borrow::Cow,
io::{self, stdout, Stdout, Write},
path::PathBuf,
time::Duration,
@ -47,31 +46,9 @@ pub struct Application {
// TODO: temp
#[inline(always)]
pub fn text_color() -> Style {
return Style::default().fg(Color::Rgb(219, 191, 239)); // lilac
Style::default().fg(Color::Rgb(219, 191, 239)) // lilac
}
// pub fn render_cursor(&mut self, view: &View, prompt: Option<&Prompt>, viewport: Rect) {
// let mut stdout = stdout();
// match view.doc.mode() {
// Mode::Insert => write!(stdout, "\x1B[6 q"),
// mode => write!(stdout, "\x1B[2 q"),
// };
// let pos = if let Some(prompt) = prompt {
// Position::new(self.size.0 as usize, 2 + prompt.cursor)
// } else {
// let cursor = view.doc.state.selection().cursor();
// let mut pos = view
// .screen_coords_at_pos(&view.doc.text().slice(..), cursor)
// .expect("Cursor is out of bounds.");
// pos.col += viewport.x as usize;
// pos.row += viewport.y as usize;
// pos
// };
// execute!(stdout, cursor::MoveTo(pos.col as u16, pos.row as u16));
// }
impl Application {
pub fn new(mut args: Args, executor: &'static smol::Executor<'static>) -> Result<Self, Error> {
let backend = CrosstermBackend::new(stdout());
@ -106,13 +83,14 @@ fn render(&mut self) {
let editor = &mut self.editor;
let compositor = &self.compositor;
// TODO: should be unnecessary
// self.terminal.autoresize();
let mut cx = crate::compositor::Context { editor, executor };
let area = self.terminal.size().unwrap();
compositor.render(area, self.terminal.current_buffer_mut(), &mut cx);
let pos = compositor.cursor_position(area, &mut cx);
self.terminal.draw();
self.terminal.set_cursor(pos.col as u16, pos.row as u16);
}
pub async fn event_loop(&mut self) {

View File

@ -1,20 +0,0 @@
// IDEA: render to a cache buffer, then if not changed, copy the buf into the parent
type Surface = ();
pub trait Component {
/// Process input events, return true if handled.
fn process_event(&mut self, event: crossterm::event::Event, args: ()) -> bool;
/// Should redraw? Useful for saving redraw cycles if we know component didn't change.
fn should_update(&self) -> bool {
true
}
fn render(&mut self, surface: &mut Surface, args: ());
}
// HStack / VStack
// focus by component id: each View/Editor gets it's own incremental id at create
// Component: View(Arc<State>) -> multiple views can point to same state
// id 0 = prompt?
// when entering to prompt, it needs to direct Commands to last focus window
// -> prompt.trigger(focus_id), on_leave -> focus(focus_id)
// popups on another layer

View File

@ -14,6 +14,7 @@
// cursive does compositor.screen_mut().add_layer_at(pos::absolute(x, y), <component>)
use crossterm::event::Event;
use helix_core::Position;
use smol::Executor;
use tui::buffer::Buffer as Surface;
use tui::layout::Rect;
@ -52,6 +53,10 @@ fn should_update(&self) -> bool {
}
fn render(&self, area: Rect, frame: &mut Surface, ctx: &mut Context);
fn cursor_position(&self, area: Rect, ctx: &mut Context) -> Option<Position> {
None
}
}
// struct Editor { };
@ -138,4 +143,13 @@ pub fn render(&self, area: Rect, surface: &mut Surface, cx: &mut Context) {
layer.render(area, surface, cx)
}
}
pub fn cursor_position(&self, area: Rect, cx: &mut Context) -> Position {
for layer in self.layers.iter().rev() {
if let Some(pos) = layer.cursor_position(area, cx) {
return pos;
}
}
panic!("No layer returned a position!");
}
}

View File

@ -21,6 +21,8 @@ pub struct EditorView {
keymap: Keymaps,
}
const OFFSET: u16 = 7; // 1 diagnostic + 5 linenr + 1 gutter
impl EditorView {
pub fn new() -> Self {
Self {
@ -34,11 +36,10 @@ pub fn render_view(
surface: &mut Surface,
theme: &Theme,
) {
const OFFSET: u16 = 7; // 1 diagnostic + 5 linenr + 1 gutter
let area = Rect::new(OFFSET, 0, viewport.width - OFFSET, viewport.height - 2); // - 2 for statusline and prompt
self.render_buffer(view, area, surface, theme);
let area = Rect::new(0, viewport.height - 2, viewport.width, 1);
self.render_statusline(view, viewport, surface, theme);
self.render_statusline(view, area, surface, theme);
}
// TODO: ideally not &mut View but highlights require it because of cursor cache
@ -218,7 +219,7 @@ pub fn render_statusline(
};
// statusline
surface.set_style(
Rect::new(0, viewport.y, viewport.height, 1),
Rect::new(0, viewport.y, viewport.width, 1),
theme.get("ui.statusline"),
);
surface.set_string(1, viewport.y, mode, text_color());
@ -306,6 +307,21 @@ fn render(&self, area: Rect, surface: &mut Surface, cx: &mut Context) {
}
// TODO: drop unwrap
// TODO: !!! self.render_cursor(cx.editor.view().unwrap(), None, viewport);
}
fn cursor_position(&self, area: Rect, ctx: &mut Context) -> Option<Position> {
// match view.doc.mode() {
// Mode::Insert => write!(stdout, "\x1B[6 q"),
// mode => write!(stdout, "\x1B[2 q"),
// };
let view = ctx.editor.view().unwrap();
let cursor = view.doc.state.selection().cursor();
let mut pos = view
.screen_coords_at_pos(&view.doc.text().slice(..), cursor)
.expect("Cursor is out of bounds.");
pos.col += area.x as usize + OFFSET as usize;
pos.row += area.y as usize;
Some(pos)
}
}

View File

@ -1,5 +1,6 @@
use crate::compositor::{Component, Context, EventResult};
use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
use helix_core::Position;
use helix_view::Editor;
use helix_view::Theme;
use std::string::String;
@ -200,4 +201,11 @@ fn handle_event(&mut self, event: Event, cx: &mut Context) -> EventResult {
fn render(&self, area: Rect, surface: &mut Surface, cx: &mut Context) {
self.render_prompt(area, surface, &cx.editor.theme)
}
fn cursor_position(&self, area: Rect, ctx: &mut Context) -> Option<Position> {
Some(Position::new(
area.height as usize - 1,
area.x as usize + 2 + self.cursor,
))
}
}