on master help sign in
Fix tab rendering to use dynamic tab width
fd02d1bBlaž Hrastnik
helix-core/src/position.rs+1−1
@@ -83,7 +83,7 @@ pub fn visual_coords_at_pos(text: RopeSlice, pos: usize, tab_width: usize) -> Po
83
83
84 for grapheme in RopeGraphemes::new(text.slice(line_start..pos)) {
84 for grapheme in RopeGraphemes::new(text.slice(line_start..pos)) {
85 if grapheme == "\t" {
85 if grapheme == "\t" {
86− col += tab_width;
86+ col += tab_width - (col % tab_width);
87 } else {
87 } else {
88 let grapheme = Cow::from(grapheme);
88 let grapheme = Cow::from(grapheme);
89 col += grapheme_width(&grapheme);
89 col += grapheme_width(&grapheme);
helix-term/src/ui/editor.rs+2−1
@@ -378,7 +378,8 @@ impl EditorView {
378
378
379 let (grapheme, width) = if grapheme == "\t" {
379 let (grapheme, width) = if grapheme == "\t" {
380 // make sure we display tab as appropriate amount of spaces
380 // make sure we display tab as appropriate amount of spaces
381− (tab.as_str(), tab_width)
381+ let visual_tab_width = tab_width - (visual_x as usize % tab_width);
382+ (&tab[..visual_tab_width], visual_tab_width)
382 } else {
383 } else {
383 // Cow will prevent allocations if span contained in a single slice
384 // Cow will prevent allocations if span contained in a single slice
384 // which should really be the majority case
385 // which should really be the majority case
helix-view/src/view.rs+17−6
@@ -243,18 +243,29 @@ impl View {
243 let current_line = text.line(line_number);
243 let current_line = text.line(line_number);
244
244
245 let target = (column - inner.x) as usize + self.offset.col;
245 let target = (column - inner.x) as usize + self.offset.col;
246− let mut selected = 0;
246+ let mut col = 0;
247
247
248+ // TODO: extract this part as pos_at_visual_coords
248 for grapheme in RopeGraphemes::new(current_line) {
249 for grapheme in RopeGraphemes::new(current_line) {
249− if selected >= target {
250+ if col >= target {
250 break;
251 break;
251 }
252 }
253+
252− if grapheme == "\t" {
254+ let width = if grapheme == "\t" {
253− selected += tab_width;
255+ tab_width - (col % tab_width)
254 } else {
256 } else {
255− let width = grapheme_width(&Cow::from(grapheme));
257+ let grapheme = Cow::from(grapheme);
256− selected += width;
258+ grapheme_width(&grapheme)
259+ };
260+
261+ // If pos is in the middle of a wider grapheme (tab for example)
262+ // return the starting offset.
263+ if col + width >= target {
264+ break;
257 }
265 }
266+
267+ col += width;
268+ // TODO: use byte pos that converts back to char pos?
258 pos += grapheme.chars().count();
269 pos += grapheme.chars().count();
259 }
270 }
260
271