Skip to content

Commit a57fbad

Browse files
superyngoclaude
andcommitted
feat: v0.4.1 - 行號格式優化、管道顏色保留、shell 配置文件支援
## 主要變更 ### 1. 行號格式優化 - 移除行號右對齊縮排,從 `{:>6}` 改為 `{}` - 使輸出更緊湊,行號與內容之間只保留單個空格 - 修改位置:src/printer.rs:77, 96 ### 2. 管道顏色保留功能 - 改進 TTY 檢測邏輯:區分管道和文件重定向 - 新增 `is_redirected_to_file()` 函數使用 `libc::fstat` 檢測輸出類型 - 行為變更: - 終端輸出:保留顏色 ✅ - 管道傳輸 (|):保留顏色 ✅ (新) - 文件重定向 (>):禁用顏色 ❌ - 新增依賴:libc = "0.2" (Unix 平台) - 修改位置:src/main.rs:31-59 ### 3. Shell 配置文件自動識別 - 新增 shell 配置文件自動使用 bash 語法高亮 - 支援的文件名: - Bash: .bashrc, .bash_profile, .bash_login, .bash_logout, bashrc, bash_profile - Zsh: .zshrc, .zprofile, .zshenv, .zlogin, .zlogout - 通用: .profile - 修改位置:src/highlighter.rs:125-140 ## 技術細節 **Unix 平台文件類型檢測** 使用 `libc::fstat` 和 `S_IFMT` 掩碼檢測文件描述符類型: - `S_ISREG`: 普通文件 → 禁用顏色 - `S_ISFIFO`: 管道 → 保留顏色 - `S_ISCHR`: 字符設備(終端) → 保留顏色 **Windows 平台** 保守策略:非終端輸出一律禁用顏色(管道和文件都禁用) ## 版本資訊 - 版本:0.4.0 → 0.4.1 - 日期:2025-11-28 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 956ca28 commit a57fbad

4 files changed

Lines changed: 78 additions & 7 deletions

File tree

Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "cate"
3-
version = "0.4.0"
3+
version = "0.4.1"
44
edition = "2021"
55
authors = ["wen"]
66
description = "A lightweight CLI tool to display file contents with encoding support and syntax highlighting"
@@ -22,6 +22,9 @@ ansi_colours = "1.2" # RGB 到 ANSI 256 色轉換(與 bat 相同)
2222
[target.'cfg(windows)'.dependencies]
2323
winapi = { version = "0.3", features = ["winnls"] }
2424

25+
[target.'cfg(unix)'.dependencies]
26+
libc = "0.2" # 用於 fstat 檢測文件類型
27+
2528
[features]
2629
default = ["syntax-highlighting"]
2730
syntax-highlighting = []

src/highlighter.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,36 @@ impl Highlighter {
120120
}
121121

122122
// 特殊檔名處理
123-
match name.to_lowercase().as_str() {
123+
let name_lower = name.to_lowercase();
124+
125+
// Shell 配置文件
126+
if matches!(
127+
name_lower.as_str(),
128+
".bashrc"
129+
| ".bash_profile"
130+
| ".bash_login"
131+
| ".bash_logout"
132+
| ".zshrc"
133+
| ".zprofile"
134+
| ".zshenv"
135+
| ".zlogin"
136+
| ".zlogout"
137+
| ".profile"
138+
| "bashrc"
139+
| "bash_profile"
140+
) {
141+
// 嘗試找 Bash 或 Shell Script 語法
142+
if let Some(syntax) = SYNTAX_SET
143+
.find_syntax_by_name("Bash")
144+
.or_else(|| SYNTAX_SET.find_syntax_by_name("Shell Script (Bash)"))
145+
.or_else(|| SYNTAX_SET.find_syntax_by_extension("sh"))
146+
{
147+
return syntax;
148+
}
149+
}
150+
151+
// 其他特殊檔名
152+
match name_lower.as_str() {
124153
"makefile" | "gnumakefile" => {
125154
if let Some(syntax) = SYNTAX_SET.find_syntax_by_name("Makefile") {
126155
return syntax;

src/main.rs

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ mod printer;
44

55
use anyhow::Result;
66
use pico_args::Arguments;
7-
use std::io::{IsTerminal, Write};
7+
use std::io::Write;
88
use std::path::PathBuf;
99

1010
/// 顏色輸出模式
@@ -28,16 +28,55 @@ impl ColorMode {
2828
}
2929
}
3030

31-
/// 根據模式和 TTY 狀態決定是否啟用顏色
31+
/// 根據模式和輸出目標決定是否啟用顏色
32+
/// auto 模式:終端和管道有顏色,文件重定向無顏色
3233
fn should_colorize(&self) -> bool {
3334
match self {
34-
ColorMode::Auto => std::io::stdout().is_terminal(),
35+
ColorMode::Auto => !is_redirected_to_file(),
3536
ColorMode::Always => true,
3637
ColorMode::Never => false,
3738
}
3839
}
3940
}
4041

42+
/// 檢測 stdout 是否重定向到普通文件
43+
/// 返回 true 表示重定向到文件(應該禁用顏色)
44+
/// 返回 false 表示終端或管道(應該啟用顏色)
45+
fn is_redirected_to_file() -> bool {
46+
use std::io::IsTerminal;
47+
48+
// 如果是終端,肯定不是文件重定向
49+
if std::io::stdout().is_terminal() {
50+
return false;
51+
}
52+
53+
// 不是終端,需要進一步檢查是管道還是文件
54+
// 在 Unix 系統上,可以用 fstat 檢查
55+
#[cfg(unix)]
56+
{
57+
use std::os::unix::io::AsRawFd;
58+
let fd = std::io::stdout().as_raw_fd();
59+
60+
unsafe {
61+
let mut stat: libc::stat = std::mem::zeroed();
62+
if libc::fstat(fd, &mut stat) == 0 {
63+
// S_ISREG: 普通文件
64+
// S_ISFIFO: 管道(FIFO)
65+
// S_ISCHR: 字符設備(終端)
66+
return (stat.st_mode & libc::S_IFMT) == libc::S_IFREG;
67+
}
68+
}
69+
// Unix 檢查失敗,保守處理
70+
return false;
71+
}
72+
73+
// Windows:不是 TTY 就禁用顏色(無法區分管道和文件)
74+
#[cfg(not(unix))]
75+
{
76+
true
77+
}
78+
}
79+
4180
struct Args {
4281
files: Vec<PathBuf>,
4382
encoding: Option<String>,

src/printer.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ fn print_single_line(
7474
.unwrap_or_else(|_| line.to_string());
7575

7676
if show_line_numbers {
77-
match write!(stdout, "{:>6} {}", line_number, highlighted) {
77+
match write!(stdout, "{} {}", line_number, highlighted) {
7878
Ok(_) => Ok(()),
7979
Err(e) if e.kind() == io::ErrorKind::BrokenPipe => Ok(()),
8080
Err(e) => Err(e),
@@ -93,7 +93,7 @@ fn print_plain_line(line: &str, line_number: usize, show_line_numbers: bool) ->
9393
let mut stdout = io::stdout().lock();
9494

9595
if show_line_numbers {
96-
match writeln!(stdout, "{:>6} {}", line_number, line.trim_end()) {
96+
match writeln!(stdout, "{} {}", line_number, line.trim_end()) {
9797
Ok(_) => Ok(()),
9898
Err(e) if e.kind() == io::ErrorKind::BrokenPipe => Ok(()),
9999
Err(e) => Err(e),

0 commit comments

Comments
 (0)