|
|
@ -61,8 +61,7 @@ impl JumpList {
|
|
|
|
pub struct View {
|
|
|
|
pub struct View {
|
|
|
|
pub id: ViewId,
|
|
|
|
pub id: ViewId,
|
|
|
|
pub doc: DocumentId,
|
|
|
|
pub doc: DocumentId,
|
|
|
|
pub first_line: usize,
|
|
|
|
pub offset: Position,
|
|
|
|
pub first_col: usize,
|
|
|
|
|
|
|
|
pub area: Rect,
|
|
|
|
pub area: Rect,
|
|
|
|
pub jumps: JumpList,
|
|
|
|
pub jumps: JumpList,
|
|
|
|
/// the last accessed file before the current one
|
|
|
|
/// the last accessed file before the current one
|
|
|
@ -74,8 +73,7 @@ impl View {
|
|
|
|
Self {
|
|
|
|
Self {
|
|
|
|
id: ViewId::default(),
|
|
|
|
id: ViewId::default(),
|
|
|
|
doc,
|
|
|
|
doc,
|
|
|
|
first_line: 0,
|
|
|
|
offset: Position::new(0, 0),
|
|
|
|
first_col: 0,
|
|
|
|
|
|
|
|
area: Rect::default(), // will get calculated upon inserting into tree
|
|
|
|
area: Rect::default(), // will get calculated upon inserting into tree
|
|
|
|
jumps: JumpList::new((doc, Selection::point(0))), // TODO: use actual sel
|
|
|
|
jumps: JumpList::new((doc, Selection::point(0))), // TODO: use actual sel
|
|
|
|
last_accessed_doc: None,
|
|
|
|
last_accessed_doc: None,
|
|
|
@ -91,7 +89,7 @@ impl View {
|
|
|
|
let line = pos.row;
|
|
|
|
let line = pos.row;
|
|
|
|
let col = pos.col;
|
|
|
|
let col = pos.col;
|
|
|
|
let height = self.area.height.saturating_sub(1); // - 1 for statusline
|
|
|
|
let height = self.area.height.saturating_sub(1); // - 1 for statusline
|
|
|
|
let last_line = (self.first_line + height as usize).saturating_sub(1);
|
|
|
|
let last_line = (self.offset.row + height as usize).saturating_sub(1);
|
|
|
|
|
|
|
|
|
|
|
|
// - 1 so we have at least one gap in the middle.
|
|
|
|
// - 1 so we have at least one gap in the middle.
|
|
|
|
// a height of 6 with padding of 3 on each side will keep shifting the view back and forth
|
|
|
|
// a height of 6 with padding of 3 on each side will keep shifting the view back and forth
|
|
|
@ -100,22 +98,22 @@ impl View {
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: not ideal
|
|
|
|
// TODO: not ideal
|
|
|
|
const OFFSET: usize = 7; // 1 diagnostic + 5 linenr + 1 gutter
|
|
|
|
const OFFSET: usize = 7; // 1 diagnostic + 5 linenr + 1 gutter
|
|
|
|
let last_col = (self.first_col + self.area.width as usize).saturating_sub(OFFSET + 1);
|
|
|
|
let last_col = (self.offset.col + self.area.width as usize).saturating_sub(OFFSET + 1);
|
|
|
|
|
|
|
|
|
|
|
|
if line > last_line.saturating_sub(scrolloff) {
|
|
|
|
if line > last_line.saturating_sub(scrolloff) {
|
|
|
|
// scroll down
|
|
|
|
// scroll down
|
|
|
|
self.first_line += line - (last_line.saturating_sub(scrolloff));
|
|
|
|
self.offset.row += line - (last_line.saturating_sub(scrolloff));
|
|
|
|
} else if line < self.first_line + scrolloff {
|
|
|
|
} else if line < self.offset.row + scrolloff {
|
|
|
|
// scroll up
|
|
|
|
// scroll up
|
|
|
|
self.first_line = line.saturating_sub(scrolloff);
|
|
|
|
self.offset.row = line.saturating_sub(scrolloff);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if col > last_col.saturating_sub(scrolloff) {
|
|
|
|
if col > last_col.saturating_sub(scrolloff) {
|
|
|
|
// scroll right
|
|
|
|
// scroll right
|
|
|
|
self.first_col += col - (last_col.saturating_sub(scrolloff));
|
|
|
|
self.offset.col += col - (last_col.saturating_sub(scrolloff));
|
|
|
|
} else if col < self.first_col + scrolloff {
|
|
|
|
} else if col < self.offset.col + scrolloff {
|
|
|
|
// scroll left
|
|
|
|
// scroll left
|
|
|
|
self.first_col = col.saturating_sub(scrolloff);
|
|
|
|
self.offset.col = col.saturating_sub(scrolloff);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -125,7 +123,7 @@ impl View {
|
|
|
|
let height = self.area.height.saturating_sub(1); // - 1 for statusline
|
|
|
|
let height = self.area.height.saturating_sub(1); // - 1 for statusline
|
|
|
|
std::cmp::min(
|
|
|
|
std::cmp::min(
|
|
|
|
// Saturating subs to make it inclusive zero indexing.
|
|
|
|
// Saturating subs to make it inclusive zero indexing.
|
|
|
|
(self.first_line + height as usize).saturating_sub(1),
|
|
|
|
(self.offset.row + height as usize).saturating_sub(1),
|
|
|
|
doc.text().len_lines().saturating_sub(1),
|
|
|
|
doc.text().len_lines().saturating_sub(1),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -141,7 +139,7 @@ impl View {
|
|
|
|
) -> Option<Position> {
|
|
|
|
) -> Option<Position> {
|
|
|
|
let line = text.char_to_line(pos);
|
|
|
|
let line = text.char_to_line(pos);
|
|
|
|
|
|
|
|
|
|
|
|
if line < self.first_line || line > self.last_line(doc) {
|
|
|
|
if line < self.offset.row || line > self.last_line(doc) {
|
|
|
|
// Line is not visible on screen
|
|
|
|
// Line is not visible on screen
|
|
|
|
return None;
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -161,8 +159,8 @@ impl View {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// It is possible for underflow to occur if the buffer length is larger than the terminal width.
|
|
|
|
// It is possible for underflow to occur if the buffer length is larger than the terminal width.
|
|
|
|
let row = line.saturating_sub(self.first_line);
|
|
|
|
let row = line.saturating_sub(self.offset.row);
|
|
|
|
let col = col.saturating_sub(self.first_col);
|
|
|
|
let col = col.saturating_sub(self.offset.col);
|
|
|
|
|
|
|
|
|
|
|
|
Some(Position::new(row, col))
|
|
|
|
Some(Position::new(row, col))
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -186,7 +184,7 @@ impl View {
|
|
|
|
return None;
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let line_number = (row - self.area.y) as usize + self.first_line;
|
|
|
|
let line_number = (row - self.area.y) as usize + self.offset.row;
|
|
|
|
|
|
|
|
|
|
|
|
if line_number > text.len_lines() - 1 {
|
|
|
|
if line_number > text.len_lines() - 1 {
|
|
|
|
return Some(text.len_chars());
|
|
|
|
return Some(text.len_chars());
|
|
|
@ -196,7 +194,7 @@ impl View {
|
|
|
|
|
|
|
|
|
|
|
|
let current_line = text.line(line_number);
|
|
|
|
let current_line = text.line(line_number);
|
|
|
|
|
|
|
|
|
|
|
|
let target = (column - OFFSET - self.area.x) as usize + self.first_col;
|
|
|
|
let target = (column - OFFSET - self.area.x) as usize + self.offset.col;
|
|
|
|
let mut selected = 0;
|
|
|
|
let mut selected = 0;
|
|
|
|
|
|
|
|
|
|
|
|
for grapheme in RopeGraphemes::new(current_line) {
|
|
|
|
for grapheme in RopeGraphemes::new(current_line) {
|
|
|
|