aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBlaž Hrastnik2022-03-04 02:01:33 +0000
committerBlaž Hrastnik2022-03-04 02:01:33 +0000
commitfd02d1bf8966754624c733790c20bb8431e1eb54 (patch)
treed0f4480f9190f8048d70acceca1711cc2e999a34
parent5f386fa355d2f3e95a890c2d63d95b05ddca23a4 (diff)
Fix tab rendering to use dynamic tab width
Each tab is just wide enough to round to the nearest tab stop. Refs #1243
-rw-r--r--helix-core/src/position.rs2
-rw-r--r--helix-term/src/ui/editor.rs3
-rw-r--r--helix-view/src/view.rs23
3 files changed, 20 insertions, 8 deletions
diff --git a/helix-core/src/position.rs b/helix-core/src/position.rs
index 17908d7a..ce37300a 100644
--- a/helix-core/src/position.rs
+++ b/helix-core/src/position.rs
@@ -83,7 +83,7 @@ pub fn visual_coords_at_pos(text: RopeSlice, pos: usize, tab_width: usize) -> Po
for grapheme in RopeGraphemes::new(text.slice(line_start..pos)) {
if grapheme == "\t" {
- col += tab_width;
+ col += tab_width - (col % tab_width);
} else {
let grapheme = Cow::from(grapheme);
col += grapheme_width(&grapheme);
diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs
index f9c5e55e..31a9bfc8 100644
--- a/helix-term/src/ui/editor.rs
+++ b/helix-term/src/ui/editor.rs
@@ -378,7 +378,8 @@ impl EditorView {
let (grapheme, width) = if grapheme == "\t" {
// make sure we display tab as appropriate amount of spaces
- (tab.as_str(), tab_width)
+ let visual_tab_width = tab_width - (visual_x as usize % tab_width);
+ (&tab[..visual_tab_width], visual_tab_width)
} else {
// Cow will prevent allocations if span contained in a single slice
// which should really be the majority case
diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs
index 58a9b602..b427a8d4 100644
--- a/helix-view/src/view.rs
+++ b/helix-view/src/view.rs
@@ -243,18 +243,29 @@ impl View {
let current_line = text.line(line_number);
let target = (column - inner.x) as usize + self.offset.col;
- let mut selected = 0;
+ let mut col = 0;
+ // TODO: extract this part as pos_at_visual_coords
for grapheme in RopeGraphemes::new(current_line) {
- if selected >= target {
+ if col >= target {
break;
}
- if grapheme == "\t" {
- selected += tab_width;
+
+ let width = if grapheme == "\t" {
+ tab_width - (col % tab_width)
} else {
- let width = grapheme_width(&Cow::from(grapheme));
- selected += width;
+ let grapheme = Cow::from(grapheme);
+ grapheme_width(&grapheme)
+ };
+
+ // If pos is in the middle of a wider grapheme (tab for example)
+ // return the starting offset.
+ if col + width >= target {
+ break;
}
+
+ col += width;
+ // TODO: use byte pos that converts back to char pos?
pos += grapheme.chars().count();
}