on master help sign in
Fix cursor positioning.
commitef0d062b1fd202fe89bc4bbd33826c46f660ef70 authorBlaž Hrastnik <blaz@mxxn.io> dateSun 13 Dec 2020, 13:29 (6 years ago) parent8695415
5 files changed+46−50
helix-term/src/application.rs+4−26 helix-term/src/component.rs−20 helix-term/src/compositor.rs+14 helix-term/src/editor_view.rs+20−4 helix-term/src/prompt.rs+8
helix-term/src/application.rs+4−26
@@ -9,7 +9,6 @@ use crate::prompt::Prompt;
99use log::{debug, info};
1010
1111use std::{
12− borrow::Cow,
1312 io::{self, stdout, Stdout, Write},
1413 path::PathBuf,
1514 time::Duration,
@@ -47,31 +46,9 @@ pub struct Application {
4746// TODO: temp
4847#[inline(always)]
4948pub fn text_color() -> Style {
50− return Style::default().fg(Color::Rgb(219, 191, 239)); // lilac
49+ Style::default().fg(Color::Rgb(219, 191, 239)) // lilac
5150}
5251
53−// pub fn render_cursor(&mut self, view: &View, prompt: Option<&Prompt>, viewport: Rect) {
54−// let mut stdout = stdout();
55−// match view.doc.mode() {
56−// Mode::Insert => write!(stdout, "\x1B[6 q"),
57−// mode => write!(stdout, "\x1B[2 q"),
58−// };
59−// let pos = if let Some(prompt) = prompt {
60−// Position::new(self.size.0 as usize, 2 + prompt.cursor)
61−// } else {
62−// let cursor = view.doc.state.selection().cursor();
63−
64−// let mut pos = view
65−// .screen_coords_at_pos(&view.doc.text().slice(..), cursor)
66−// .expect("Cursor is out of bounds.");
67−// pos.col += viewport.x as usize;
68−// pos.row += viewport.y as usize;
69−// pos
70−// };
71−
72−// execute!(stdout, cursor::MoveTo(pos.col as u16, pos.row as u16));
73−// }
74−
7552impl Application {
7653 pub fn new(mut args: Args, executor: &'static smol::Executor<'static>) -> Result<Self, Error> {
7754 let backend = CrosstermBackend::new(stdout());
@@ -106,13 +83,14 @@ impl Application {
10683 let editor = &mut self.editor;
10784 let compositor = &self.compositor;
10885
109− // TODO: should be unnecessary
110− // self.terminal.autoresize();
11186 let mut cx = crate::compositor::Context { editor, executor };
11287 let area = self.terminal.size().unwrap();
88+
11389 compositor.render(area, self.terminal.current_buffer_mut(), &mut cx);
90+ let pos = compositor.cursor_position(area, &mut cx);
11491
11592 self.terminal.draw();
93+ self.terminal.set_cursor(pos.col as u16, pos.row as u16);
11694 }
11795
11896 pub async fn event_loop(&mut self) {
helix-term/src/component.rsdeleted−20
@@ -1,20 +0,0 @@
1−// IDEA: render to a cache buffer, then if not changed, copy the buf into the parent
2−type Surface = ();
3−pub trait Component {
4− /// Process input events, return true if handled.
5− fn process_event(&mut self, event: crossterm::event::Event, args: ()) -> bool;
6− /// Should redraw? Useful for saving redraw cycles if we know component didn't change.
7− fn should_update(&self) -> bool {
8− true
9− }
10−
11− fn render(&mut self, surface: &mut Surface, args: ());
12−}
13−
14−// HStack / VStack
15−// focus by component id: each View/Editor gets it's own incremental id at create
16−// Component: View(Arc<State>) -> multiple views can point to same state
17−// id 0 = prompt?
18−// when entering to prompt, it needs to direct Commands to last focus window
19−// -> prompt.trigger(focus_id), on_leave -> focus(focus_id)
20−// popups on another layer
helix-term/src/compositor.rs+14
@@ -14,6 +14,7 @@
1414// cursive does compositor.screen_mut().add_layer_at(pos::absolute(x, y), <component>)
1515
1616use crossterm::event::Event;
17+use helix_core::Position;
1718use smol::Executor;
1819use tui::buffer::Buffer as Surface;
1920use tui::layout::Rect;
@@ -52,6 +53,10 @@ pub trait Component {
5253 }
5354
5455 fn render(&self, area: Rect, frame: &mut Surface, ctx: &mut Context);
56+
57+ fn cursor_position(&self, area: Rect, ctx: &mut Context) -> Option<Position> {
58+ None
59+ }
5560}
5661
5762// struct Editor { };
@@ -138,4 +143,13 @@ impl Compositor {
138143 layer.render(area, surface, cx)
139144 }
140145 }
146+
147+ pub fn cursor_position(&self, area: Rect, cx: &mut Context) -> Position {
148+ for layer in self.layers.iter().rev() {
149+ if let Some(pos) = layer.cursor_position(area, cx) {
150+ return pos;
151+ }
152+ }
153+ panic!("No layer returned a position!");
154+ }
141155}
helix-term/src/editor_view.rs+20−4
@@ -21,6 +21,8 @@ pub struct EditorView {
2121 keymap: Keymaps,
2222}
2323
24+const OFFSET: u16 = 7; // 1 diagnostic + 5 linenr + 1 gutter
25+
2426impl EditorView {
2527 pub fn new() -> Self {
2628 Self {
@@ -34,11 +36,10 @@ impl EditorView {
3436 surface: &mut Surface,
3537 theme: &Theme,
3638 ) {
37− const OFFSET: u16 = 7; // 1 diagnostic + 5 linenr + 1 gutter
3839 let area = Rect::new(OFFSET, 0, viewport.width - OFFSET, viewport.height - 2); // - 2 for statusline and prompt
3940 self.render_buffer(view, area, surface, theme);
4041 let area = Rect::new(0, viewport.height - 2, viewport.width, 1);
41− self.render_statusline(view, viewport, surface, theme);
42+ self.render_statusline(view, area, surface, theme);
4243 }
4344
4445 // TODO: ideally not &mut View but highlights require it because of cursor cache
@@ -218,7 +219,7 @@ impl EditorView {
218219 };
219220 // statusline
220221 surface.set_style(
221− Rect::new(0, viewport.y, viewport.height, 1),
222+ Rect::new(0, viewport.y, viewport.width, 1),
222223 theme.get("ui.statusline"),
223224 );
224225 surface.set_string(1, viewport.y, mode, text_color());
@@ -306,6 +307,21 @@ impl Component for EditorView {
306307 }
307308
308309 // TODO: drop unwrap
309− // TODO: !!! self.render_cursor(cx.editor.view().unwrap(), None, viewport);
310+ }
311+
312+ fn cursor_position(&self, area: Rect, ctx: &mut Context) -> Option<Position> {
313+ // match view.doc.mode() {
314+ // Mode::Insert => write!(stdout, "\x1B[6 q"),
315+ // mode => write!(stdout, "\x1B[2 q"),
316+ // };
317+ let view = ctx.editor.view().unwrap();
318+ let cursor = view.doc.state.selection().cursor();
319+
320+ let mut pos = view
321+ .screen_coords_at_pos(&view.doc.text().slice(..), cursor)
322+ .expect("Cursor is out of bounds.");
323+ pos.col += area.x as usize + OFFSET as usize;
324+ pos.row += area.y as usize;
325+ Some(pos)
310326 }
311327}
helix-term/src/prompt.rs+8
@@ -1,5 +1,6 @@
11use crate::compositor::{Component, Context, EventResult};
22use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
3+use helix_core::Position;
34use helix_view::Editor;
45use helix_view::Theme;
56use std::string::String;
@@ -200,4 +201,11 @@ impl Component for Prompt {
200201 fn render(&self, area: Rect, surface: &mut Surface, cx: &mut Context) {
201202 self.render_prompt(area, surface, &cx.editor.theme)
202203 }
204+
205+ fn cursor_position(&self, area: Rect, ctx: &mut Context) -> Option<Position> {
206+ Some(Position::new(
207+ area.height as usize - 1,
208+ area.x as usize + 2 + self.cursor,
209+ ))
210+ }
203211}