fix: expand tabs to 8-column stops in diff and file views

Replace the hard-coded two-space tab rendering with standard
8-column tab stops so hard tabs align like most editors and terminals.

Fixes #2803

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
wuyangfan 2026-05-17 16:21:58 +08:00
parent 8619c07f3f
commit 0fb19c0b52

View file

@ -1,5 +1,5 @@
use unicode_segmentation::UnicodeSegmentation;
use unicode_width::UnicodeWidthStr;
use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
///
pub fn trim_length_left(s: &str, width: usize) -> &str {
@ -15,13 +15,36 @@ pub fn trim_length_left(s: &str, width: usize) -> &str {
s
}
//TODO: allow customize tabsize
const TAB_WIDTH: usize = 8;
// TODO: allow customize tabsize (e.g. via .editorconfig)
pub fn tabs_to_spaces(input: String) -> String {
if input.contains('\t') {
input.replace('\t', " ")
} else {
input
if !input.contains('\t') {
return input;
}
let mut out = String::with_capacity(input.len());
let mut column = 0usize;
for ch in input.chars() {
match ch {
'\t' => {
let spaces = TAB_WIDTH - (column % TAB_WIDTH);
out.extend(std::iter::repeat_n(' ', spaces));
column += spaces;
}
'\n' => {
out.push('\n');
column = 0;
}
ch => {
out.push(ch);
column += ch.width().unwrap_or(0);
}
}
}
out
}
/// This function will return a str slice which start at specified offset.
@ -51,4 +74,13 @@ mod test {
assert_eq!(trim_length_left("👍foo", 3), "foo");
assert_eq!(trim_length_left("👍foo", 4), "foo");
}
#[test]
fn test_tabs_to_spaces() {
use super::tabs_to_spaces;
assert_eq!(tabs_to_spaces("no-tabs".into()), "no-tabs");
assert_eq!(tabs_to_spaces("\tfoo".into()), " foo");
assert_eq!(tabs_to_spaces("a\tb".into()), "a b");
}
}