on master help sign in
Add configuration for min width of line-numbers gutter (#4724)
commit2b58ff4d7cc09bc48bcdd79096110eeb578b509f authorDoug Kelkhoff <18220321+dgkf@users.noreply.github.com> dateSat 21 Jan 2023, 15:20 (4 years ago) parent8347139
5 files changed+310−92
book/src/configuration.md+52 helix-view/src/editor.rs+95−9 helix-view/src/gutter.rs+95−10 helix-view/src/tree.rs+9−33 helix-view/src/view.rs+59−40
book/src/configuration.md+52
@@ -256,3 +256,55 @@ render = true
256256character = "╎" # Some characters that work well: "▏", "┆", "┊", "⸽"
257257skip-levels = 1
258258```
259+
260+### `[editor.gutters]` Section
261+
262+For simplicity, `editor.gutters` accepts an array of gutter types, which will
263+use default settings for all gutter components.
264+
265+```toml
266+[editor]
267+gutters = ["diff", "diagnostics", "line-numbers", "spacer"]
268+```
269+
270+To customize the behavior of gutters, the `[editor.gutters]` section must
271+be used. This section contains top level settings, as well as settings for
272+specific gutter components as sub-sections.
273+
274+| Key | Description | Default |
275+| --- | --- | --- |
276+| `layout` | A vector of gutters to display | `["diagnostics", "spacer", "line-numbers", "spacer", "diff"]` |
277+
278+Example:
279+
280+```toml
281+[editor.gutters]
282+layout = ["diff", "diagnostics", "line-numbers", "spacer"]
283+```
284+
285+#### `[editor.gutters.line-numbers]` Section
286+
287+Options for the line number gutter
288+
289+| Key | Description | Default |
290+| --- | --- | --- |
291+| `min-width` | The minimum number of characters to use | `3` |
292+
293+Example:
294+
295+```toml
296+[editor.gutters.line-numbers]
297+min-width = 1
298+```
299+
300+#### `[editor.gutters.diagnotics]` Section
301+
302+Currently unused
303+
304+#### `[editor.gutters.diff]` Section
305+
306+Currently unused
307+
308+#### `[editor.gutters.spacer]` Section
309+
310+Currently unused
helix-view/src/editor.rs+95−9
@@ -71,6 +71,96 @@ where
7171 )
7272}
7373
74+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
75+#[serde(rename_all = "kebab-case", default, deny_unknown_fields)]
76+pub struct GutterConfig {
77+ /// Gutter Layout
78+ pub layout: Vec<GutterType>,
79+ /// Options specific to the "line-numbers" gutter
80+ pub line_numbers: GutterLineNumbersConfig,
81+}
82+
83+impl Default for GutterConfig {
84+ fn default() -> Self {
85+ Self {
86+ layout: vec![
87+ GutterType::Diagnostics,
88+ GutterType::Spacer,
89+ GutterType::LineNumbers,
90+ GutterType::Spacer,
91+ GutterType::Diff,
92+ ],
93+ line_numbers: GutterLineNumbersConfig::default(),
94+ }
95+ }
96+}
97+
98+impl From<Vec<GutterType>> for GutterConfig {
99+ fn from(x: Vec<GutterType>) -> Self {
100+ GutterConfig {
101+ layout: x,
102+ ..Default::default()
103+ }
104+ }
105+}
106+
107+fn deserialize_gutter_seq_or_struct<'de, D>(deserializer: D) -> Result<GutterConfig, D::Error>
108+where
109+ D: Deserializer<'de>,
110+{
111+ struct GutterVisitor;
112+
113+ impl<'de> serde::de::Visitor<'de> for GutterVisitor {
114+ type Value = GutterConfig;
115+
116+ fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
117+ write!(
118+ formatter,
119+ "an array of gutter names or a detailed gutter configuration"
120+ )
121+ }
122+
123+ fn visit_seq<S>(self, mut seq: S) -> Result<Self::Value, S::Error>
124+ where
125+ S: serde::de::SeqAccess<'de>,
126+ {
127+ let mut gutters = Vec::new();
128+ while let Some(gutter) = seq.next_element::<&str>()? {
129+ gutters.push(
130+ gutter
131+ .parse::<GutterType>()
132+ .map_err(serde::de::Error::custom)?,
133+ )
134+ }
135+
136+ Ok(gutters.into())
137+ }
138+
139+ fn visit_map<M>(self, map: M) -> Result<Self::Value, M::Error>
140+ where
141+ M: serde::de::MapAccess<'de>,
142+ {
143+ let deserializer = serde::de::value::MapAccessDeserializer::new(map);
144+ Deserialize::deserialize(deserializer)
145+ }
146+ }
147+
148+ deserializer.deserialize_any(GutterVisitor)
149+}
150+
151+#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
152+#[serde(rename_all = "kebab-case", default, deny_unknown_fields)]
153+pub struct GutterLineNumbersConfig {
154+ /// Minimum number of characters to use for line number gutter. Defaults to 3.
155+ pub min_width: usize,
156+}
157+
158+impl Default for GutterLineNumbersConfig {
159+ fn default() -> Self {
160+ Self { min_width: 3 }
161+ }
162+}
163+
74164#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
75165#[serde(rename_all = "kebab-case", default, deny_unknown_fields)]
76166pub struct FilePickerConfig {
@@ -132,8 +222,8 @@ pub struct Config {
132222 pub cursorline: bool,
133223 /// Highlight the columns cursors are currently on. Defaults to false.
134224 pub cursorcolumn: bool,
135− /// Gutters. Default ["diagnostics", "line-numbers"]
136− pub gutters: Vec<GutterType>,
225+ #[serde(deserialize_with = "deserialize_gutter_seq_or_struct")]
226+ pub gutters: GutterConfig,
137227 /// Middle click paste support. Defaults to true.
138228 pub middle_click_paste: bool,
139229 /// Automatic insertion of pairs to parentheses, brackets,
@@ -606,13 +696,7 @@ impl Default for Config {
606696 line_number: LineNumber::Absolute,
607697 cursorline: false,
608698 cursorcolumn: false,
609− gutters: vec![
610− GutterType::Diagnostics,
611− GutterType::Spacer,
612− GutterType::LineNumbers,
613− GutterType::Spacer,
614− GutterType::Diff,
615− ],
699+ gutters: GutterConfig::default(),
616700 middle_click_paste: true,
617701 auto_pairs: AutoPairConfig::default(),
618702 auto_completion: true,
@@ -844,6 +928,7 @@ impl Editor {
844928 let config = self.config();
845929 self.auto_pairs = (&config.auto_pairs).into();
846930 self.reset_idle_timer();
931+ self._refresh();
847932 }
848933
849934 pub fn clear_idle_timer(&mut self) {
@@ -984,6 +1069,7 @@ impl Editor {
9841069 for (view, _) in self.tree.views_mut() {
9851070 let doc = doc_mut!(self, &view.doc);
9861071 view.sync_changes(doc);
1072+ view.gutters = config.gutters.clone();
9871073 view.ensure_cursor_in_view(doc, config.scrolloff)
9881074 }
9891075 }
helix-view/src/gutter.rs+95−10
@@ -35,10 +35,10 @@ impl GutterType {
3535 }
3636 }
3737
38− pub fn width(self, _view: &View, doc: &Document) -> usize {
38+ pub fn width(self, view: &View, doc: &Document) -> usize {
3939 match self {
4040 GutterType::Diagnostics => 1,
41− GutterType::LineNumbers => line_numbers_width(_view, doc),
41+ GutterType::LineNumbers => line_numbers_width(view, doc),
4242 GutterType::Spacer => 1,
4343 GutterType::Diff => 1,
4444 }
@@ -140,12 +140,13 @@ pub fn line_numbers<'doc>(
140140 is_focused: bool,
141141) -> GutterFn<'doc> {
142142 let text = doc.text().slice(..);
143− let last_line = view.last_line(doc);
144− let width = GutterType::LineNumbers.width(view, doc);
143+ let width = line_numbers_width(view, doc);
144+
145+ let last_line_in_view = view.last_line(doc);
145146
146147 // Whether to draw the line number for the last line of the
147148 // document or not. We only draw it if it's not an empty line.
148− let draw_last = text.line_to_byte(last_line) < text.len_bytes();
149+ let draw_last = text.line_to_byte(last_line_in_view) < text.len_bytes();
149150
150151 let linenr = theme.get("ui.linenr");
151152 let linenr_select = theme.get("ui.linenr.selected");
@@ -158,7 +159,7 @@ pub fn line_numbers<'doc>(
158159 let mode = editor.mode;
159160
160161 Box::new(move |line: usize, selected: bool, out: &mut String| {
161− if line == last_line && !draw_last {
162+ if line == last_line_in_view && !draw_last {
162163 write!(out, "{:>1$}", '~', width).unwrap();
163164 Some(linenr)
164165 } else {
@@ -187,14 +188,19 @@ pub fn line_numbers<'doc>(
187188 })
188189}
189190
190−pub fn line_numbers_width(_view: &View, doc: &Document) -> usize {
191+/// The width of a "line-numbers" gutter
192+///
193+/// The width of the gutter depends on the number of lines in the document,
194+/// whether there is content on the last line (the `~` line), and the
195+/// `editor.gutters.line-numbers.min-width` settings.
196+fn line_numbers_width(view: &View, doc: &Document) -> usize {
191197 let text = doc.text();
192198 let last_line = text.len_lines().saturating_sub(1);
193199 let draw_last = text.line_to_byte(last_line) < text.len_bytes();
194200 let last_drawn = if draw_last { last_line + 1 } else { last_line };
195−
196− // set a lower bound to 2-chars to minimize ambiguous relative line numbers
197− std::cmp::max(count_digits(last_drawn), 2)
201+ let digits = count_digits(last_drawn);
202+ let n_min = view.gutters.line_numbers.min_width;
203+ digits.max(n_min)
198204}
199205
200206pub fn padding<'doc>(
@@ -282,3 +288,82 @@ pub fn diagnostics_or_breakpoints<'doc>(
282288 breakpoints(line, selected, out).or_else(|| diagnostics(line, selected, out))
283289 })
284290}
291+
292+#[cfg(test)]
293+mod tests {
294+ use super::*;
295+ use crate::document::Document;
296+ use crate::editor::{GutterConfig, GutterLineNumbersConfig};
297+ use crate::graphics::Rect;
298+ use crate::DocumentId;
299+ use helix_core::Rope;
300+
301+ #[test]
302+ fn test_default_gutter_widths() {
303+ let mut view = View::new(DocumentId::default(), GutterConfig::default());
304+ view.area = Rect::new(40, 40, 40, 40);
305+
306+ let rope = Rope::from_str("abc\n\tdef");
307+ let doc = Document::from(rope, None);
308+
309+ assert_eq!(view.gutters.layout.len(), 5);
310+ assert_eq!(view.gutters.layout[0].width(&view, &doc), 1);
311+ assert_eq!(view.gutters.layout[1].width(&view, &doc), 1);
312+ assert_eq!(view.gutters.layout[2].width(&view, &doc), 3);
313+ assert_eq!(view.gutters.layout[3].width(&view, &doc), 1);
314+ assert_eq!(view.gutters.layout[4].width(&view, &doc), 1);
315+ }
316+
317+ #[test]
318+ fn test_configured_gutter_widths() {
319+ let gutters = GutterConfig {
320+ layout: vec![GutterType::Diagnostics],
321+ ..Default::default()
322+ };
323+
324+ let mut view = View::new(DocumentId::default(), gutters);
325+ view.area = Rect::new(40, 40, 40, 40);
326+
327+ let rope = Rope::from_str("abc\n\tdef");
328+ let doc = Document::from(rope, None);
329+
330+ assert_eq!(view.gutters.layout.len(), 1);
331+ assert_eq!(view.gutters.layout[0].width(&view, &doc), 1);
332+
333+ let gutters = GutterConfig {
334+ layout: vec![GutterType::Diagnostics, GutterType::LineNumbers],
335+ line_numbers: GutterLineNumbersConfig { min_width: 10 },
336+ };
337+
338+ let mut view = View::new(DocumentId::default(), gutters);
339+ view.area = Rect::new(40, 40, 40, 40);
340+
341+ let rope = Rope::from_str("abc\n\tdef");
342+ let doc = Document::from(rope, None);
343+
344+ assert_eq!(view.gutters.layout.len(), 2);
345+ assert_eq!(view.gutters.layout[0].width(&view, &doc), 1);
346+ assert_eq!(view.gutters.layout[1].width(&view, &doc), 10);
347+ }
348+
349+ #[test]
350+ fn test_line_numbers_gutter_width_resizes() {
351+ let gutters = GutterConfig {
352+ layout: vec![GutterType::Diagnostics, GutterType::LineNumbers],
353+ line_numbers: GutterLineNumbersConfig { min_width: 1 },
354+ };
355+
356+ let mut view = View::new(DocumentId::default(), gutters);
357+ view.area = Rect::new(40, 40, 40, 40);
358+
359+ let rope = Rope::from_str("a\nb");
360+ let doc_short = Document::from(rope, None);
361+
362+ let rope = Rope::from_str("a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\np");
363+ let doc_long = Document::from(rope, None);
364+
365+ assert_eq!(view.gutters.layout.len(), 2);
366+ assert_eq!(view.gutters.layout[1].width(&view, &doc_short), 1);
367+ assert_eq!(view.gutters.layout[1].width(&view, &doc_long), 2);
368+ }
369+}
helix-view/src/tree.rs+9−33
@@ -701,7 +701,7 @@ impl<'a> DoubleEndedIterator for Traverse<'a> {
701701#[cfg(test)]
702702mod test {
703703 use super::*;
704− use crate::editor::GutterType;
704+ use crate::editor::GutterConfig;
705705 use crate::DocumentId;
706706
707707 #[test]
@@ -712,34 +712,22 @@ mod test {
712712 width: 180,
713713 height: 80,
714714 });
715− let mut view = View::new(
716− DocumentId::default(),
717− vec![GutterType::Diagnostics, GutterType::LineNumbers],
718− );
715+ let mut view = View::new(DocumentId::default(), GutterConfig::default());
719716 view.area = Rect::new(0, 0, 180, 80);
720717 tree.insert(view);
721718
722719 let l0 = tree.focus;
723− let view = View::new(
724− DocumentId::default(),
725− vec![GutterType::Diagnostics, GutterType::LineNumbers],
726− );
720+ let view = View::new(DocumentId::default(), GutterConfig::default());
727721 tree.split(view, Layout::Vertical);
728722 let r0 = tree.focus;
729723
730724 tree.focus = l0;
731− let view = View::new(
732− DocumentId::default(),
733− vec![GutterType::Diagnostics, GutterType::LineNumbers],
734− );
725+ let view = View::new(DocumentId::default(), GutterConfig::default());
735726 tree.split(view, Layout::Horizontal);
736727 let l1 = tree.focus;
737728
738729 tree.focus = l0;
739− let view = View::new(
740− DocumentId::default(),
741− vec![GutterType::Diagnostics, GutterType::LineNumbers],
742− );
730+ let view = View::new(DocumentId::default(), GutterConfig::default());
743731 tree.split(view, Layout::Vertical);
744732 let l2 = tree.focus;
745733
@@ -781,40 +769,28 @@ mod test {
781769 });
782770
783771 let doc_l0 = DocumentId::default();
784− let mut view = View::new(
785− doc_l0,
786− vec![GutterType::Diagnostics, GutterType::LineNumbers],
787− );
772+ let mut view = View::new(doc_l0, GutterConfig::default());
788773 view.area = Rect::new(0, 0, 180, 80);
789774 tree.insert(view);
790775
791776 let l0 = tree.focus;
792777
793778 let doc_r0 = DocumentId::default();
794− let view = View::new(
795− doc_r0,
796− vec![GutterType::Diagnostics, GutterType::LineNumbers],
797− );
779+ let view = View::new(doc_r0, GutterConfig::default());
798780 tree.split(view, Layout::Vertical);
799781 let r0 = tree.focus;
800782
801783 tree.focus = l0;
802784
803785 let doc_l1 = DocumentId::default();
804− let view = View::new(
805− doc_l1,
806− vec![GutterType::Diagnostics, GutterType::LineNumbers],
807− );
786+ let view = View::new(doc_l1, GutterConfig::default());
808787 tree.split(view, Layout::Horizontal);
809788 let l1 = tree.focus;
810789
811790 tree.focus = l0;
812791
813792 let doc_l2 = DocumentId::default();
814− let view = View::new(
815− doc_l2,
816− vec![GutterType::Diagnostics, GutterType::LineNumbers],
817− );
793+ let view = View::new(doc_l2, GutterConfig::default());
818794 tree.split(view, Layout::Vertical);
819795 let l2 = tree.focus;
820796
helix-view/src/view.rs+59−40
@@ -1,4 +1,10 @@
1−use crate::{align_view, editor::GutterType, graphics::Rect, Align, Document, DocumentId, ViewId};
1+use crate::{
2+ align_view,
3+ editor::{GutterConfig, GutterType},
4+ graphics::Rect,
5+ Align, Document, DocumentId, ViewId,
6+};
7+
28use helix_core::{
39 pos_at_visual_coords, visual_coords_at_pos, Position, RopeSlice, Selection, Transaction,
410};
@@ -103,8 +109,8 @@ pub struct View {
103109 pub last_modified_docs: [Option<DocumentId>; 2],
104110 /// used to store previous selections of tree-sitter objects
105111 pub object_selections: Vec<Selection>,
106− /// GutterTypes used to fetch Gutter (constructor) and width for rendering
107− gutters: Vec<GutterType>,
112+ /// all gutter-related configuration settings, used primarily for gutter rendering
113+ pub gutters: GutterConfig,
108114 /// A mapping between documents and the last history revision the view was updated at.
109115 /// Changes between documents and views are synced lazily when switching windows. This
110116 /// mapping keeps track of the last applied history revision so that only new changes
@@ -123,7 +129,7 @@ impl fmt::Debug for View {
123129}
124130
125131impl View {
126− pub fn new(doc: DocumentId, gutter_types: Vec<crate::editor::GutterType>) -> Self {
132+ pub fn new(doc: DocumentId, gutters: GutterConfig) -> Self {
127133 Self {
128134 id: ViewId::default(),
129135 doc,
@@ -133,7 +139,7 @@ impl View {
133139 docs_access_history: Vec::new(),
134140 last_modified_docs: [None, None],
135141 object_selections: Vec::new(),
136− gutters: gutter_types,
142+ gutters,
137143 doc_revisions: HashMap::new(),
138144 }
139145 }
@@ -154,11 +160,12 @@ impl View {
154160 }
155161
156162 pub fn gutters(&self) -> &[GutterType] {
157− &self.gutters
163+ &self.gutters.layout
158164 }
159165
160166 pub fn gutter_offset(&self, doc: &Document) -> u16 {
161167 self.gutters
168+ .layout
162169 .iter()
163170 .map(|gutter| gutter.width(self, doc) as u16)
164171 .sum()
@@ -414,18 +421,19 @@ impl View {
414421mod tests {
415422 use super::*;
416423 use helix_core::Rope;
417− const OFFSET: u16 = 3; // 1 diagnostic + 2 linenr (< 100 lines)
418− const OFFSET_WITHOUT_LINE_NUMBERS: u16 = 1; // 1 diagnostic
419− // const OFFSET: u16 = GUTTERS.iter().map(|(_, width)| *width as u16).sum();
424+
425+ // 1 diagnostic + 1 spacer + 3 linenr (< 1000 lines) + 1 spacer + 1 diff
426+ const DEFAULT_GUTTER_OFFSET: u16 = 7;
427+
428+ // 1 diagnostics + 1 spacer + 1 gutter
429+ const DEFAULT_GUTTER_OFFSET_ONLY_DIAGNOSTICS: u16 = 3;
430+
420431 use crate::document::Document;
421− use crate::editor::GutterType;
432+ use crate::editor::{GutterConfig, GutterLineNumbersConfig, GutterType};
422433
423434 #[test]
424435 fn test_text_pos_at_screen_coords() {
425− let mut view = View::new(
426− DocumentId::default(),
427− vec![GutterType::Diagnostics, GutterType::LineNumbers],
428− );
436+ let mut view = View::new(DocumentId::default(), GutterConfig::default());
429437 view.area = Rect::new(40, 40, 40, 40);
430438 let rope = Rope::from_str("abc\n\tdef");
431439 let doc = Document::from(rope, None);
@@ -445,24 +453,24 @@ mod tests {
445453 assert_eq!(view.text_pos_at_screen_coords(&doc, 78, 41, 4), None);
446454
447455 assert_eq!(
448− view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 3, 4),
456+ view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 3, 4),
449457 Some(3)
450458 );
451459
452460 assert_eq!(view.text_pos_at_screen_coords(&doc, 40, 80, 4), Some(3));
453461
454462 assert_eq!(
455− view.text_pos_at_screen_coords(&doc, 41, 40 + OFFSET + 1, 4),
463+ view.text_pos_at_screen_coords(&doc, 41, 40 + DEFAULT_GUTTER_OFFSET + 1, 4),
456464 Some(4)
457465 );
458466
459467 assert_eq!(
460− view.text_pos_at_screen_coords(&doc, 41, 40 + OFFSET + 4, 4),
468+ view.text_pos_at_screen_coords(&doc, 41, 40 + DEFAULT_GUTTER_OFFSET + 4, 4),
461469 Some(5)
462470 );
463471
464472 assert_eq!(
465− view.text_pos_at_screen_coords(&doc, 41, 40 + OFFSET + 7, 4),
473+ view.text_pos_at_screen_coords(&doc, 41, 40 + DEFAULT_GUTTER_OFFSET + 7, 4),
466474 Some(8)
467475 );
468476
@@ -471,19 +479,36 @@ mod tests {
471479
472480 #[test]
473481 fn test_text_pos_at_screen_coords_without_line_numbers_gutter() {
474− let mut view = View::new(DocumentId::default(), vec![GutterType::Diagnostics]);
482+ let mut view = View::new(
483+ DocumentId::default(),
484+ GutterConfig {
485+ layout: vec![GutterType::Diagnostics],
486+ line_numbers: GutterLineNumbersConfig::default(),
487+ },
488+ );
475489 view.area = Rect::new(40, 40, 40, 40);
476490 let rope = Rope::from_str("abc\n\tdef");
477491 let doc = Document::from(rope, None);
478492 assert_eq!(
479− view.text_pos_at_screen_coords(&doc, 41, 40 + OFFSET_WITHOUT_LINE_NUMBERS + 1, 4),
493+ view.text_pos_at_screen_coords(
494+ &doc,
495+ 41,
496+ 40 + DEFAULT_GUTTER_OFFSET_ONLY_DIAGNOSTICS + 1,
497+ 4
498+ ),
480499 Some(4)
481500 );
482501 }
483502
484503 #[test]
485504 fn test_text_pos_at_screen_coords_without_any_gutters() {
486− let mut view = View::new(DocumentId::default(), vec![]);
505+ let mut view = View::new(
506+ DocumentId::default(),
507+ GutterConfig {
508+ layout: vec![],
509+ line_numbers: GutterLineNumbersConfig::default(),
510+ },
511+ );
487512 view.area = Rect::new(40, 40, 40, 40);
488513 let rope = Rope::from_str("abc\n\tdef");
489514 let doc = Document::from(rope, None);
@@ -492,76 +517,70 @@ mod tests {
492517
493518 #[test]
494519 fn test_text_pos_at_screen_coords_cjk() {
495− let mut view = View::new(
496− DocumentId::default(),
497− vec![GutterType::Diagnostics, GutterType::LineNumbers],
498− );
520+ let mut view = View::new(DocumentId::default(), GutterConfig::default());
499521 view.area = Rect::new(40, 40, 40, 40);
500522 let rope = Rope::from_str("Hi! こんにちは皆さん");
501523 let doc = Document::from(rope, None);
502524
503525 assert_eq!(
504− view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET, 4),
526+ view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET, 4),
505527 Some(0)
506528 );
507529
508530 assert_eq!(
509− view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 4, 4),
531+ view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 4, 4),
510532 Some(4)
511533 );
512534 assert_eq!(
513− view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 5, 4),
535+ view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 5, 4),
514536 Some(4)
515537 );
516538
517539 assert_eq!(
518− view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 6, 4),
540+ view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 6, 4),
519541 Some(5)
520542 );
521543
522544 assert_eq!(
523− view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 7, 4),
545+ view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 7, 4),
524546 Some(5)
525547 );
526548
527549 assert_eq!(
528− view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 8, 4),
550+ view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 8, 4),
529551 Some(6)
530552 );
531553 }
532554
533555 #[test]
534556 fn test_text_pos_at_screen_coords_graphemes() {
535− let mut view = View::new(
536− DocumentId::default(),
537− vec![GutterType::Diagnostics, GutterType::LineNumbers],
538− );
557+ let mut view = View::new(DocumentId::default(), GutterConfig::default());
539558 view.area = Rect::new(40, 40, 40, 40);
540559 let rope = Rope::from_str("Hèl̀l̀ò world!");
541560 let doc = Document::from(rope, None);
542561
543562 assert_eq!(
544− view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET, 4),
563+ view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET, 4),
545564 Some(0)
546565 );
547566
548567 assert_eq!(
549− view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 1, 4),
568+ view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 1, 4),
550569 Some(1)
551570 );
552571
553572 assert_eq!(
554− view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 2, 4),
573+ view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 2, 4),
555574 Some(3)
556575 );
557576
558577 assert_eq!(
559− view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 3, 4),
578+ view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 3, 4),
560579 Some(5)
561580 );
562581
563582 assert_eq!(
564− view.text_pos_at_screen_coords(&doc, 40, 40 + OFFSET + 4, 4),
583+ view.text_pos_at_screen_coords(&doc, 40, 40 + DEFAULT_GUTTER_OFFSET + 4, 4),
565584 Some(7)
566585 );
567586 }