1use unicode_segmentation::UnicodeSegmentation;
2use unicode_width::UnicodeWidthStr;
3
4fn grapheme_width(g: &str) -> usize {
9 if g == "\t" {
10 0
11 } else {
12 UnicodeWidthStr::width(g)
14 }
15}
16
17pub fn display_width_with_tabs(s: &str, tab_width: usize) -> usize {
19 let mut col = 0usize;
20 for g in s.graphemes(true) {
21 if g == "\t" {
22 col += tab_width - (col % tab_width);
23 } else {
24 col += grapheme_width(g);
25 }
26 }
27 col
28}
29
30pub fn display_width(s: &str) -> usize {
32 display_width_with_tabs(s, 4)
33}
34
35pub fn grapheme_to_display_col(line: &str, grapheme_idx: usize, tab_width: usize) -> usize {
37 let mut col = 0usize;
38 for (i, g) in line.graphemes(true).enumerate() {
39 if i == grapheme_idx {
40 return col;
41 }
42 if g == "\t" {
43 col += tab_width - (col % tab_width);
44 } else {
45 col += grapheme_width(g);
46 }
47 }
48 col
49}
50
51pub fn display_to_grapheme_col(line: &str, display_col: usize, tab_width: usize) -> usize {
57 let mut col = 0usize;
58 for (i, g) in line.graphemes(true).enumerate() {
59 let w = if g == "\t" {
60 tab_width - (col % tab_width)
61 } else {
62 grapheme_width(g)
63 };
64 if display_col < col + w.max(1) {
65 return i;
66 }
67 col += w;
68 }
69 line.graphemes(true).count()
70}
71
72#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
77pub struct Position {
78 pub line: usize,
79 pub col: usize,
80}