From 0bc31f849987f81add3d84783866946e80360651 Mon Sep 17 00:00:00 2001 From: Ingrid Date: Mon, 22 Apr 2024 22:10:00 +0200 Subject: [PATCH] remove View.offset in favour of Document.view_data.view_position --- helix-term/src/application.rs | 15 ++++++- helix-term/src/commands.rs | 55 +++++++++++++++-------- helix-term/src/commands/lsp.rs | 8 +++- helix-term/src/commands/typed.rs | 8 +++- helix-term/src/ui/editor.rs | 21 +++++---- helix-term/src/ui/mod.rs | 6 +-- helix-view/src/document.rs | 14 +++++- helix-view/src/editor.rs | 15 +------ helix-view/src/lib.rs | 7 ++- helix-view/src/view.rs | 75 +++++++++++++++++++------------- 10 files changed, 143 insertions(+), 81 deletions(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 6bdf60bca..5095cf489 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -381,10 +381,21 @@ impl Application { self.editor.refresh_config(); // reset view position in case softwrap was enabled/disabled + let mut view_position_resets = Vec::new(); 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]; - view.ensure_cursor_in_view(doc, scrolloff) + + if let Some(offset) = view.offset_coords_to_in_view_center::(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; } } diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index cc7b84c4b..13920a8a4 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1023,6 +1023,7 @@ fn goto_window(cx: &mut Context, align: Align) { let count = cx.count() - 1; let config = cx.editor.config(); let (view, doc) = current!(cx.editor); + let view_offset = doc.view_data_mut(view.id).view_position; 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 visual_line = match align { - Align::Top => view.offset.vertical_offset + scrolloff + count, - Align::Center => view.offset.vertical_offset + (last_visual_line / 2), + Align::Top => view_offset.vertical_offset + scrolloff + count, + Align::Center => view_offset.vertical_offset + (last_visual_line / 2), 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 - .max(view.offset.vertical_offset + scrolloff) - .min(view.offset.vertical_offset + last_visual_line.saturating_sub(scrolloff)); + .max(view_offset.vertical_offset + scrolloff) + .min(view_offset.vertical_offset + last_visual_line.saturating_sub(scrolloff)); let pos = view .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::*; let config = cx.editor.config(); 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 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 viewport = view.inner_area(doc); let text_fmt = doc.text_format(viewport.width, None); - let mut annotations = view.text_annotations(&*doc, None); - (view.offset.anchor, view.offset.vertical_offset) = char_idx_at_visual_offset( + let annotations = view.text_annotations(&*doc, None); + let (new_anchor, new_vertical_offset) = char_idx_at_visual_offset( doc_text, - view.offset.anchor, - view.offset.vertical_offset as isize + offset, + view_offset.anchor, + view_offset.vertical_offset as isize + offset, 0, &text_fmt, &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 { let movement = match cx.editor.mode { @@ -1717,14 +1725,16 @@ pub fn scroll(cx: &mut Context, offset: usize, direction: Direction, sync_cursor return; } + let view_offset = doc.view_data(view.id).unwrap().view_position; + let mut head; match direction { Forward => { let off; (head, off) = char_idx_at_visual_offset( doc_text, - view.offset.anchor, - (view.offset.vertical_offset + scrolloff) as isize, + view_offset.anchor, + (view_offset.vertical_offset + scrolloff) as isize, 0, &text_fmt, &annotations, @@ -1737,8 +1747,8 @@ pub fn scroll(cx: &mut Context, offset: usize, direction: Direction, sync_cursor Backward => { head = char_idx_at_visual_offset( doc_text, - view.offset.anchor, - (view.offset.vertical_offset + height - scrolloff - 1) as isize, + view_offset.anchor, + (view_offset.vertical_offset + height - scrolloff - 1) as isize, 0, &text_fmt, &annotations, @@ -5132,7 +5142,7 @@ fn split(editor: &mut Editor, action: Action) { let (view, doc) = current!(editor); let id = doc.id(); 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); @@ -5141,7 +5151,7 @@ fn split(editor: &mut Editor, action: Action) { doc.set_selection(view.id, selection); // match the view scroll offset (switch doesn't handle this fully // 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) { @@ -5238,10 +5248,16 @@ fn align_view_middle(cx: &mut Context) { let doc_text = doc.text().slice(..); let annotations = view.text_annotations(doc, None); let pos = doc.selection(view.id).primary().cursor(doc_text); - let pos = - visual_offset_from_block(doc_text, view.offset.anchor, pos, &text_fmt, &annotations).0; + let pos = visual_offset_from_block( + 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 .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. // 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 primary_selection = doc.selection(view.id).primary(); diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 88bd07919..b413df787 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -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 // longer than the view is). 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 last_line = first_visible_line .saturating_add(view_height.saturating_mul(2)) diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index f38ae6bba..1bc5de20c 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1554,7 +1554,13 @@ fn tree_sitter_highlight_name( // Query the same range as the one used in syntax highlighting. let range = { // 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. let last_line = text.len_lines().saturating_sub(1); let height = view.inner_area(doc).height; diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 97f90f625..a7de2ae29 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -93,6 +93,8 @@ impl EditorView { let theme = &editor.theme; 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 mut line_decorations: Vec> = Vec::new(); let mut translated_positions: Vec = Vec::new(); @@ -123,13 +125,13 @@ impl EditorView { } 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 = - 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( doc, - view.offset.anchor, + view_offset.anchor, inner.height, &text_annotations, ); @@ -196,7 +198,7 @@ impl EditorView { surface, inner, doc, - view.offset, + view_offset, &text_annotations, syntax_highlights, overlay_highlights, @@ -249,11 +251,13 @@ impl EditorView { .and_then(|config| config.rulers.as_ref()) .unwrap_or(editor_rulers); + let view_offset = doc.view_data(view.id).unwrap().view_position; + rulers .iter() // View might be horizontally scrolled, convert from absolute distance // 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) .map(|ruler| viewport.clip_left(ruler).with_width(1)) .for_each(|area| surface.set_style(area, ruler_theme)) @@ -823,6 +827,7 @@ impl EditorView { let inner_area = view.inner_area(doc); let selection = doc.selection(view.id); + let view_offset = doc.view_data(view.id).unwrap().view_position; let primary = selection.primary(); let text_format = doc.text_format(viewport.width, None); for range in selection.iter() { @@ -833,11 +838,11 @@ impl EditorView { visual_offset_from_block(text, cursor, cursor, &text_format, text_annotations).0; // if the cursor is horizontally in the view - if col >= view.offset.horizontal_offset - && inner_area.width > (col - view.offset.horizontal_offset) as u16 + if col >= view_offset.horizontal_offset + && inner_area.width > (col - view_offset.horizontal_offset) as u16 { 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, 1, view.area.height, diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 5211c2e27..e244205b3 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -82,7 +82,7 @@ pub fn raw_regex_prompt( let (view, doc) = current!(cx.editor); let doc_id = view.doc; 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 mut prompt = Prompt::new( @@ -94,7 +94,7 @@ pub fn raw_regex_prompt( PromptEvent::Abort => { let (view, doc) = current!(cx.editor); 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 => { // skip empty input @@ -135,7 +135,7 @@ pub fn raw_regex_prompt( Err(err) => { let (view, doc) = current!(cx.editor); 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 { let callback = async move { diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 3a351794a..32f933b4e 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -1165,12 +1165,16 @@ impl Document { self.set_selection(view_id, Selection::single(origin.anchor, origin.head)); } - /// Initializes a new selection for the given view if it does not - /// already have one. + /// Initializes a new selection and view_data for the given view + /// if it does not already have them. pub fn ensure_view_init(&mut self, view_id: ViewId) { if self.selections.get(&view_id).is_none() { 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 @@ -1216,6 +1220,12 @@ impl Document { .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 let Some(selection) = transaction.selection() { self.selections.insert( diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index b78648936..78498cd4d 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -7,7 +7,6 @@ use crate::{ register::Registers, theme::{self, Theme}, tree::{self, Tree}, - view::ViewPosition, Document, DocumentId, View, ViewId, }; use dap::StackFrame; @@ -1463,19 +1462,9 @@ impl Editor { let scrolloff = self.config().scrolloff; 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; 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); view.sync_changes(doc); doc.mark_as_focused(); @@ -1838,8 +1827,8 @@ impl Editor { pub fn ensure_cursor_in_view(&mut self, id: ViewId) { let config = self.config(); - let view = self.tree.get_mut(id); - let doc = &self.documents[&view.doc]; + let view = self.tree.get(id).clone(); + let doc = self.document_mut(view.doc).unwrap(); view.ensure_cursor_in_view(doc, config.scrolloff) } diff --git a/helix-view/src/lib.rs b/helix-view/src/lib.rs index 14b6e1ce8..4563df48e 100644 --- a/helix-view/src/lib.rs +++ b/helix-view/src/lib.rs @@ -46,7 +46,7 @@ pub enum Align { 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 cursor = doc.selection(view.id).primary().cursor(doc_text); 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 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, cursor, -(relative as isize), @@ -68,6 +68,9 @@ pub fn align_view(doc: &Document, view: &mut View, align: Align) { &text_fmt, &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; diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index 5b283b98f..165b03d82 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -110,7 +110,6 @@ pub struct ViewPosition { #[derive(Clone)] pub struct View { pub id: ViewId, - pub offset: ViewPosition, pub area: Rect, pub doc: DocumentId, pub jumps: JumpList, @@ -147,11 +146,6 @@ impl View { Self { id: ViewId::default(), doc, - offset: ViewPosition { - anchor: 0, - horizontal_offset: 0, - vertical_offset: 0, - }, area: Rect::default(), // will get calculated upon inserting into tree jumps: JumpList::new((doc, Selection::point(0))), // TODO: use actual sel docs_access_history: Vec::new(), @@ -213,9 +207,10 @@ impl View { doc: &Document, scrolloff: usize, ) -> Option { + let view_offset = doc.view_data(self.id)?.view_position; let doc_text = doc.text().slice(..); 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 annotations = self.text_annotations(doc, None); @@ -229,7 +224,7 @@ impl View { }; 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( doc_text, offset.anchor, @@ -294,22 +289,22 @@ impl View { } // if we are not centering return None if view position is unchanged - if !CENTERING && offset == self.offset { + if !CENTERING && offset == view_offset { return None; } 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::(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::(doc, scrolloff) { - self.offset = offset; + doc.view_data_mut(self.id).view_position = offset; } else { align_view(doc, self, Align::Center); } @@ -327,7 +322,13 @@ impl View { #[inline] pub fn estimate_last_doc_line(&self, doc: &Document) -> usize { 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. (line + self.inner_height()) .min(doc_text.len_lines()) @@ -341,9 +342,15 @@ impl View { let viewport = self.inner_area(doc); let text_fmt = doc.text_format(viewport.width, 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 - 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, if self.estimate_last_doc_line(doc) < doc_text.len_lines() - 1 { @@ -353,7 +360,7 @@ impl View { // translate to document line let pos = visual_offset_from_anchor( doc_text, - self.offset.anchor, + view_offset.anchor, usize::MAX, &text_fmt, &annotations, @@ -361,7 +368,7 @@ impl View { ); 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(PosBeforeAnchorRow) => 0, } @@ -376,7 +383,9 @@ impl View { text: RopeSlice, pos: usize, ) -> Option { - 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 return None; } @@ -387,7 +396,7 @@ impl View { let mut pos = visual_offset_from_anchor( text, - self.offset.anchor, + view_offset.anchor, pos, &text_fmt, &annotations, @@ -395,14 +404,14 @@ impl View { ) .ok()? .0; - if pos.row < self.offset.vertical_offset { + if pos.row < view_offset.vertical_offset { return None; } - pos.row -= self.offset.vertical_offset; + pos.row -= view_offset.vertical_offset; if pos.row >= viewport.height as usize { return None; } - pos.col = pos.col.saturating_sub(self.offset.horizontal_offset); + pos.col = pos.col.saturating_sub(view_offset.horizontal_offset); Some(pos) } @@ -496,13 +505,14 @@ impl View { ignore_virtual_text: bool, ) -> Option { 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_col = column as usize + self.offset.horizontal_offset; + let text_row = row as usize + view_offset.vertical_offset; + let text_col = column as usize + view_offset.horizontal_offset; let (char_idx, virt_lines) = char_idx_at_visual_offset( text, - self.offset.anchor, + view_offset.anchor, text_row as isize, text_col, &text_fmt, @@ -650,11 +660,12 @@ mod tests { let mut view = View::new(DocumentId::default(), GutterConfig::default()); view.area = Rect::new(40, 40, 40, 40); let rope = Rope::from_str("abc\n\tdef"); - let doc = Document::from( + let mut doc = Document::from( rope, None, Arc::new(ArcSwap::new(Arc::new(Config::default()))), ); + doc.ensure_view_init(view.id); assert_eq!( view.text_pos_at_screen_coords( @@ -824,11 +835,12 @@ mod tests { ); view.area = Rect::new(40, 40, 40, 40); let rope = Rope::from_str("abc\n\tdef"); - let doc = Document::from( + let mut doc = Document::from( rope, None, Arc::new(ArcSwap::new(Arc::new(Config::default()))), ); + doc.ensure_view_init(view.id); assert_eq!( view.text_pos_at_screen_coords( &doc, @@ -853,11 +865,12 @@ mod tests { ); view.area = Rect::new(40, 40, 40, 40); let rope = Rope::from_str("abc\n\tdef"); - let doc = Document::from( + let mut doc = Document::from( rope, None, Arc::new(ArcSwap::new(Arc::new(Config::default()))), ); + doc.ensure_view_init(view.id); assert_eq!( view.text_pos_at_screen_coords( &doc, @@ -876,11 +889,12 @@ mod tests { let mut view = View::new(DocumentId::default(), GutterConfig::default()); view.area = Rect::new(40, 40, 40, 40); let rope = Rope::from_str("Hi! こんにちは皆さん"); - let doc = Document::from( + let mut doc = Document::from( rope, None, Arc::new(ArcSwap::new(Arc::new(Config::default()))), ); + doc.ensure_view_init(view.id); assert_eq!( view.text_pos_at_screen_coords( @@ -959,11 +973,12 @@ mod tests { let mut view = View::new(DocumentId::default(), GutterConfig::default()); view.area = Rect::new(40, 40, 40, 40); let rope = Rope::from_str("Hèl̀l̀ò world!"); - let doc = Document::from( + let mut doc = Document::from( rope, None, Arc::new(ArcSwap::new(Arc::new(Config::default()))), ); + doc.ensure_view_init(view.id); assert_eq!( view.text_pos_at_screen_coords(