|
|
|
@ -1,4 +1,10 @@
|
|
|
|
|
use crate::{align_view, editor::GutterType, graphics::Rect, Align, Document, DocumentId, ViewId};
|
|
|
|
|
use crate::{
|
|
|
|
|
align_view,
|
|
|
|
|
editor::{GutterConfig, GutterType},
|
|
|
|
|
graphics::Rect,
|
|
|
|
|
Align, Document, DocumentId, ViewId,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
use helix_core::{
|
|
|
|
|
pos_at_visual_coords, visual_coords_at_pos, Position, RopeSlice, Selection, Transaction,
|
|
|
|
|
};
|
|
|
|
@ -103,8 +109,8 @@ pub struct View {
|
|
|
|
|
pub last_modified_docs: [Option<DocumentId>; 2],
|
|
|
|
|
/// used to store previous selections of tree-sitter objects
|
|
|
|
|
pub object_selections: Vec<Selection>,
|
|
|
|
|
/// GutterTypes used to fetch Gutter (constructor) and width for rendering
|
|
|
|
|
gutters: Vec<GutterType>,
|
|
|
|
|
/// all gutter-related configuration settings, used primarily for gutter rendering
|
|
|
|
|
pub gutters: GutterConfig,
|
|
|
|
|
/// A mapping between documents and the last history revision the view was updated at.
|
|
|
|
|
/// Changes between documents and views are synced lazily when switching windows. This
|
|
|
|
|
/// mapping keeps track of the last applied history revision so that only new changes
|
|
|
|
@ -123,7 +129,7 @@ impl fmt::Debug for View {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl View {
|
|
|
|
|
pub fn new(doc: DocumentId, gutter_types: Vec<crate::editor::GutterType>) -> Self {
|
|
|
|
|
pub fn new(doc: DocumentId, gutters: GutterConfig) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
id: ViewId::default(),
|
|
|
|
|
doc,
|
|
|
|
@ -133,7 +139,7 @@ impl View {
|
|
|
|
|
docs_access_history: Vec::new(),
|
|
|
|
|
last_modified_docs: [None, None],
|
|
|
|
|
object_selections: Vec::new(),
|
|
|
|
|
gutters: gutter_types,
|
|
|
|
|
gutters,
|
|
|
|
|
doc_revisions: HashMap::new(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -154,11 +160,12 @@ impl View {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn gutters(&self) -> &[GutterType] {
|
|
|
|
|
&self.gutters
|
|
|
|
|
&self.gutters.layout
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn gutter_offset(&self, doc: &Document) -> u16 {
|
|
|
|
|
self.gutters
|
|
|
|
|
.layout
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|gutter| gutter.width(self, doc) as u16)
|
|
|
|
|
.sum()
|
|
|
|
@ -414,18 +421,19 @@ impl View {
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
|
|
|
|
use helix_core::Rope;
|
|
|
|
|
const OFFSET: u16 = 3; // 1 diagnostic + 2 linenr (< 100 lines)
|
|
|
|
|
const OFFSET_WITHOUT_LINE_NUMBERS: u16 = 1; // 1 diagnostic
|
|
|
|
|
// const OFFSET: u16 = GUTTERS.iter().map(|(_, width)| *width as u16).sum();
|
|
|
|
|
|
|
|
|
|
// 1 diagnostic + 1 spacer + 3 linenr (< 1000 lines) + 1 spacer + 1 diff
|
|
|
|
|
const DEFAULT_GUTTER_OFFSET: u16 = 7;
|
|
|
|
|
|
|
|
|
|
// 1 diagnostics + 1 spacer + 1 gutter
|
|
|
|
|
const DEFAULT_GUTTER_OFFSET_ONLY_DIAGNOSTICS: u16 = 3;
|
|
|
|
|
|
|
|
|
|
use crate::document::Document;
|
|
|
|
|
use crate::editor::GutterType;
|
|
|
|
|
use crate::editor::{GutterConfig, GutterLineNumbersConfig, GutterType};
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_text_pos_at_screen_coords() {
|
|
|
|
|
let mut view = View::new(
|
|
|
|
|
DocumentId::default(),
|
|
|
|
|
vec![GutterType::Diagnostics, GutterType::LineNumbers],
|
|
|
|
|
);
|
|
|
|
|
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);
|
|
|
|
@ -445,24 +453,24 @@ mod tests {
|
|
|
|
|
assert_eq!(view.text_pos_at_screen_coords(&doc, 78, 41, 4), None);
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 3, 4),
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 3, 4),
|
|
|
|
|
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, 41, 40 + OFFSET + 1, 4),
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 41, 40 + DEFAULT_GUTTER_OFFSET + 1, 4),
|
|
|
|
|
Some(4)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 41, 40 + OFFSET + 4, 4),
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 41, 40 + DEFAULT_GUTTER_OFFSET + 4, 4),
|
|
|
|
|
Some(5)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 41, 40 + OFFSET + 7, 4),
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 41, 40 + DEFAULT_GUTTER_OFFSET + 7, 4),
|
|
|
|
|
Some(8)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
@ -471,19 +479,36 @@ mod tests {
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_text_pos_at_screen_coords_without_line_numbers_gutter() {
|
|
|
|
|
let mut view = View::new(DocumentId::default(), vec![GutterType::Diagnostics]);
|
|
|
|
|
let mut view = View::new(
|
|
|
|
|
DocumentId::default(),
|
|
|
|
|
GutterConfig {
|
|
|
|
|
layout: vec![GutterType::Diagnostics],
|
|
|
|
|
line_numbers: GutterLineNumbersConfig::default(),
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
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 + OFFSET_WITHOUT_LINE_NUMBERS + 1, 4),
|
|
|
|
|
view.text_pos_at_screen_coords(
|
|
|
|
|
&doc,
|
|
|
|
|
41,
|
|
|
|
|
40 + DEFAULT_GUTTER_OFFSET_ONLY_DIAGNOSTICS + 1,
|
|
|
|
|
4
|
|
|
|
|
),
|
|
|
|
|
Some(4)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_text_pos_at_screen_coords_without_any_gutters() {
|
|
|
|
|
let mut view = View::new(DocumentId::default(), vec![]);
|
|
|
|
|
let mut view = View::new(
|
|
|
|
|
DocumentId::default(),
|
|
|
|
|
GutterConfig {
|
|
|
|
|
layout: vec![],
|
|
|
|
|
line_numbers: GutterLineNumbersConfig::default(),
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
view.area = Rect::new(40, 40, 40, 40);
|
|
|
|
|
let rope = Rope::from_str("abc\n\tdef");
|
|
|
|
|
let doc = Document::from(rope, None);
|
|
|
|
@ -492,76 +517,70 @@ mod tests {
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_text_pos_at_screen_coords_cjk() {
|
|
|
|
|
let mut view = View::new(
|
|
|
|
|
DocumentId::default(),
|
|
|
|
|
vec![GutterType::Diagnostics, GutterType::LineNumbers],
|
|
|
|
|
);
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET, 4),
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET, 4),
|
|
|
|
|
Some(0)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 4, 4),
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 4, 4),
|
|
|
|
|
Some(4)
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 5, 4),
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 5, 4),
|
|
|
|
|
Some(4)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 6, 4),
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 6, 4),
|
|
|
|
|
Some(5)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 7, 4),
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 7, 4),
|
|
|
|
|
Some(5)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 8, 4),
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 8, 4),
|
|
|
|
|
Some(6)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_text_pos_at_screen_coords_graphemes() {
|
|
|
|
|
let mut view = View::new(
|
|
|
|
|
DocumentId::default(),
|
|
|
|
|
vec![GutterType::Diagnostics, GutterType::LineNumbers],
|
|
|
|
|
);
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET, 4),
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET, 4),
|
|
|
|
|
Some(0)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 1, 4),
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 1, 4),
|
|
|
|
|
Some(1)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 2, 4),
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 2, 4),
|
|
|
|
|
Some(3)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 3, 4),
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 3, 4),
|
|
|
|
|
Some(5)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 4, 4),
|
|
|
|
|
view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 4, 4),
|
|
|
|
|
Some(7)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|