diff options
Diffstat (limited to 'helix-view/src')
-rw-r--r-- | helix-view/src/editor.rs | 28 | ||||
-rw-r--r-- | helix-view/src/gutter.rs | 2 | ||||
-rw-r--r-- | helix-view/src/tree.rs | 21 | ||||
-rw-r--r-- | helix-view/src/view.rs | 81 |
4 files changed, 108 insertions, 24 deletions
diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 76fc6713..dd805c00 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -117,6 +117,8 @@ pub struct Config { pub shell: Vec<String>, /// Line number mode. pub line_number: LineNumber, + /// Gutters. Default ["diagnostics", "line-numbers"] + pub gutters: Vec<GutterType>, /// Middle click paste support. Defaults to true. pub middle_click_paste: bool, /// Automatic insertion of pairs to parentheses, brackets, @@ -238,6 +240,27 @@ impl std::str::FromStr for LineNumber { } } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum GutterType { + /// Show diagnostics and other features like breakpoints + Diagnostics, + /// Show line numbers + LineNumbers, +} + +impl std::str::FromStr for GutterType { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + match s.to_lowercase().as_str() { + "diagnostics" => Ok(Self::Diagnostics), + "line-numbers" => Ok(Self::LineNumbers), + _ => anyhow::bail!("Gutter type can only be `diagnostics` or `line-numbers`."), + } + } +} + impl Default for Config { fn default() -> Self { Self { @@ -250,6 +273,7 @@ impl Default for Config { vec!["sh".to_owned(), "-c".to_owned()] }, line_number: LineNumber::Absolute, + gutters: vec![GutterType::Diagnostics, GutterType::LineNumbers], middle_click_paste: true, auto_pairs: AutoPairConfig::default(), auto_completion: true, @@ -579,7 +603,7 @@ impl Editor { return; } Action::HorizontalSplit | Action::VerticalSplit => { - let view = View::new(id); + let view = View::new(id, self.config().gutters.clone()); let view_id = self.tree.split( view, match action { @@ -701,7 +725,7 @@ impl Editor { .map(|(&doc_id, _)| doc_id) .next() .unwrap_or_else(|| self.new_document(Document::default())); - let view = View::new(doc_id); + let view = View::new(doc_id, self.config().gutters.clone()); let view_id = self.tree.insert(view); let doc = self.documents.get_mut(&doc_id).unwrap(); doc.selections.insert(view_id, Selection::point(0)); diff --git a/helix-view/src/gutter.rs b/helix-view/src/gutter.rs index 7327ed1a..06ce1b2e 100644 --- a/helix-view/src/gutter.rs +++ b/helix-view/src/gutter.rs @@ -39,7 +39,7 @@ pub fn diagnostic<'doc>( }) } -pub fn line_number<'doc>( +pub fn line_numbers<'doc>( editor: &'doc Editor, doc: &'doc Document, view: &View, diff --git a/helix-view/src/tree.rs b/helix-view/src/tree.rs index 99cbe0f9..b068f4c7 100644 --- a/helix-view/src/tree.rs +++ b/helix-view/src/tree.rs @@ -568,6 +568,7 @@ impl<'a> Iterator for Traverse<'a> { #[cfg(test)] mod test { use super::*; + use crate::editor::GutterType; use crate::DocumentId; #[test] @@ -578,22 +579,34 @@ mod test { width: 180, height: 80, }); - let mut view = View::new(DocumentId::default()); + let mut view = View::new( + DocumentId::default(), + vec![GutterType::Diagnostics, GutterType::LineNumbers], + ); view.area = Rect::new(0, 0, 180, 80); tree.insert(view); let l0 = tree.focus; - let view = View::new(DocumentId::default()); + let view = View::new( + DocumentId::default(), + vec![GutterType::Diagnostics, GutterType::LineNumbers], + ); tree.split(view, Layout::Vertical); let r0 = tree.focus; tree.focus = l0; - let view = View::new(DocumentId::default()); + let view = View::new( + DocumentId::default(), + vec![GutterType::Diagnostics, GutterType::LineNumbers], + ); tree.split(view, Layout::Horizontal); let l1 = tree.focus; tree.focus = l0; - let view = View::new(DocumentId::default()); + let view = View::new( + DocumentId::default(), + vec![GutterType::Diagnostics, GutterType::LineNumbers], + ); tree.split(view, Layout::Vertical); let l2 = tree.focus; diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index c6ae0c56..7cf88c2e 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -11,6 +11,8 @@ use helix_core::{ visual_coords_at_pos, Position, RopeSlice, Selection, }; +use std::fmt; + type Jump = (DocumentId, Selection); #[derive(Debug, Clone)] @@ -64,17 +66,11 @@ impl JumpList { } } -const GUTTERS: &[(Gutter, usize)] = &[ - (gutter::diagnostics_or_breakpoints, 1), - (gutter::line_number, 5), -]; - -#[derive(Debug)] pub struct View { pub id: ViewId, - pub doc: DocumentId, pub offset: Position, pub area: Rect, + pub doc: DocumentId, pub jumps: JumpList, /// the last accessed file before the current one pub last_accessed_doc: Option<DocumentId>, @@ -85,10 +81,29 @@ pub struct View { pub last_modified_docs: [Option<DocumentId>; 2], /// used to store previous selections of tree-sitter objecs pub object_selections: Vec<Selection>, + pub gutters: Vec<(Gutter, usize)>, +} + +impl fmt::Debug for View { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("View") + .field("id", &self.id) + .field("area", &self.area) + .field("doc", &self.doc) + .finish() + } } impl View { - pub fn new(doc: DocumentId) -> Self { + pub fn new(doc: DocumentId, gutter_types: Vec<crate::editor::GutterType>) -> Self { + let mut gutters: Vec<(Gutter, usize)> = vec![]; + use crate::editor::GutterType; + for gutter_type in &gutter_types { + match gutter_type { + GutterType::Diagnostics => gutters.push((gutter::diagnostics_or_breakpoints, 1)), + GutterType::LineNumbers => gutters.push((gutter::line_numbers, 5)), + } + } Self { id: ViewId::default(), doc, @@ -98,17 +113,14 @@ impl View { last_accessed_doc: None, last_modified_docs: [None, None], object_selections: Vec::new(), + gutters, } } - pub fn gutters(&self) -> &[(Gutter, usize)] { - GUTTERS - } - pub fn inner_area(&self) -> Rect { // TODO: cache this let offset = self - .gutters() + .gutters .iter() .map(|(_, width)| *width as u16) .sum::<u16>() @@ -324,11 +336,16 @@ mod tests { use super::*; use helix_core::Rope; const OFFSET: u16 = 7; // 1 diagnostic + 5 linenr + 1 gutter - // const OFFSET: u16 = GUTTERS.iter().map(|(_, width)| *width as u16).sum(); + const OFFSET_WITHOUT_LINE_NUMBERS: u16 = 2; // 1 diagnostic + 1 gutter + // const OFFSET: u16 = GUTTERS.iter().map(|(_, width)| *width as u16).sum(); + use crate::editor::GutterType; #[test] fn test_text_pos_at_screen_coords() { - let mut view = View::new(DocumentId::default()); + let mut view = View::new( + DocumentId::default(), + vec![GutterType::Diagnostics, GutterType::LineNumbers], + ); view.area = Rect::new(40, 40, 40, 40); let rope = Rope::from_str("abc\n\tdef"); let text = rope.slice(..); @@ -373,8 +390,35 @@ mod tests { } #[test] + fn test_text_pos_at_screen_coords_without_line_numbers_gutter() { + let mut view = View::new(DocumentId::default(), vec![GutterType::Diagnostics]); + view.area = Rect::new(40, 40, 40, 40); + let rope = Rope::from_str("abc\n\tdef"); + let text = rope.slice(..); + assert_eq!( + view.text_pos_at_screen_coords(&text, 41, 40 + OFFSET_WITHOUT_LINE_NUMBERS + 1, 4), + Some(4) + ); + } + + #[test] + fn test_text_pos_at_screen_coords_without_any_gutters() { + let mut view = View::new(DocumentId::default(), vec![]); + view.area = Rect::new(40, 40, 40, 40); + let rope = Rope::from_str("abc\n\tdef"); + let text = rope.slice(..); + assert_eq!( + view.text_pos_at_screen_coords(&text, 41, 40 + 1, 4), + Some(4) + ); + } + + #[test] fn test_text_pos_at_screen_coords_cjk() { - let mut view = View::new(DocumentId::default()); + let mut view = View::new( + DocumentId::default(), + vec![GutterType::Diagnostics, GutterType::LineNumbers], + ); view.area = Rect::new(40, 40, 40, 40); let rope = Rope::from_str("Hi! こんにちは皆さん"); let text = rope.slice(..); @@ -411,7 +455,10 @@ mod tests { #[test] fn test_text_pos_at_screen_coords_graphemes() { - let mut view = View::new(DocumentId::default()); + let mut view = View::new( + DocumentId::default(), + vec![GutterType::Diagnostics, GutterType::LineNumbers], + ); view.area = Rect::new(40, 40, 40, 40); let rope = Rope::from_str("Hèl̀l̀ò world!"); let text = rope.slice(..); |