Tùy chỉnh file picker @ trong Claude Code
Khi bạn gõ @ trong Claude Code, một file picker hiện lên để bạn chỉ cho Claude
một file. Đây là một trong những tính năng dùng nhiều nhất — và mặc định của nó lặng
lẽ cản đường bạn. File picker tuân theo .gitignore, nên bất cứ thứ gì git bỏ qua đều
vô hình; nó giới hạn trong dự án hiện tại; và cách khớp của nó khó tính hơn bạn muốn.
Bài này nói về vì sao những mặc định đó gây khó chịu, và cách tôi nhào nặn lại file
picker thành một thứ tìm được đúng cái tôi cần.
Vấn đề: file picker mặc định giấu quá nhiều
File picker @ hữu ích cho tới khi nó không còn hữu ích. Ba thứ làm tôi vấp:
- File bị gitignore là vô hình. Mặc định, file picker tôn trọng
.gitignore. Nghe thì gọn gàng, nhưng những file mà git bỏ qua thường lại đúng là những file tôi muốn đưa cho Claude xem: một.envcục bộ, một config được tạo ra, một build artifact tôi đang debug. Nếu git bỏ qua nó, tôi không@-nhắc được — tôi kẹt lại với việc dán đường dẫn bằng tay. - Không với tới ngoài dự án. File picker liệt kê các file dưới dự án hiện tại, hết. Một file ở thư mục trên một cấp, hay trong một repo anh em, không hiện ra.
- Cách khớp kén chọn. Tôi nhớ một mẩu của tên file, không phải cách viết hay chữ
hoa/thường chính xác. Nếu tôi gõ
dftmong trúngDemoFileTest.txt, một bộ khớp chặt sẽ trả về rỗng. Tôi muốn khớp mờ (fuzzy) — các chữ theo đúng thứ tự, mặc kệ hoa thường.
Hai trong số này quy về một thiết lập; cái thứ ba cần một script nhỏ. Claude Code cho bạn cả hai đòn bẩy.
Đòn bẩy một: thôi giấu các file bị gitignore
Cách sửa đầu tiên là một dòng trong settings.json:
{
"respectGitignore": false
}
Tắt cái đó đi, file picker thôi lọc theo .gitignore, và những file .env cục bộ và
config được tạo ra lại hiện lên. Xong vấn đề — nhưng nó tạo ra một cái mới. Git cũng
đang giấu tiếng ồn: node_modules, dist, target, .next. Tắt
respectGitignore và tất cả những cái đó ùa ngược vào file picker. Nên riêng thiết
lập là chưa đủ; bạn cần một cách tự giấu tiếng ồn. Đó là đòn bẩy thứ hai.
Đòn bẩy hai: một lệnh gợi ý tùy chỉnh
Claude Code cho bạn thay danh sách file của file picker bằng script của riêng bạn.
Trong settings.json:
{
"fileSuggestion": {
"type": "command",
"command": "~/.claude/file-suggestion.sh"
}
}
Giờ, thay vì logic dựng sẵn của nó, Claude Code chạy script của bạn mỗi lần bạn gõ sau
@. Giao ước rất đơn giản:
- Nó nhận một khối JSON qua stdin —
{"query": "thứ bạn gõ"}. - Thư mục gốc của dự án tới qua biến môi trường
CLAUDE_PROJECT_DIR. - Script của bạn in ra các đường dẫn tương đối, mỗi dòng một cái; Claude Code hiển thị khoảng 15 cái đầu.
Đó là toàn bộ giao diện. Một khi bạn làm chủ danh sách, bạn kiểm soát mọi thứ: giấu thư mục nào, khớp ra sao, xếp hạng kết quả thế nào, có hiện thư mục hay không. Đây là cách tôi dùng nó.
Giấu thư mục, ở khắp nơi
Việc đầu tiên là gỡ bỏ tiếng ồn mà respectGitignore: false để lọt vào. Script của
tôi liệt kê file bằng find, cắt bỏ (prune) các thư mục tôi không bao giờ muốn gợi ý
— trong bất kỳ dự án nào:
FIND=/usr/bin/find
ROOT="${CLAUDE_PROJECT_DIR:-$PWD}"
cd "$ROOT" 2>/dev/null || exit 0
files="$("$FIND" . \
\( -path '*/.git' \
-o -path '*/node_modules' \
-o -path '*/target' \
-o -path '*/dist' \
-o -path '*/build' \
-o -path '*/.next' \
-o -path '*/.venv' \
-o -path '*/vendor' \) -prune \
-o \( -type f -o -type d \) -print 2>/dev/null \
| sed 's|^\./||')"
Đây là một danh sách bỏ qua toàn cục nằm ở một chỗ, độc lập với .gitignore của bất
kỳ dự án nào. Muốn giấu thêm một thư mục ở khắp nơi? Thêm một dòng -o -path '*/NAME' -prune. Nó cũng liệt kê thư mục, không chỉ file, nên tôi có thể @-nhắc cả một thư
mục khi đó là ý tôi.
Khớp mờ, không phân biệt hoa thường
Việc còn lại là tìm file từ một mẩu của cái tên. Script của tôi làm một phép khớp
dãy con (subsequence): các chữ bạn gõ phải xuất hiện theo đúng thứ tự, nhưng không
cần liền nhau — và mọi thứ được đưa về chữ thường trước, nên hoa thường chẳng bao giờ
quan trọng. Đó là cái cho phép df khớp cả demoFile.txt lẫn DemoFileTest.txt, và
dft khớp DemoFileTest.txt.
Nó cũng xếp hạng kết quả để phỏng đoán tốt nhất lên đầu:
- Hạng 0 — query của bạn là một chuỗi con liền mạch của tên file (
demo→demoFile.txt). - Hạng 1 — query của bạn là một dãy con của tên file (
dft→DemoFileTest.txt). - Hạng 2 — query của bạn chỉ khớp ở đâu đó trong toàn đường dẫn (qua tên một thư mục cha).
Trong cùng một hạng, tên file ngắn hơn lên trước, rồi theo bảng chữ cái. Kết quả là file tôi đang hình dung thường là kết quả đầu bảng, kể cả khi tôi chỉ nhớ mang máng cái tên.
# Chưa có query: trả về một lát nhỏ để file picker không trống.
if [ -z "$query" ]; then
printf '%s\n' "$files" | head -n 20
exit 0
fi
# Ngược lại: đưa query về chữ thường và xếp hạng theo chuỗi con > dãy-con-của-tên >
# dãy-con-của-đường-dẫn, tên ngắn nhất trước. (Toàn bộ logic khớp nằm trong script.)
Còn file ngoài dự án thì sao?
Đây là hạn chế duy nhất mà các đòn bẩy không xóa được hoàn toàn. File picker — và
script của tôi — bắt gốc ở CLAUDE_PROJECT_DIR, nên một file trong repo anh em vẫn
không hiện. Điều cần biết là giờ bạn làm chủ danh sách: vì script của bạn quyết định
in ra những đường dẫn nào, bạn có thể trỏ ROOT sang chỗ khác, hoặc thêm một vị trí
tìm kiếm thứ hai, nếu bạn thật sự cần file ngoài cây thư mục. Tôi giữ của mình bắt gốc
ở dự án một cách có chủ đích — những file tôi nhắc gần như luôn nằm trong dự án — nhưng
cánh cửa để mở nếu luồng làm việc của bạn cần.
Vài điểm cần lưu ý
- Claude Code chạy script trong một shell trần, không tương tác. Các công cụ xịn
như
rgvàfzf, hay các lớp bọc shell quanhfind, có thể không nằm trênPATH. Tôi gọi các binary thật bằng đường dẫn tuyệt đối (/usr/bin/find,/usr/bin/jq) để script chạy được bất kể thế nào. - Giữ nó nhanh. Nó chạy ở mỗi phím gõ sau
@, nên mộtfindchậm trên một cây thư mục khổng lồ khiến file picker thấy ì. Cắt bỏ các thư mục lớn (ở trên) là thứ giữ cho nó nhanh nhẹn. - Giới hạn đầu ra. Claude Code chỉ hiện khoảng 15, nên kết thúc pipeline bằng
head -n 20tránh làm thêm việc mà bạn sẽ chẳng bao giờ thấy.
Một checklist để lấy dùng
- Đặt
respectGitignore: falseđể các file bị gitignore (.env, config được tạo ra) có thể được nhắc. - Thêm một lệnh
fileSuggestionđể nắm quyền danh sách một khi git không còn lọc giùm bạn. - Cắt bỏ các thư mục ồn (
node_modules,dist,target, …) trong script đó, ở một chỗ, cho mọi dự án. - Khớp mờ và không phân biệt hoa thường để một mẩu tên tìm ra file.
- Gọi công cụ bằng đường dẫn tuyệt đối, giữ script nhanh, và giới hạn kết quả.
File picker @ thì nhỏ, nhưng bạn động vào nó liên tục. Một thiết lập và một script
ngắn biến nó từ "cho tôi xem những gì git cho phép" thành "tìm ra đúng file tôi đang
nghĩ tới" — và khác biệt đó cộng dồn lại qua một ngày.
Link tham khảo
Bài viết gốc (tiếng Anh): Customizing the @ File Picker in Claude Code
All rights reserved