aboutsummaryrefslogtreecommitdiff
path: root/helix-view/src/view.rs
diff options
context:
space:
mode:
authorPascal Kuthe2023-01-31 17:03:19 +0000
committerGitHub2023-01-31 17:03:19 +0000
commit4dcf1fe66ba30a78edc054780d9b65c2f826530f (patch)
treeffb84ea94f07ceb52494a955b1bd78f115395dc0 /helix-view/src/view.rs
parent4eca4b3079bf53de874959270d0b3471d320debc (diff)
rework positioning/rendering and enable softwrap/virtual text (#5420)
* rework positioning/rendering, enables softwrap/virtual text This commit is a large rework of the core text positioning and rendering code in helix to remove the assumption that on-screen columns/lines correspond to text columns/lines. A generic `DocFormatter` is introduced that positions graphemes on and is used both for rendering and for movements/scrolling. Both virtual text support (inline, grapheme overlay and multi-line) and a capable softwrap implementation is included. fix picker highlight cleanup doc formatter, use word bondaries for wrapping make visual vertical movement a seperate commnad estimate line gutter width to improve performance cache cursor position cleanup and optimize doc formatter cleanup documentation fix typos Co-authored-by: Daniel Hines <d4hines@gmail.com> update documentation fix panic in last_visual_line funciton improve soft-wrap documentation add extend_visual_line_up/down commands fix non-visual vertical movement streamline virtual text highlighting, add softwrap indicator fix cursor position if softwrap is disabled improve documentation of text_annotations module avoid crashes if view anchor is out of bounds fix: consider horizontal offset when traslation char_idx -> vpos improve default configuration fix: mixed up horizontal and vertical offset reset view position after config reload apply suggestions from review disabled softwrap for very small screens to avoid endless spin fix wrap_indicator setting fix bar cursor disappearring on the EOF character add keybinding for linewise vertical movement fix: inconsistent gutter highlights improve virtual text API make scope idx lookup more ergonomic allow overlapping overlays correctly track char_pos for virtual text adjust configuration deprecate old position fucntions fix infinite loop in highlight lookup fix gutter style fix formatting document max-line-width interaction with softwrap change wrap-indicator example to use empty string fix: rare panic when view is in invalid state (bis) * Apply suggestions from code review Co-authored-by: Michael Davis <mcarsondavis@gmail.com> * improve documentation for positoning functions * simplify tests * fix documentation of Grapheme::width * Apply suggestions from code review Co-authored-by: Michael Davis <mcarsondavis@gmail.com> * add explicit drop invocation * Add explicit MoveFn type alias * add docuntation to Editor::cursor_cache * fix a few typos * explain use of allow(deprecated) * make gj and gk extend in select mode * remove unneded debug and TODO * mark tab_width_at #[inline] * add fast-path to move_vertically_visual in case softwrap is disabled * rename first_line to first_visual_line * simplify duplicate if/else --------- Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
Diffstat (limited to 'helix-view/src/view.rs')
-rw-r--r--helix-view/src/view.rs647
1 files changed, 519 insertions, 128 deletions
diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs
index abcf9a16..660cce65 100644
--- a/helix-view/src/view.rs
+++ b/helix-view/src/view.rs
@@ -2,11 +2,13 @@ use crate::{
align_view,
editor::{GutterConfig, GutterType},
graphics::Rect,
- Align, Document, DocumentId, ViewId,
+ Align, Document, DocumentId, Theme, ViewId,
};
use helix_core::{
- pos_at_visual_coords, visual_coords_at_pos, Position, RopeSlice, Selection, Transaction,
+ char_idx_at_visual_offset, doc_formatter::TextFormat, text_annotations::TextAnnotations,
+ visual_offset_from_anchor, visual_offset_from_block, Position, RopeSlice, Selection,
+ Transaction,
};
use std::{
@@ -93,10 +95,17 @@ impl JumpList {
}
}
+#[derive(Clone, Debug, PartialEq, Eq, Copy, Default)]
+pub struct ViewPosition {
+ pub anchor: usize,
+ pub horizontal_offset: usize,
+ pub vertical_offset: usize,
+}
+
#[derive(Clone)]
pub struct View {
pub id: ViewId,
- pub offset: Position,
+ pub offset: ViewPosition,
pub area: Rect,
pub doc: DocumentId,
pub jumps: JumpList,
@@ -133,7 +142,11 @@ impl View {
Self {
id: ViewId::default(),
doc,
- offset: Position::new(0, 0),
+ 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(),
@@ -159,6 +172,10 @@ impl View {
self.area.clip_bottom(1).height.into() // -1 for statusline
}
+ pub fn inner_width(&self, doc: &Document) -> u16 {
+ self.area.clip_left(self.gutter_offset(doc)).width
+ }
+
pub fn gutters(&self) -> &[GutterType] {
&self.gutters.layout
}
@@ -176,84 +193,120 @@ impl View {
&self,
doc: &Document,
scrolloff: usize,
- ) -> Option<(usize, usize)> {
- self.offset_coords_to_in_view_center(doc, scrolloff, false)
+ ) -> Option<ViewPosition> {
+ self.offset_coords_to_in_view_center::<false>(doc, scrolloff)
}
- pub fn offset_coords_to_in_view_center(
+ pub fn offset_coords_to_in_view_center<const CENTERING: bool>(
&self,
doc: &Document,
scrolloff: usize,
- centering: bool,
- ) -> Option<(usize, usize)> {
- let cursor = doc
- .selection(self.id)
- .primary()
- .cursor(doc.text().slice(..));
-
- let Position { col, row: line } =
- visual_coords_at_pos(doc.text().slice(..), cursor, doc.tab_width());
-
- let inner_area = self.inner_area(doc);
- let last_line = (self.offset.row + inner_area.height as usize).saturating_sub(1);
- let last_col = self.offset.col + inner_area.width.saturating_sub(1) as usize;
-
- let new_offset = |scrolloff: usize| {
- // - 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
- // as we type
- let scrolloff = scrolloff.min(inner_area.height.saturating_sub(1) as usize / 2);
-
- let row = if line > last_line.saturating_sub(scrolloff) {
- // scroll down
- self.offset.row + line - (last_line.saturating_sub(scrolloff))
- } else if line < self.offset.row + scrolloff {
- // scroll up
- line.saturating_sub(scrolloff)
+ ) -> Option<ViewPosition> {
+ 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 text_fmt = doc.text_format(viewport.width, None);
+ let annotations = self.text_annotations(doc, None);
+
+ // - 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
+ // as we type
+ let scrolloff = scrolloff.min(viewport.height.saturating_sub(1) as usize / 2);
+
+ let cursor = doc.selection(self.id).primary().cursor(doc_text);
+ let mut offset = self.offset;
+
+ let (visual_off, mut at_top) = if cursor >= offset.anchor {
+ let off = visual_offset_from_anchor(
+ doc_text,
+ offset.anchor,
+ cursor,
+ &text_fmt,
+ &annotations,
+ vertical_viewport_end,
+ );
+ (off, false)
+ } else if CENTERING {
+ // cursor out of view
+ return None;
+ } else {
+ (None, true)
+ };
+
+ let new_anchor = match visual_off {
+ Some((visual_pos, _)) if visual_pos.row < scrolloff + offset.vertical_offset => {
+ if CENTERING && visual_pos.row < offset.vertical_offset {
+ // cursor out of view
+ return None;
+ }
+ at_top = true;
+ true
+ }
+ Some((visual_pos, _)) if visual_pos.row >= vertical_viewport_end - scrolloff => {
+ if CENTERING && visual_pos.row >= vertical_viewport_end as usize {
+ // cursor out of view
+ return None;
+ }
+ true
+ }
+ Some(_) => false,
+ None => true,
+ };
+
+ if new_anchor {
+ let v_off = if at_top {
+ scrolloff as isize
} else {
- self.offset.row
+ viewport.height as isize - scrolloff as isize
};
+ (offset.anchor, offset.vertical_offset) =
+ char_idx_at_visual_offset(doc_text, cursor, -v_off, 0, &text_fmt, &annotations);
+ }
- let col = if col > last_col.saturating_sub(scrolloff) {
+ if text_fmt.soft_wrap {
+ offset.horizontal_offset = 0;
+ } else {
+ // determine the current visual column of the text
+ let col = visual_off
+ .unwrap_or_else(|| {
+ visual_offset_from_block(
+ doc_text,
+ offset.anchor,
+ cursor,
+ &text_fmt,
+ &annotations,
+ )
+ })
+ .0
+ .col;
+
+ let last_col = offset.horizontal_offset + viewport.width.saturating_sub(1) as usize;
+ if col > last_col.saturating_sub(scrolloff) {
// scroll right
- self.offset.col + col - (last_col.saturating_sub(scrolloff))
- } else if col < self.offset.col + scrolloff {
+ offset.horizontal_offset += col - (last_col.saturating_sub(scrolloff))
+ } else if col < offset.horizontal_offset + scrolloff {
// scroll left
- col.saturating_sub(scrolloff)
- } else {
- self.offset.col
+ offset.horizontal_offset = col.saturating_sub(scrolloff)
};
- (row, col)
- };
- let current_offset = (self.offset.row, self.offset.col);
- if centering {
- // return None if cursor is out of view
- let offset = new_offset(0);
- (offset == current_offset).then(|| {
- if scrolloff == 0 {
- offset
- } else {
- new_offset(scrolloff)
- }
- })
- } else {
- // return None if cursor is in (view - scrolloff)
- let offset = new_offset(scrolloff);
- (offset != current_offset).then(|| offset) // TODO: use 'then_some' when 1.62 <= MSRV
}
+
+ // if we are not centering return None if view position is unchanged
+ if !CENTERING && offset == self.offset {
+ return None;
+ }
+
+ Some(offset)
}
pub fn ensure_cursor_in_view(&mut self, doc: &Document, scrolloff: usize) {
- if let Some((row, col)) = self.offset_coords_to_in_view_center(doc, scrolloff, false) {
- self.offset.row = row;
- self.offset.col = col;
+ if let Some(offset) = self.offset_coords_to_in_view_center::<false>(doc, scrolloff) {
+ self.offset = offset;
}
}
pub fn ensure_cursor_in_view_center(&mut self, doc: &Document, scrolloff: usize) {
- if let Some((row, col)) = self.offset_coords_to_in_view_center(doc, scrolloff, true) {
- self.offset.row = row;
- self.offset.col = col;
+ if let Some(offset) = self.offset_coords_to_in_view_center::<true>(doc, scrolloff) {
+ self.offset = offset;
} else {
align_view(doc, self, Align::Center);
}
@@ -263,14 +316,51 @@ impl View {
self.offset_coords_to_in_view(doc, scrolloff).is_none()
}
- /// Calculates the last visible line on screen
+ /// Estimates the last visible document line on screen.
+ /// This estimate is an upper bound obtained by calculating the first
+ /// visible line and adding the viewport height.
+ /// The actual last visible line may be smaller if softwrapping occurs
+ /// or virtual text lines are visible
#[inline]
- pub fn last_line(&self, doc: &Document) -> usize {
- std::cmp::min(
- // Saturating subs to make it inclusive zero indexing.
- (self.offset.row + self.inner_height()).saturating_sub(1),
- doc.text().len_lines().saturating_sub(1),
- )
+ 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()));
+ // Saturating subs to make it inclusive zero indexing.
+ (line + self.inner_height())
+ .min(doc_text.len_lines())
+ .saturating_sub(1)
+ }
+
+ /// Calculates the last non-empty visual line on screen
+ #[inline]
+ pub fn last_visual_line(&self, doc: &Document) -> usize {
+ let doc_text = doc.text().slice(..);
+ let viewport = self.inner_area(doc);
+ let text_fmt = doc.text_format(viewport.width, None);
+ let annotations = self.text_annotations(doc, None);
+
+ // last visual line in view is trivial to compute
+ let visual_height = self.offset.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 {
+ return visual_height.saturating_sub(1);
+ }
+
+ // translate to document line
+ let pos = visual_offset_from_anchor(
+ doc_text,
+ self.offset.anchor,
+ usize::MAX,
+ &text_fmt,
+ &annotations,
+ visual_height,
+ );
+
+ match pos {
+ Some((Position { row, .. }, _)) => row.saturating_sub(self.offset.vertical_offset),
+ None => visual_height.saturating_sub(1),
+ }
}
/// Translates a document position to an absolute position in the terminal.
@@ -282,22 +372,39 @@ impl View {
text: RopeSlice,
pos: usize,
) -> Option<Position> {
- let line = text.char_to_line(pos);
-
- if line < self.offset.row || line > self.last_line(doc) {
+ if pos < self.offset.anchor {
// Line is not visible on screen
return None;
}
- let tab_width = doc.tab_width();
- // TODO: visual_coords_at_pos also does char_to_line which we ignore, can we reuse the call?
- let Position { col, .. } = visual_coords_at_pos(text, pos, tab_width);
+ let viewport = self.inner_area(doc);
+ let text_fmt = doc.text_format(viewport.width, None);
+ let annotations = self.text_annotations(doc, None);
+
+ let mut pos = visual_offset_from_anchor(
+ text,
+ self.offset.anchor,
+ pos,
+ &text_fmt,
+ &annotations,
+ viewport.height as usize,
+ )?
+ .0;
+ if pos.row < self.offset.vertical_offset {
+ return None;
+ }
+ pos.row -= self.offset.vertical_offset;
+ if pos.row >= viewport.height as usize {
+ return None;
+ }
+ pos.col = pos.col.saturating_sub(self.offset.horizontal_offset);
- // It is possible for underflow to occur if the buffer length is larger than the terminal width.
- let row = line.saturating_sub(self.offset.row);
- let col = col.saturating_sub(self.offset.col);
+ Some(pos)
+ }
- Some(Position::new(row, col))
+ pub fn text_annotations(&self, doc: &Document, theme: Option<&Theme>) -> TextAnnotations {
+ // TODO custom annotations for custom views like side by side diffs
+ doc.text_annotations(theme)
}
pub fn text_pos_at_screen_coords(
@@ -305,9 +412,10 @@ impl View {
doc: &Document,
row: u16,
column: u16,
- tab_width: usize,
+ fmt: TextFormat,
+ annotations: &TextAnnotations,
+ ignore_virtual_text: bool,
) -> Option<usize> {
- let text = doc.text().slice(..);
let inner = self.inner_area(doc);
// 1 for status
if row < inner.top() || row >= inner.bottom() {
@@ -318,27 +426,80 @@ impl View {
return None;
}
- let text_row = (row - inner.y) as usize + self.offset.row;
- if text_row > text.len_lines() - 1 {
- return Some(text.len_chars());
- }
+ self.text_pos_at_visual_coords(
+ doc,
+ row - inner.y,
+ column - inner.x,
+ fmt,
+ annotations,
+ ignore_virtual_text,
+ )
+ }
+
+ pub fn text_pos_at_visual_coords(
+ &self,
+ doc: &Document,
+ row: u16,
+ column: u16,
+ text_fmt: TextFormat,
+ annotations: &TextAnnotations,
+ ignore_virtual_text: bool,
+ ) -> Option<usize> {
+ let text = doc.text().slice(..);
- let text_col = (column - inner.x) as usize + self.offset.col;
+ let text_row = row as usize + self.offset.vertical_offset;
+ let text_col = column as usize + self.offset.horizontal_offset;
- Some(pos_at_visual_coords(
+ let (char_idx, virt_lines) = char_idx_at_visual_offset(
text,
- Position {
- row: text_row,
- col: text_col,
- },
- tab_width,
- ))
+ self.offset.anchor,
+ text_row as isize,
+ text_col,
+ &text_fmt,
+ annotations,
+ );
+
+ // if the cursor is on a line with only virtual text return None
+ if virt_lines != 0 && ignore_virtual_text {
+ return None;
+ }
+ Some(char_idx)
}
/// Translates a screen position to position in the text document.
/// Returns a usize typed position in bounds of the text if found in this view, None if out of view.
- pub fn pos_at_screen_coords(&self, doc: &Document, row: u16, column: u16) -> Option<usize> {
- self.text_pos_at_screen_coords(doc, row, column, doc.tab_width())
+ pub fn pos_at_screen_coords(
+ &self,
+ doc: &Document,
+ row: u16,
+ column: u16,
+ ignore_virtual_text: bool,
+ ) -> Option<usize> {
+ self.text_pos_at_screen_coords(
+ doc,
+ row,
+ column,
+ doc.text_format(self.inner_width(doc), None),
+ &self.text_annotations(doc, None),
+ ignore_virtual_text,
+ )
+ }
+
+ pub fn pos_at_visual_coords(
+ &self,
+ doc: &Document,
+ row: u16,
+ column: u16,
+ ignore_virtual_text: bool,
+ ) -> Option<usize> {
+ self.text_pos_at_visual_coords(
+ doc,
+ row,
+ column,
+ doc.text_format(self.inner_width(doc), None),
+ &self.text_annotations(doc, None),
+ ignore_virtual_text,
+ )
}
/// Translates screen coordinates into coordinates on the gutter of the view.
@@ -419,7 +580,10 @@ impl View {
#[cfg(test)]
mod tests {
+ use std::sync::Arc;
+
use super::*;
+ use arc_swap::ArcSwap;
use helix_core::Rope;
// 1 diagnostic + 1 spacer + 3 linenr (< 1000 lines) + 1 spacer + 1 diff
@@ -429,52 +593,174 @@ mod tests {
const DEFAULT_GUTTER_OFFSET_ONLY_DIAGNOSTICS: u16 = 3;
use crate::document::Document;
- use crate::editor::{GutterConfig, GutterLineNumbersConfig, GutterType};
+ use crate::editor::{Config, GutterConfig, GutterLineNumbersConfig, GutterType};
#[test]
fn test_text_pos_at_screen_coords() {
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(rope, None);
+ let doc = Document::from(
+ rope,
+ None,
+ Arc::new(ArcSwap::new(Arc::new(Config::default()))),
+ );
- assert_eq!(view.text_pos_at_screen_coords(&doc, 40, 2, 4), None);
+ assert_eq!(
+ view.text_pos_at_screen_coords(
+ &doc,
+ 40,
+ 2,
+ TextFormat::default(),
+ &TextAnnotations::default(),
+ true
+ ),
+ None
+ );
- assert_eq!(view.text_pos_at_screen_coords(&doc, 40, 41, 4), None);
+ assert_eq!(
+ view.text_pos_at_screen_coords(
+ &doc,
+ 40,
+ 41,
+ TextFormat::default(),
+ &TextAnnotations::default(),
+ true
+ ),
+ None
+ );
- assert_eq!(view.text_pos_at_screen_coords(&doc, 0, 2, 4), None);
+ assert_eq!(
+ view.text_pos_at_screen_coords(
+ &doc,
+ 0,
+ 2,
+ TextFormat::default(),
+ &TextAnnotations::default(),
+ true
+ ),
+ None
+ );
- assert_eq!(view.text_pos_at_screen_coords(&doc, 0, 49, 4), None);
+ assert_eq!(
+ view.text_pos_at_screen_coords(
+ &doc,
+ 0,
+ 49,
+ TextFormat::default(),
+ &TextAnnotations::default(),
+ true
+ ),
+ None
+ );
- assert_eq!(view.text_pos_at_screen_coords(&doc, 0, 41, 4), None);
+ assert_eq!(
+ view.text_pos_at_screen_coords(
+ &doc,
+ 0,
+ 41,
+ TextFormat::default(),
+ &TextAnnotations::default(),
+ true
+ ),
+ None
+ );
- assert_eq!(view.text_pos_at_screen_coords(&doc, 40, 81, 4), None);
+ assert_eq!(
+ view.text_pos_at_screen_coords(
+ &doc,
+ 40,
+ 81,
+ TextFormat::default(),
+ &TextAnnotations::default(),
+ true
+ ),
+ None
+ );
- assert_eq!(view.text_pos_at_screen_coords(&doc, 78, 41, 4), None);
+ assert_eq!(
+ view.text_pos_at_screen_coords(
+ &doc,
+ 78,
+ 41,
+ TextFormat::default(),
+ &TextAnnotations::default(),
+ true
+ ),
+ None
+ );
assert_eq!(
- view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 3, 4),
+ view.text_pos_at_screen_coords(
+ &doc,
+ 40,
+ 40 + DEFAULT_GUTTER_OFFSET + 3,
+ TextFormat::default(),
+ &TextAnnotations::default(),
+ true
+ ),
Some(3)
);
- assert_eq!(view.text_pos_at_screen_coords(&doc, 40, 80, 4), Some(3));
+ assert_eq!(
+ view.text_pos_at_screen_coords(
+ &doc,
+ 40,
+ 80,
+ TextFormat::default(),
+ &TextAnnotations::default(),
+ true
+ ),
+ Some(3)
+ );
assert_eq!(
- view.text_pos_at_screen_coords(&doc, 41, 40 + DEFAULT_GUTTER_OFFSET + 1, 4),
+ view.text_pos_at_screen_coords(
+ &doc,
+ 41,
+ 40 + DEFAULT_GUTTER_OFFSET + 1,
+ TextFormat::default(),
+ &TextAnnotations::default(),
+ true
+ ),
Some(4)
);
assert_eq!(
- view.text_pos_at_screen_coords(&doc, 41, 40 + DEFAULT_GUTTER_OFFSET + 4, 4),
+ view.text_pos_at_screen_coords(
+ &doc,
+ 41,
+ 40 + DEFAULT_GUTTER_OFFSET + 4,
+ TextFormat::default(),
+ &TextAnnotations::default(),
+ true
+ ),
Some(5)
);
assert_eq!(
- view.text_pos_at_screen_coords(&doc, 41, 40 + DEFAULT_GUTTER_OFFSET + 7, 4),
+ view.text_pos_at_screen_coords(
+ &doc,
+ 41,
+ 40 + DEFAULT_GUTTER_OFFSET + 7,
+ TextFormat::default(),
+ &TextAnnotations::default(),
+ true
+ ),
Some(8)
);
- assert_eq!(view.text_pos_at_screen_coords(&doc, 41, 80, 4), Some(8));
+ assert_eq!(
+ view.text_pos_at_screen_coords(
+ &doc,
+ 41,
+ 80,
+ TextFormat::default(),
+ &TextAnnotations::default(),
+ true
+ ),
+ Some(8)
+ );
}
#[test]
@@ -488,13 +774,19 @@ mod tests {
);
view.area = Rect::new(40, 40, 40, 40);
let rope = Rope::from_str("abc\n\tdef");
- let doc = Document::from(rope, None);
+ let doc = Document::from(
+ rope,
+ None,
+ Arc::new(ArcSwap::new(Arc::new(Config::default()))),
+ );
assert_eq!(
view.text_pos_at_screen_coords(
&doc,
41,
40 + DEFAULT_GUTTER_OFFSET_ONLY_DIAGNOSTICS + 1,
- 4
+ TextFormat::default(),
+ &TextAnnotations::default(),
+ true
),
Some(4)
);
@@ -511,8 +803,22 @@ mod tests {
);
view.area = Rect::new(40, 40, 40, 40);
let rope = Rope::from_str("abc\n\tdef");
- let doc = Document::from(rope, None);
- assert_eq!(view.text_pos_at_screen_coords(&doc, 41, 40 + 1, 4), Some(4));
+ let doc = Document::from(
+ rope,
+ None,
+ Arc::new(ArcSwap::new(Arc::new(Config::default()))),
+ );
+ assert_eq!(
+ view.text_pos_at_screen_coords(
+ &doc,
+ 41,
+ 40 + 1,
+ TextFormat::default(),
+ &TextAnnotations::default(),
+ true
+ ),
+ Some(4)
+ );
}
#[test]
@@ -520,34 +826,80 @@ 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(rope, None);
+ let doc = Document::from(
+ rope,
+ None,
+ Arc::new(ArcSwap::new(Arc::new(Config::default()))),
+ );
assert_eq!(
- view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET, 4),
+ view.text_pos_at_screen_coords(
+ &doc,
+ 40,
+ 40 + DEFAULT_GUTTER_OFFSET,
+ TextFormat::default(),
+ &TextAnnotations::default(),
+ true
+ ),
Some(0)
);
assert_eq!(
- view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 4, 4),
+ view.text_pos_at_screen_coords(
+ &doc,
+ 40,
+ 40 + DEFAULT_GUTTER_OFFSET + 4,
+ TextFormat::default(),
+ &TextAnnotations::default(),
+ true
+ ),
Some(4)
);
assert_eq!(
- view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 5, 4),
+ view.text_pos_at_screen_coords(
+ &doc,
+ 40,
+ 40 + DEFAULT_GUTTER_OFFSET + 5,
+ TextFormat::default(),
+ &TextAnnotations::default(),
+ true
+ ),
Some(4)
);
assert_eq!(
- view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 6, 4),
+ view.text_pos_at_screen_coords(
+ &doc,
+ 40,
+ 40 + DEFAULT_GUTTER_OFFSET + 6,
+ TextFormat::default(),
+ &TextAnnotations::default(),
+ true
+ ),
Some(5)
);
assert_eq!(
- view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 7, 4),
+ view.text_pos_at_screen_coords(
+ &doc,
+ 40,
+ 40 + DEFAULT_GUTTER_OFFSET + 7,
+ TextFormat::default(),
+ &TextAnnotations::default(),
+ true
+ ),
Some(5)
);
assert_eq!(
- view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 8, 4),
+ view.text_pos_at_screen_coords(
+ &doc,
+ 40,
+ 40 + DEFAULT_GUTTER_OFFSET + 8,
+ TextFormat::default(),
+ &TextAnnotations::default(),
+ true
+ ),
Some(6)
);
}
@@ -557,30 +909,69 @@ 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(rope, None);
+ let doc = Document::from(
+ rope,
+ None,
+ Arc::new(ArcSwap::new(Arc::new(Config::default()))),
+ );
assert_eq!(
- view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET, 4),
+ view.text_pos_at_screen_coords(
+ &doc,
+ 40,
+ 40 + DEFAULT_GUTTER_OFFSET,
+ TextFormat::default(),
+ &TextAnnotations::default(),
+ true
+ ),
Some(0)
);
assert_eq!(
- view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 1, 4),
+ view.text_pos_at_screen_coords(
+ &doc,
+ 40,
+ 40 + DEFAULT_GUTTER_OFFSET + 1,
+ TextFormat::default(),
+ &TextAnnotations::default(),
+ true
+ ),
Some(1)
);
assert_eq!(
- view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 2, 4),
+ view.text_pos_at_screen_coords(
+ &doc,
+ 40,
+ 40 + DEFAULT_GUTTER_OFFSET + 2,
+ TextFormat::default(),
+ &TextAnnotations::default(),
+ true
+ ),
Some(3)
);
assert_eq!(
- view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 3, 4),
+ view.text_pos_at_screen_coords(
+ &doc,
+ 40,
+ 40 + DEFAULT_GUTTER_OFFSET + 3,
+ TextFormat::default(),
+ &TextAnnotations::default(),
+ true
+ ),
Some(5)
);
assert_eq!(
- view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 4, 4),
+ view.text_pos_at_screen_coords(
+ &doc,
+ 40,
+ 40 + DEFAULT_GUTTER_OFFSET + 4,
+ TextFormat::default(),
+ &TextAnnotations::default(),
+ true
+ ),
Some(7)
);
}