remove View.offset in favour of Document.view_data.view_position

pull/10559/head
Ingrid 2 months ago
parent 1e02af1817
commit 0bc31f8499

@ -381,10 +381,21 @@ impl Application {
self.editor.refresh_config(); self.editor.refresh_config();
// reset view position in case softwrap was enabled/disabled // reset view position in case softwrap was enabled/disabled
let mut view_position_resets = Vec::new();
let scrolloff = self.editor.config().scrolloff; let scrolloff = self.editor.config().scrolloff;
for (view, _) in self.editor.tree.views_mut() { for (view, _) in self.editor.tree.views() {
let doc = &self.editor.documents[&view.doc]; let doc = &self.editor.documents[&view.doc];
view.ensure_cursor_in_view(doc, scrolloff)
if let Some(offset) = view.offset_coords_to_in_view_center::<false>(doc, scrolloff) {
view_position_resets.push((offset, view.id, view.doc));
}
}
for (offset, view_id, doc_id) in view_position_resets {
self.editor
.document_mut(doc_id)
.unwrap()
.view_data_mut(view_id)
.view_position = offset;
} }
} }

@ -1023,6 +1023,7 @@ fn goto_window(cx: &mut Context, align: Align) {
let count = cx.count() - 1; let count = cx.count() - 1;
let config = cx.editor.config(); let config = cx.editor.config();
let (view, doc) = current!(cx.editor); let (view, doc) = current!(cx.editor);
let view_offset = doc.view_data_mut(view.id).view_position;
let height = view.inner_height(); let height = view.inner_height();
@ -1035,15 +1036,15 @@ fn goto_window(cx: &mut Context, align: Align) {
let last_visual_line = view.last_visual_line(doc); let last_visual_line = view.last_visual_line(doc);
let visual_line = match align { let visual_line = match align {
Align::Top => view.offset.vertical_offset + scrolloff + count, Align::Top => view_offset.vertical_offset + scrolloff + count,
Align::Center => view.offset.vertical_offset + (last_visual_line / 2), Align::Center => view_offset.vertical_offset + (last_visual_line / 2),
Align::Bottom => { Align::Bottom => {
view.offset.vertical_offset + last_visual_line.saturating_sub(scrolloff + count) view_offset.vertical_offset + last_visual_line.saturating_sub(scrolloff + count)
} }
}; };
let visual_line = visual_line let visual_line = visual_line
.max(view.offset.vertical_offset + scrolloff) .max(view_offset.vertical_offset + scrolloff)
.min(view.offset.vertical_offset + last_visual_line.saturating_sub(scrolloff)); .min(view_offset.vertical_offset + last_visual_line.saturating_sub(scrolloff));
let pos = view let pos = view
.pos_at_visual_coords(doc, visual_line as u16, 0, false) .pos_at_visual_coords(doc, visual_line as u16, 0, false)
@ -1667,6 +1668,7 @@ pub fn scroll(cx: &mut Context, offset: usize, direction: Direction, sync_cursor
use Direction::*; use Direction::*;
let config = cx.editor.config(); let config = cx.editor.config();
let (view, doc) = current!(cx.editor); let (view, doc) = current!(cx.editor);
let view_offset = doc.view_data_mut(view.id).view_position;
let range = doc.selection(view.id).primary(); let range = doc.selection(view.id).primary();
let text = doc.text().slice(..); let text = doc.text().slice(..);
@ -1683,15 +1685,21 @@ pub fn scroll(cx: &mut Context, offset: usize, direction: Direction, sync_cursor
let doc_text = doc.text().slice(..); let doc_text = doc.text().slice(..);
let viewport = view.inner_area(doc); let viewport = view.inner_area(doc);
let text_fmt = doc.text_format(viewport.width, None); let text_fmt = doc.text_format(viewport.width, None);
let mut annotations = view.text_annotations(&*doc, None); let annotations = view.text_annotations(&*doc, None);
(view.offset.anchor, view.offset.vertical_offset) = char_idx_at_visual_offset( let (new_anchor, new_vertical_offset) = char_idx_at_visual_offset(
doc_text, doc_text,
view.offset.anchor, view_offset.anchor,
view.offset.vertical_offset as isize + offset, view_offset.vertical_offset as isize + offset,
0, 0,
&text_fmt, &text_fmt,
&annotations, &annotations,
); );
let view_data = doc.view_data_mut(view.id);
view_data.view_position.anchor = new_anchor;
view_data.view_position.vertical_offset = new_vertical_offset;
let doc_text = doc.text().slice(..);
let mut annotations = view.text_annotations(&*doc, None);
if sync_cursor { if sync_cursor {
let movement = match cx.editor.mode { let movement = match cx.editor.mode {
@ -1717,14 +1725,16 @@ pub fn scroll(cx: &mut Context, offset: usize, direction: Direction, sync_cursor
return; return;
} }
let view_offset = doc.view_data(view.id).unwrap().view_position;
let mut head; let mut head;
match direction { match direction {
Forward => { Forward => {
let off; let off;
(head, off) = char_idx_at_visual_offset( (head, off) = char_idx_at_visual_offset(
doc_text, doc_text,
view.offset.anchor, view_offset.anchor,
(view.offset.vertical_offset + scrolloff) as isize, (view_offset.vertical_offset + scrolloff) as isize,
0, 0,
&text_fmt, &text_fmt,
&annotations, &annotations,
@ -1737,8 +1747,8 @@ pub fn scroll(cx: &mut Context, offset: usize, direction: Direction, sync_cursor
Backward => { Backward => {
head = char_idx_at_visual_offset( head = char_idx_at_visual_offset(
doc_text, doc_text,
view.offset.anchor, view_offset.anchor,
(view.offset.vertical_offset + height - scrolloff - 1) as isize, (view_offset.vertical_offset + height - scrolloff - 1) as isize,
0, 0,
&text_fmt, &text_fmt,
&annotations, &annotations,
@ -5132,7 +5142,7 @@ fn split(editor: &mut Editor, action: Action) {
let (view, doc) = current!(editor); let (view, doc) = current!(editor);
let id = doc.id(); let id = doc.id();
let selection = doc.selection(view.id).clone(); let selection = doc.selection(view.id).clone();
let offset = view.offset; let offset = doc.view_data(view.id).unwrap().view_position;
editor.switch(id, action); editor.switch(id, action);
@ -5141,7 +5151,7 @@ fn split(editor: &mut Editor, action: Action) {
doc.set_selection(view.id, selection); doc.set_selection(view.id, selection);
// match the view scroll offset (switch doesn't handle this fully // match the view scroll offset (switch doesn't handle this fully
// since the selection is only matched after the split) // since the selection is only matched after the split)
view.offset = offset; doc.view_data_mut(view.id).view_position = offset;
} }
fn hsplit(cx: &mut Context) { fn hsplit(cx: &mut Context) {
@ -5238,10 +5248,16 @@ fn align_view_middle(cx: &mut Context) {
let doc_text = doc.text().slice(..); let doc_text = doc.text().slice(..);
let annotations = view.text_annotations(doc, None); let annotations = view.text_annotations(doc, None);
let pos = doc.selection(view.id).primary().cursor(doc_text); let pos = doc.selection(view.id).primary().cursor(doc_text);
let pos = let pos = visual_offset_from_block(
visual_offset_from_block(doc_text, view.offset.anchor, pos, &text_fmt, &annotations).0; doc_text,
doc.view_data(view.id).unwrap().view_position.anchor,
pos,
&text_fmt,
&annotations,
)
.0;
view.offset.horizontal_offset = pos doc.view_data_mut(view.id).view_position.horizontal_offset = pos
.col .col
.saturating_sub((view.inner_area(doc).width as usize) / 2); .saturating_sub((view.inner_area(doc).width as usize) / 2);
} }
@ -6104,7 +6120,8 @@ fn jump_to_word(cx: &mut Context, behaviour: Movement) {
// This is not necessarily exact if there is virtual text like soft wrap. // This is not necessarily exact if there is virtual text like soft wrap.
// It's ok though because the extra jump labels will not be rendered. // It's ok though because the extra jump labels will not be rendered.
let start = text.line_to_char(text.char_to_line(view.offset.anchor)); let start =
text.line_to_char(text.char_to_line(doc.view_data(view.id).unwrap().view_position.anchor));
let end = text.line_to_char(view.estimate_last_doc_line(doc) + 1); let end = text.line_to_char(view.estimate_last_doc_line(doc) + 1);
let primary_selection = doc.selection(view.id).primary(); let primary_selection = doc.selection(view.id).primary();

@ -1208,7 +1208,13 @@ fn compute_inlay_hints_for_view(
// than computing all the hints for the full file (which could be dozens of time // than computing all the hints for the full file (which could be dozens of time
// longer than the view is). // longer than the view is).
let view_height = view.inner_height(); let view_height = view.inner_height();
let first_visible_line = doc_text.char_to_line(view.offset.anchor.min(doc_text.len_chars())); let first_visible_line = doc_text.char_to_line(
doc.view_data(view_id)
.unwrap()
.view_position
.anchor
.min(doc_text.len_chars()),
);
let first_line = first_visible_line.saturating_sub(view_height); let first_line = first_visible_line.saturating_sub(view_height);
let last_line = first_visible_line let last_line = first_visible_line
.saturating_add(view_height.saturating_mul(2)) .saturating_add(view_height.saturating_mul(2))

@ -1554,7 +1554,13 @@ fn tree_sitter_highlight_name(
// Query the same range as the one used in syntax highlighting. // Query the same range as the one used in syntax highlighting.
let range = { let range = {
// Calculate viewport byte ranges: // Calculate viewport byte ranges:
let row = text.char_to_line(view.offset.anchor.min(text.len_chars())); let row = text.char_to_line(
doc.view_data(view.id)
.unwrap()
.view_position
.anchor
.min(text.len_chars()),
);
// Saturating subs to make it inclusive zero indexing. // Saturating subs to make it inclusive zero indexing.
let last_line = text.len_lines().saturating_sub(1); let last_line = text.len_lines().saturating_sub(1);
let height = view.inner_area(doc).height; let height = view.inner_area(doc).height;

@ -93,6 +93,8 @@ impl EditorView {
let theme = &editor.theme; let theme = &editor.theme;
let config = editor.config(); let config = editor.config();
let view_offset = doc.view_data(view.id).unwrap().view_position;
let text_annotations = view.text_annotations(doc, Some(theme)); let text_annotations = view.text_annotations(doc, Some(theme));
let mut line_decorations: Vec<Box<dyn LineDecoration>> = Vec::new(); let mut line_decorations: Vec<Box<dyn LineDecoration>> = Vec::new();
let mut translated_positions: Vec<TranslatedPosition> = Vec::new(); let mut translated_positions: Vec<TranslatedPosition> = Vec::new();
@ -123,13 +125,13 @@ impl EditorView {
} }
let syntax_highlights = let syntax_highlights =
Self::doc_syntax_highlights(doc, view.offset.anchor, inner.height, theme); Self::doc_syntax_highlights(doc, view_offset.anchor, inner.height, theme);
let mut overlay_highlights = let mut overlay_highlights =
Self::empty_highlight_iter(doc, view.offset.anchor, inner.height); Self::empty_highlight_iter(doc, view_offset.anchor, inner.height);
let overlay_syntax_highlights = Self::overlay_syntax_highlights( let overlay_syntax_highlights = Self::overlay_syntax_highlights(
doc, doc,
view.offset.anchor, view_offset.anchor,
inner.height, inner.height,
&text_annotations, &text_annotations,
); );
@ -196,7 +198,7 @@ impl EditorView {
surface, surface,
inner, inner,
doc, doc,
view.offset, view_offset,
&text_annotations, &text_annotations,
syntax_highlights, syntax_highlights,
overlay_highlights, overlay_highlights,
@ -249,11 +251,13 @@ impl EditorView {
.and_then(|config| config.rulers.as_ref()) .and_then(|config| config.rulers.as_ref())
.unwrap_or(editor_rulers); .unwrap_or(editor_rulers);
let view_offset = doc.view_data(view.id).unwrap().view_position;
rulers rulers
.iter() .iter()
// View might be horizontally scrolled, convert from absolute distance // View might be horizontally scrolled, convert from absolute distance
// from the 1st column to relative distance from left of viewport // from the 1st column to relative distance from left of viewport
.filter_map(|ruler| ruler.checked_sub(1 + view.offset.horizontal_offset as u16)) .filter_map(|ruler| ruler.checked_sub(1 + view_offset.horizontal_offset as u16))
.filter(|ruler| ruler < &viewport.width) .filter(|ruler| ruler < &viewport.width)
.map(|ruler| viewport.clip_left(ruler).with_width(1)) .map(|ruler| viewport.clip_left(ruler).with_width(1))
.for_each(|area| surface.set_style(area, ruler_theme)) .for_each(|area| surface.set_style(area, ruler_theme))
@ -823,6 +827,7 @@ impl EditorView {
let inner_area = view.inner_area(doc); let inner_area = view.inner_area(doc);
let selection = doc.selection(view.id); let selection = doc.selection(view.id);
let view_offset = doc.view_data(view.id).unwrap().view_position;
let primary = selection.primary(); let primary = selection.primary();
let text_format = doc.text_format(viewport.width, None); let text_format = doc.text_format(viewport.width, None);
for range in selection.iter() { for range in selection.iter() {
@ -833,11 +838,11 @@ impl EditorView {
visual_offset_from_block(text, cursor, cursor, &text_format, text_annotations).0; visual_offset_from_block(text, cursor, cursor, &text_format, text_annotations).0;
// if the cursor is horizontally in the view // if the cursor is horizontally in the view
if col >= view.offset.horizontal_offset if col >= view_offset.horizontal_offset
&& inner_area.width > (col - view.offset.horizontal_offset) as u16 && inner_area.width > (col - view_offset.horizontal_offset) as u16
{ {
let area = Rect::new( let area = Rect::new(
inner_area.x + (col - view.offset.horizontal_offset) as u16, inner_area.x + (col - view_offset.horizontal_offset) as u16,
view.area.y, view.area.y,
1, 1,
view.area.height, view.area.height,

@ -82,7 +82,7 @@ pub fn raw_regex_prompt(
let (view, doc) = current!(cx.editor); let (view, doc) = current!(cx.editor);
let doc_id = view.doc; let doc_id = view.doc;
let snapshot = doc.selection(view.id).clone(); let snapshot = doc.selection(view.id).clone();
let offset_snapshot = view.offset; let offset_snapshot = doc.view_data(view.id).unwrap().view_position;
let config = cx.editor.config(); let config = cx.editor.config();
let mut prompt = Prompt::new( let mut prompt = Prompt::new(
@ -94,7 +94,7 @@ pub fn raw_regex_prompt(
PromptEvent::Abort => { PromptEvent::Abort => {
let (view, doc) = current!(cx.editor); let (view, doc) = current!(cx.editor);
doc.set_selection(view.id, snapshot.clone()); doc.set_selection(view.id, snapshot.clone());
view.offset = offset_snapshot; doc.view_data_mut(view.id).view_position = offset_snapshot;
} }
PromptEvent::Update | PromptEvent::Validate => { PromptEvent::Update | PromptEvent::Validate => {
// skip empty input // skip empty input
@ -135,7 +135,7 @@ pub fn raw_regex_prompt(
Err(err) => { Err(err) => {
let (view, doc) = current!(cx.editor); let (view, doc) = current!(cx.editor);
doc.set_selection(view.id, snapshot.clone()); doc.set_selection(view.id, snapshot.clone());
view.offset = offset_snapshot; doc.view_data_mut(view.id).view_position = offset_snapshot;
if event == PromptEvent::Validate { if event == PromptEvent::Validate {
let callback = async move { let callback = async move {

@ -1165,12 +1165,16 @@ impl Document {
self.set_selection(view_id, Selection::single(origin.anchor, origin.head)); self.set_selection(view_id, Selection::single(origin.anchor, origin.head));
} }
/// Initializes a new selection for the given view if it does not /// Initializes a new selection and view_data for the given view
/// already have one. /// if it does not already have them.
pub fn ensure_view_init(&mut self, view_id: ViewId) { pub fn ensure_view_init(&mut self, view_id: ViewId) {
if self.selections.get(&view_id).is_none() { if self.selections.get(&view_id).is_none() {
self.reset_selection(view_id); self.reset_selection(view_id);
} }
if self.view_data(view_id).is_none() {
self.view_data.insert(view_id, ViewData::default());
}
} }
/// Mark document as recent used for MRU sorting /// Mark document as recent used for MRU sorting
@ -1216,6 +1220,12 @@ impl Document {
.ensure_invariants(self.text.slice(..)); .ensure_invariants(self.text.slice(..));
} }
for view_data in self.view_data.values_mut() {
view_data.view_position.anchor = transaction
.changes()
.map_pos(view_data.view_position.anchor, Assoc::Before);
}
// if specified, the current selection should instead be replaced by transaction.selection // if specified, the current selection should instead be replaced by transaction.selection
if let Some(selection) = transaction.selection() { if let Some(selection) = transaction.selection() {
self.selections.insert( self.selections.insert(

@ -7,7 +7,6 @@ use crate::{
register::Registers, register::Registers,
theme::{self, Theme}, theme::{self, Theme},
tree::{self, Tree}, tree::{self, Tree},
view::ViewPosition,
Document, DocumentId, View, ViewId, Document, DocumentId, View, ViewId,
}; };
use dap::StackFrame; use dap::StackFrame;
@ -1463,19 +1462,9 @@ impl Editor {
let scrolloff = self.config().scrolloff; let scrolloff = self.config().scrolloff;
let view = self.tree.get_mut(current_view); let view = self.tree.get_mut(current_view);
if let Some(old_doc) = self.documents.get_mut(&view.doc) {
old_doc.view_data_mut(current_view).view_position = view.offset;
}
view.doc = doc_id; view.doc = doc_id;
let doc = doc_mut!(self, &doc_id); let doc = doc_mut!(self, &doc_id);
view.offset = if let Some(view_data) = doc.view_data(current_view) {
view_data.view_position
} else {
ViewPosition::default()
};
doc.ensure_view_init(view.id); doc.ensure_view_init(view.id);
view.sync_changes(doc); view.sync_changes(doc);
doc.mark_as_focused(); doc.mark_as_focused();
@ -1838,8 +1827,8 @@ impl Editor {
pub fn ensure_cursor_in_view(&mut self, id: ViewId) { pub fn ensure_cursor_in_view(&mut self, id: ViewId) {
let config = self.config(); let config = self.config();
let view = self.tree.get_mut(id); let view = self.tree.get(id).clone();
let doc = &self.documents[&view.doc]; let doc = self.document_mut(view.doc).unwrap();
view.ensure_cursor_in_view(doc, config.scrolloff) view.ensure_cursor_in_view(doc, config.scrolloff)
} }

@ -46,7 +46,7 @@ pub enum Align {
Bottom, Bottom,
} }
pub fn align_view(doc: &Document, view: &mut View, align: Align) { pub fn align_view(doc: &mut Document, view: &View, align: Align) {
let doc_text = doc.text().slice(..); let doc_text = doc.text().slice(..);
let cursor = doc.selection(view.id).primary().cursor(doc_text); let cursor = doc.selection(view.id).primary().cursor(doc_text);
let viewport = view.inner_area(doc); let viewport = view.inner_area(doc);
@ -60,7 +60,7 @@ pub fn align_view(doc: &Document, view: &mut View, align: Align) {
let text_fmt = doc.text_format(viewport.width, None); let text_fmt = doc.text_format(viewport.width, None);
let annotations = view.text_annotations(doc, None); let annotations = view.text_annotations(doc, None);
(view.offset.anchor, view.offset.vertical_offset) = char_idx_at_visual_offset( let (new_anchor, new_vertical_offset) = char_idx_at_visual_offset(
doc_text, doc_text,
cursor, cursor,
-(relative as isize), -(relative as isize),
@ -68,6 +68,9 @@ pub fn align_view(doc: &Document, view: &mut View, align: Align) {
&text_fmt, &text_fmt,
&annotations, &annotations,
); );
let view_data = doc.view_data_mut(view.id);
view_data.view_position.anchor = new_anchor;
view_data.view_position.vertical_offset = new_vertical_offset;
} }
pub use document::Document; pub use document::Document;

@ -110,7 +110,6 @@ pub struct ViewPosition {
#[derive(Clone)] #[derive(Clone)]
pub struct View { pub struct View {
pub id: ViewId, pub id: ViewId,
pub offset: ViewPosition,
pub area: Rect, pub area: Rect,
pub doc: DocumentId, pub doc: DocumentId,
pub jumps: JumpList, pub jumps: JumpList,
@ -147,11 +146,6 @@ impl View {
Self { Self {
id: ViewId::default(), id: ViewId::default(),
doc, doc,
offset: ViewPosition {
anchor: 0,
horizontal_offset: 0,
vertical_offset: 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
docs_access_history: Vec::new(), docs_access_history: Vec::new(),
@ -213,9 +207,10 @@ impl View {
doc: &Document, doc: &Document,
scrolloff: usize, scrolloff: usize,
) -> Option<ViewPosition> { ) -> Option<ViewPosition> {
let view_offset = doc.view_data(self.id)?.view_position;
let doc_text = doc.text().slice(..); let doc_text = doc.text().slice(..);
let viewport = self.inner_area(doc); let viewport = self.inner_area(doc);
let vertical_viewport_end = self.offset.vertical_offset + viewport.height as usize; let vertical_viewport_end = view_offset.vertical_offset + viewport.height as usize;
let text_fmt = doc.text_format(viewport.width, None); let text_fmt = doc.text_format(viewport.width, None);
let annotations = self.text_annotations(doc, None); let annotations = self.text_annotations(doc, None);
@ -229,7 +224,7 @@ impl View {
}; };
let cursor = doc.selection(self.id).primary().cursor(doc_text); let cursor = doc.selection(self.id).primary().cursor(doc_text);
let mut offset = self.offset; let mut offset = view_offset;
let off = visual_offset_from_anchor( let off = visual_offset_from_anchor(
doc_text, doc_text,
offset.anchor, offset.anchor,
@ -294,22 +289,22 @@ impl View {
} }
// if we are not centering return None if view position is unchanged // if we are not centering return None if view position is unchanged
if !CENTERING && offset == self.offset { if !CENTERING && offset == view_offset {
return None; return None;
} }
Some(offset) Some(offset)
} }
pub fn ensure_cursor_in_view(&mut self, doc: &Document, scrolloff: usize) { pub fn ensure_cursor_in_view(&self, doc: &mut Document, scrolloff: usize) {
if let Some(offset) = self.offset_coords_to_in_view_center::<false>(doc, scrolloff) { if let Some(offset) = self.offset_coords_to_in_view_center::<false>(doc, scrolloff) {
self.offset = offset; doc.view_data_mut(self.id).view_position = offset;
} }
} }
pub fn ensure_cursor_in_view_center(&mut self, doc: &Document, scrolloff: usize) { pub fn ensure_cursor_in_view_center(&self, doc: &mut Document, scrolloff: usize) {
if let Some(offset) = self.offset_coords_to_in_view_center::<true>(doc, scrolloff) { if let Some(offset) = self.offset_coords_to_in_view_center::<true>(doc, scrolloff) {
self.offset = offset; doc.view_data_mut(self.id).view_position = offset;
} else { } else {
align_view(doc, self, Align::Center); align_view(doc, self, Align::Center);
} }
@ -327,7 +322,13 @@ impl View {
#[inline] #[inline]
pub fn estimate_last_doc_line(&self, doc: &Document) -> usize { pub fn estimate_last_doc_line(&self, doc: &Document) -> usize {
let doc_text = doc.text().slice(..); let doc_text = doc.text().slice(..);
let line = doc_text.char_to_line(self.offset.anchor.min(doc_text.len_chars())); let line = doc_text.char_to_line(
doc.view_data(self.id)
.unwrap()
.view_position
.anchor
.min(doc_text.len_chars()),
);
// Saturating subs to make it inclusive zero indexing. // Saturating subs to make it inclusive zero indexing.
(line + self.inner_height()) (line + self.inner_height())
.min(doc_text.len_lines()) .min(doc_text.len_lines())
@ -341,9 +342,15 @@ impl View {
let viewport = self.inner_area(doc); let viewport = self.inner_area(doc);
let text_fmt = doc.text_format(viewport.width, None); let text_fmt = doc.text_format(viewport.width, None);
let annotations = self.text_annotations(doc, None); let annotations = self.text_annotations(doc, None);
let view_offset = doc.view_data(self.id).unwrap().view_position;
// last visual line in view is trivial to compute // last visual line in view is trivial to compute
let visual_height = self.offset.vertical_offset + viewport.height as usize; let visual_height = doc
.view_data(self.id)
.unwrap()
.view_position
.vertical_offset
+ viewport.height as usize;
// fast path when the EOF is not visible on the screen, // fast path when the EOF is not visible on the screen,
if self.estimate_last_doc_line(doc) < doc_text.len_lines() - 1 { if self.estimate_last_doc_line(doc) < doc_text.len_lines() - 1 {
@ -353,7 +360,7 @@ impl View {
// translate to document line // translate to document line
let pos = visual_offset_from_anchor( let pos = visual_offset_from_anchor(
doc_text, doc_text,
self.offset.anchor, view_offset.anchor,
usize::MAX, usize::MAX,
&text_fmt, &text_fmt,
&annotations, &annotations,
@ -361,7 +368,7 @@ impl View {
); );
match pos { match pos {
Ok((Position { row, .. }, _)) => row.saturating_sub(self.offset.vertical_offset), Ok((Position { row, .. }, _)) => row.saturating_sub(view_offset.vertical_offset),
Err(PosAfterMaxRow) => visual_height.saturating_sub(1), Err(PosAfterMaxRow) => visual_height.saturating_sub(1),
Err(PosBeforeAnchorRow) => 0, Err(PosBeforeAnchorRow) => 0,
} }
@ -376,7 +383,9 @@ impl View {
text: RopeSlice, text: RopeSlice,
pos: usize, pos: usize,
) -> Option<Position> { ) -> Option<Position> {
if pos < self.offset.anchor { let view_offset = doc.view_data(self.id).unwrap().view_position;
if pos < view_offset.anchor {
// Line is not visible on screen // Line is not visible on screen
return None; return None;
} }
@ -387,7 +396,7 @@ impl View {
let mut pos = visual_offset_from_anchor( let mut pos = visual_offset_from_anchor(
text, text,
self.offset.anchor, view_offset.anchor,
pos, pos,
&text_fmt, &text_fmt,
&annotations, &annotations,
@ -395,14 +404,14 @@ impl View {
) )
.ok()? .ok()?
.0; .0;
if pos.row < self.offset.vertical_offset { if pos.row < view_offset.vertical_offset {
return None; return None;
} }
pos.row -= self.offset.vertical_offset; pos.row -= view_offset.vertical_offset;
if pos.row >= viewport.height as usize { if pos.row >= viewport.height as usize {
return None; return None;
} }
pos.col = pos.col.saturating_sub(self.offset.horizontal_offset); pos.col = pos.col.saturating_sub(view_offset.horizontal_offset);
Some(pos) Some(pos)
} }
@ -496,13 +505,14 @@ impl View {
ignore_virtual_text: bool, ignore_virtual_text: bool,
) -> Option<usize> { ) -> Option<usize> {
let text = doc.text().slice(..); let text = doc.text().slice(..);
let view_offset = doc.view_data(self.id).unwrap().view_position;
let text_row = row as usize + self.offset.vertical_offset; let text_row = row as usize + view_offset.vertical_offset;
let text_col = column as usize + self.offset.horizontal_offset; let text_col = column as usize + view_offset.horizontal_offset;
let (char_idx, virt_lines) = char_idx_at_visual_offset( let (char_idx, virt_lines) = char_idx_at_visual_offset(
text, text,
self.offset.anchor, view_offset.anchor,
text_row as isize, text_row as isize,
text_col, text_col,
&text_fmt, &text_fmt,
@ -650,11 +660,12 @@ mod tests {
let mut view = View::new(DocumentId::default(), GutterConfig::default()); let mut view = View::new(DocumentId::default(), GutterConfig::default());
view.area = Rect::new(40, 40, 40, 40); view.area = Rect::new(40, 40, 40, 40);
let rope = Rope::from_str("abc\n\tdef"); let rope = Rope::from_str("abc\n\tdef");
let doc = Document::from( let mut doc = Document::from(
rope, rope,
None, None,
Arc::new(ArcSwap::new(Arc::new(Config::default()))), Arc::new(ArcSwap::new(Arc::new(Config::default()))),
); );
doc.ensure_view_init(view.id);
assert_eq!( assert_eq!(
view.text_pos_at_screen_coords( view.text_pos_at_screen_coords(
@ -824,11 +835,12 @@ mod tests {
); );
view.area = Rect::new(40, 40, 40, 40); view.area = Rect::new(40, 40, 40, 40);
let rope = Rope::from_str("abc\n\tdef"); let rope = Rope::from_str("abc\n\tdef");
let doc = Document::from( let mut doc = Document::from(
rope, rope,
None, None,
Arc::new(ArcSwap::new(Arc::new(Config::default()))), Arc::new(ArcSwap::new(Arc::new(Config::default()))),
); );
doc.ensure_view_init(view.id);
assert_eq!( assert_eq!(
view.text_pos_at_screen_coords( view.text_pos_at_screen_coords(
&doc, &doc,
@ -853,11 +865,12 @@ mod tests {
); );
view.area = Rect::new(40, 40, 40, 40); view.area = Rect::new(40, 40, 40, 40);
let rope = Rope::from_str("abc\n\tdef"); let rope = Rope::from_str("abc\n\tdef");
let doc = Document::from( let mut doc = Document::from(
rope, rope,
None, None,
Arc::new(ArcSwap::new(Arc::new(Config::default()))), Arc::new(ArcSwap::new(Arc::new(Config::default()))),
); );
doc.ensure_view_init(view.id);
assert_eq!( assert_eq!(
view.text_pos_at_screen_coords( view.text_pos_at_screen_coords(
&doc, &doc,
@ -876,11 +889,12 @@ mod tests {
let mut view = View::new(DocumentId::default(), GutterConfig::default()); let mut view = View::new(DocumentId::default(), GutterConfig::default());
view.area = Rect::new(40, 40, 40, 40); view.area = Rect::new(40, 40, 40, 40);
let rope = Rope::from_str("Hi! こんにちは皆さん"); let rope = Rope::from_str("Hi! こんにちは皆さん");
let doc = Document::from( let mut doc = Document::from(
rope, rope,
None, None,
Arc::new(ArcSwap::new(Arc::new(Config::default()))), Arc::new(ArcSwap::new(Arc::new(Config::default()))),
); );
doc.ensure_view_init(view.id);
assert_eq!( assert_eq!(
view.text_pos_at_screen_coords( view.text_pos_at_screen_coords(
@ -959,11 +973,12 @@ mod tests {
let mut view = View::new(DocumentId::default(), GutterConfig::default()); let mut view = View::new(DocumentId::default(), GutterConfig::default());
view.area = Rect::new(40, 40, 40, 40); view.area = Rect::new(40, 40, 40, 40);
let rope = Rope::from_str("Hèl̀l̀ò world!"); let rope = Rope::from_str("Hèl̀l̀ò world!");
let doc = Document::from( let mut doc = Document::from(
rope, rope,
None, None,
Arc::new(ArcSwap::new(Arc::new(Config::default()))), Arc::new(ArcSwap::new(Arc::new(Config::default()))),
); );
doc.ensure_view_init(view.id);
assert_eq!( assert_eq!(
view.text_pos_at_screen_coords( view.text_pos_at_screen_coords(

Loading…
Cancel
Save