Fix cursor positioning.

pull/6/head
Blaž Hrastnik 4 years ago
parent 8695415fbf
commit ef0d062b1f

@ -9,7 +9,6 @@ use crate::prompt::Prompt;
use log::{debug, info}; use log::{debug, info};
use std::{ use std::{
borrow::Cow,
io::{self, stdout, Stdout, Write}, io::{self, stdout, Stdout, Write},
path::PathBuf, path::PathBuf,
time::Duration, time::Duration,
@ -47,31 +46,9 @@ pub struct Application {
// TODO: temp // TODO: temp
#[inline(always)] #[inline(always)]
pub fn text_color() -> Style { 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 { impl Application {
pub fn new(mut args: Args, executor: &'static smol::Executor<'static>) -> Result<Self, Error> { pub fn new(mut args: Args, executor: &'static smol::Executor<'static>) -> Result<Self, Error> {
let backend = CrosstermBackend::new(stdout()); let backend = CrosstermBackend::new(stdout());
@ -106,13 +83,14 @@ impl Application {
let editor = &mut self.editor; let editor = &mut self.editor;
let compositor = &self.compositor; let compositor = &self.compositor;
// TODO: should be unnecessary
// self.terminal.autoresize();
let mut cx = crate::compositor::Context { editor, executor }; let mut cx = crate::compositor::Context { editor, executor };
let area = self.terminal.size().unwrap(); let area = self.terminal.size().unwrap();
compositor.render(area, self.terminal.current_buffer_mut(), &mut cx); compositor.render(area, self.terminal.current_buffer_mut(), &mut cx);
let pos = compositor.cursor_position(area, &mut cx);
self.terminal.draw(); self.terminal.draw();
self.terminal.set_cursor(pos.col as u16, pos.row as u16);
} }
pub async fn event_loop(&mut self) { pub async fn event_loop(&mut self) {

@ -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

@ -14,6 +14,7 @@
// cursive does compositor.screen_mut().add_layer_at(pos::absolute(x, y), <component>) // cursive does compositor.screen_mut().add_layer_at(pos::absolute(x, y), <component>)
use crossterm::event::Event; use crossterm::event::Event;
use helix_core::Position;
use smol::Executor; use smol::Executor;
use tui::buffer::Buffer as Surface; use tui::buffer::Buffer as Surface;
use tui::layout::Rect; use tui::layout::Rect;
@ -52,6 +53,10 @@ pub trait Component {
} }
fn render(&self, area: Rect, frame: &mut Surface, ctx: &mut Context); 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 { }; // struct Editor { };
@ -138,4 +143,13 @@ impl Compositor {
layer.render(area, surface, cx) 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!");
}
} }

@ -21,6 +21,8 @@ pub struct EditorView {
keymap: Keymaps, keymap: Keymaps,
} }
const OFFSET: u16 = 7; // 1 diagnostic + 5 linenr + 1 gutter
impl EditorView { impl EditorView {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
@ -34,11 +36,10 @@ impl EditorView {
surface: &mut Surface, surface: &mut Surface,
theme: &Theme, 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 let area = Rect::new(OFFSET, 0, viewport.width - OFFSET, viewport.height - 2); // - 2 for statusline and prompt
self.render_buffer(view, area, surface, theme); self.render_buffer(view, area, surface, theme);
let area = Rect::new(0, viewport.height - 2, viewport.width, 1); 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 // TODO: ideally not &mut View but highlights require it because of cursor cache
@ -218,7 +219,7 @@ impl EditorView {
}; };
// statusline // statusline
surface.set_style( surface.set_style(
Rect::new(0, viewport.y, viewport.height, 1), Rect::new(0, viewport.y, viewport.width, 1),
theme.get("ui.statusline"), theme.get("ui.statusline"),
); );
surface.set_string(1, viewport.y, mode, text_color()); surface.set_string(1, viewport.y, mode, text_color());
@ -306,6 +307,21 @@ impl Component for EditorView {
} }
// TODO: drop unwrap // 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)
} }
} }

@ -1,5 +1,6 @@
use crate::compositor::{Component, Context, EventResult}; use crate::compositor::{Component, Context, EventResult};
use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers}; use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
use helix_core::Position;
use helix_view::Editor; use helix_view::Editor;
use helix_view::Theme; use helix_view::Theme;
use std::string::String; use std::string::String;
@ -200,4 +201,11 @@ impl Component for Prompt {
fn render(&self, area: Rect, surface: &mut Surface, cx: &mut Context) { fn render(&self, area: Rect, surface: &mut Surface, cx: &mut Context) {
self.render_prompt(area, surface, &cx.editor.theme) 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,
))
}
} }

Loading…
Cancel
Save