aboutsummaryrefslogtreecommitdiff
path: root/helix-term
diff options
context:
space:
mode:
authorBlaž Hrastnik2020-12-13 04:29:34 +0000
committerBlaž Hrastnik2020-12-13 04:30:19 +0000
commitef0d062b1fd202fe89bc4bbd33826c46f660ef70 (patch)
tree77c10da4a77557c358f440368ba6f5506a3b7c9f /helix-term
parent8695415fbfe927250f68e93793660e3c4e4a70b4 (diff)
Fix cursor positioning.
Diffstat (limited to 'helix-term')
-rw-r--r--helix-term/src/application.rs30
-rw-r--r--helix-term/src/component.rs20
-rw-r--r--helix-term/src/compositor.rs14
-rw-r--r--helix-term/src/editor_view.rs24
-rw-r--r--helix-term/src/prompt.rs8
5 files changed, 46 insertions, 50 deletions
diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs
index 7a74f8ba..c25871c7 100644
--- a/helix-term/src/application.rs
+++ b/helix-term/src/application.rs
@@ -9,7 +9,6 @@ use crate::prompt::Prompt;
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 @@ impl Application {
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) {
diff --git a/helix-term/src/component.rs b/helix-term/src/component.rs
deleted file mode 100644
index 08d6c620..00000000
--- a/helix-term/src/component.rs
+++ /dev/null
@@ -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
diff --git a/helix-term/src/compositor.rs b/helix-term/src/compositor.rs
index 1d94ee63..2e65f02a 100644
--- a/helix-term/src/compositor.rs
+++ b/helix-term/src/compositor.rs
@@ -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 @@ pub trait Component {
}
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 @@ impl Compositor {
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!");
+ }
}
diff --git a/helix-term/src/editor_view.rs b/helix-term/src/editor_view.rs
index 0181623a..b778e79b 100644
--- a/helix-term/src/editor_view.rs
+++ b/helix-term/src/editor_view.rs
@@ -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 @@ impl EditorView {
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 @@ impl EditorView {
};
// 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 @@ impl Component for EditorView {
}
// 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)
}
}
diff --git a/helix-term/src/prompt.rs b/helix-term/src/prompt.rs
index 4747c9f5..7f473ebc 100644
--- a/helix-term/src/prompt.rs
+++ b/helix-term/src/prompt.rs
@@ -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 @@ impl Component for Prompt {
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,
+ ))
+ }
}