2020-09-21 13:24:16 +04:00
|
|
|
use anyhow::Error;
|
|
|
|
|
2020-10-19 12:18:03 +04:00
|
|
|
use std::borrow::Cow;
|
2020-09-21 13:24:16 +04:00
|
|
|
|
2020-10-01 23:16:24 +04:00
|
|
|
use helix_core::{
|
|
|
|
graphemes::{grapheme_width, RopeGraphemes},
|
2020-10-14 07:01:41 +04:00
|
|
|
indent::TAB_WIDTH,
|
2020-10-04 12:15:43 +04:00
|
|
|
History, Position, RopeSlice, State,
|
2020-10-01 23:16:24 +04:00
|
|
|
};
|
|
|
|
use tui::layout::Rect;
|
2020-09-21 13:24:16 +04:00
|
|
|
|
2020-10-14 07:03:10 +04:00
|
|
|
pub const PADDING: usize = 5;
|
|
|
|
|
2020-10-19 12:18:03 +04:00
|
|
|
// TODO: view should be View { doc: Document(state, history,..) }
|
|
|
|
// since we can have multiple views into the same file
|
2020-09-21 13:24:16 +04:00
|
|
|
pub struct View {
|
|
|
|
pub state: State,
|
2020-10-06 12:32:30 +04:00
|
|
|
pub first_line: usize,
|
2020-09-21 13:24:16 +04:00
|
|
|
pub size: (u16, u16),
|
2020-10-19 12:18:03 +04:00
|
|
|
|
2020-10-20 08:58:34 +04:00
|
|
|
// TODO: Doc fields
|
2020-10-19 12:18:03 +04:00
|
|
|
pub history: History,
|
2020-09-21 13:24:16 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl View {
|
2020-10-19 12:18:03 +04:00
|
|
|
pub fn new(state: State, size: (u16, u16)) -> Result<Self, Error> {
|
2020-09-29 13:02:27 +04:00
|
|
|
let view = Self {
|
2020-09-21 13:24:16 +04:00
|
|
|
state,
|
|
|
|
first_line: 0,
|
2020-10-06 13:59:23 +04:00
|
|
|
size,
|
2020-10-04 12:15:43 +04:00
|
|
|
history: History::default(),
|
2020-09-21 13:24:16 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
Ok(view)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn ensure_cursor_in_view(&mut self) {
|
|
|
|
let cursor = self.state.selection().cursor();
|
2020-10-06 12:32:30 +04:00
|
|
|
let line = self.state.doc().char_to_line(cursor);
|
2020-10-10 21:54:16 +04:00
|
|
|
let document_end = self.first_line + (self.size.1 as usize).saturating_sub(2);
|
2020-09-21 13:24:16 +04:00
|
|
|
|
|
|
|
// TODO: side scroll
|
|
|
|
|
2020-10-14 07:03:10 +04:00
|
|
|
if line > document_end.saturating_sub(PADDING) {
|
2020-09-21 13:24:16 +04:00
|
|
|
// scroll down
|
2020-10-14 07:03:10 +04:00
|
|
|
self.first_line += line - (document_end.saturating_sub(PADDING));
|
|
|
|
} else if line < self.first_line + PADDING {
|
2020-09-21 13:24:16 +04:00
|
|
|
// scroll up
|
2020-10-14 07:03:10 +04:00
|
|
|
self.first_line = line.saturating_sub(PADDING);
|
2020-09-21 13:24:16 +04:00
|
|
|
}
|
|
|
|
}
|
2020-10-01 23:16:24 +04:00
|
|
|
|
|
|
|
/// Calculates the last visible line on screen
|
|
|
|
#[inline]
|
2020-10-07 03:41:09 +04:00
|
|
|
pub fn last_line(&self) -> usize {
|
2020-10-10 21:54:16 +04:00
|
|
|
let viewport = Rect::new(6, 0, self.size.0, self.size.1 - 2); // - 2 for statusline and prompt
|
2020-10-01 23:16:24 +04:00
|
|
|
std::cmp::min(
|
2020-10-06 12:32:30 +04:00
|
|
|
self.first_line + (viewport.height as usize),
|
2020-10-01 23:16:24 +04:00
|
|
|
self.state.doc().len_lines() - 1,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Translates a document position to an absolute position in the terminal.
|
|
|
|
/// Returns a (line, col) position if the position is visible on screen.
|
|
|
|
// TODO: Could return width as well for the character width at cursor.
|
2020-10-07 03:41:09 +04:00
|
|
|
pub fn screen_coords_at_pos(&self, text: &RopeSlice, pos: usize) -> Option<Position> {
|
2020-10-01 23:16:24 +04:00
|
|
|
let line = text.char_to_line(pos);
|
|
|
|
|
2020-10-07 03:41:09 +04:00
|
|
|
if line < self.first_line as usize || line > self.last_line() {
|
2020-10-01 23:16:24 +04:00
|
|
|
// Line is not visible on screen
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
|
|
|
let line_start = text.line_to_char(line);
|
|
|
|
let line_slice = text.slice(line_start..pos);
|
|
|
|
let mut col = 0;
|
|
|
|
|
|
|
|
for grapheme in RopeGraphemes::new(&line_slice) {
|
|
|
|
if grapheme == "\t" {
|
2020-10-14 07:01:41 +04:00
|
|
|
col += TAB_WIDTH;
|
2020-10-01 23:16:24 +04:00
|
|
|
} else {
|
|
|
|
let grapheme = Cow::from(grapheme);
|
|
|
|
col += grapheme_width(&grapheme);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let row = line - self.first_line as usize;
|
|
|
|
|
|
|
|
Some(Position::new(row, col))
|
|
|
|
}
|
2020-09-21 13:24:16 +04:00
|
|
|
}
|