| name | line-locator |
| description | Định vị dòng trước khi đọc file hoặc tìm file trong cây thư mục — tránh đọc mù, tiết kiệm token. Dùng khi cần tìm hàm, class, symbol, hoặc bất kỳ pattern nào trong source code trước khi gọi view_range. Hai công cụ: findtree.py (tìm file nào có chứa pattern) và findtool.py (tìm dòng nào trong một file).
|
| author | Kluco |
| github | unkluco |
| email | huylet334@gmail.com |
| version | 1.1.1 |
Line-Locator
Hai script phối hợp để định vị chính xác trước khi đọc:
| Script | Phạm vi | Câu hỏi trả lời |
|---|
findtree.py | Cả cây thư mục | File nào chứa pattern này? |
findtool.py | Một file duy nhất | Dòng nào trong file này? |
Workflow:
findtree.py (shortlist files) → findtool.py (locate lines) → view_range (read)
Script nằm tại: skills/line-locator/scripts/
Output contract
Tất cả pattern dùng Python regex.
findtool — success (stdout):
{"matches": {"processOrder": [247, 312]}}
{"line": 248}
{"matched": true}
findtree — success (stdout):
{"matched_files": ["src/order.js", "tests/order.test.js"]}
Failure — cả hai tool (stderr, exit 1):
{"ok": false, "error": "No line matching pattern 'foo' was found after line 0."}
Parse nhanh:
import json, subprocess
out = subprocess.check_output([...])
data = json.loads(out)
lines = data["matches"]["pat"]
line = data["line"]
matched = data["matched"]
files = data["matched_files"]
findtree — tìm file
python findtree.py --root ROOT --pattern PAT [options]
| Option | Mặc định | Mô tả |
|---|
--root | (required) | Thư mục gốc |
--pattern | (required) | Regex pattern |
--include GLOB... | (tất cả) | Chỉ tìm file khớp glob |
--exclude GLOB... | (không) | Bỏ qua file/thư mục khớp glob |
--ignore-case | off | Case-insensitive |
--max-results N | (không giới hạn) | Dừng sau N file |
--show | matched | matched / errors / both / summary / all |
--max-file-size | (không) | Bỏ qua file lớn hơn (VD: 64K, 10M) |
--no-default-dir-excludes | off | Tắt auto-skip .git, node_modules, v.v. |
--text | off | Output text thay vì JSON |
Auto-excluded dirs: .git, .hg, node_modules, venv, .venv, __pycache__, dist, build, target, .mypy_cache, .pytest_cache, .tox, coverage
python findtree.py --root ./src --pattern "processOrder"
python findtree.py --root ./src --pattern "class\s+\w+Service"
python findtree.py --root . --pattern "TODO" --include "*.ts" "*.js" --exclude "dist/**"
python findtree.py --root . --pattern "deprecated_api" --max-results 1
findtool — tìm dòng
python findtool.py --file FILE [--ignore-case] [-s] FLAG... [--text]
| Flag | Args | Mô tả | result key |
|---|
-mr | PAT [PAT ...] | Tất cả dòng khớp một hoặc nhiều pattern | {"matches": {"pat": [1,5]}} |
-n | PAT LINE | Dòng đầu tiên khớp sau LINE (0 = từ đầu file) | {"line": 45} |
-b | PAT LINE | Dòng cuối cùng khớp trước LINE (999999 = cuối file) | {"line": 12} |
-e | PAT | File có chứa pattern không? | {"matched": true} |
-c | OPEN CLOSE LINE N | Dòng đóng khớp với OPEN thứ N trên LINE (scan xuôi) | {"line": 89} |
-o | OPEN CLOSE LINE N | Dòng mở khớp với CLOSE thứ N trên LINE (scan ngược) | {"line": 34} |
Flag -s (chỉ dùng với -c/-o): bỏ qua nội dung string và comment khi đếm depth.
python findtool.py --file app.js -mr "processOrder"
python findtool.py --file app.js -mr "processOrder" "cancelOrder" "getUser"
python findtool.py --file app.js -n "function\s+\w+" 0
python findtool.py --file app.js -b "^import\s" 999999
python findtool.py --file app.js -e "TODO"
python findtool.py --file app.js -c "\{" "\}" 248 1
python findtool.py --file app.js -c "\{" "\}" 248 1 -s
python findtool.py --file app.js -o "\{" "\}" 298 1
Pair matching (-c / -o)
Cả hai flag đều nhận OPEN CLOSE LINE N theo cùng thứ tự:
-c OPEN CLOSE LINE N → anchor tại OPEN thứ N trên LINE, scan xuôi → trả về dòng CLOSE
-o OPEN CLOSE LINE N → anchor tại CLOSE thứ N trên LINE, scan ngược → trả về dòng OPEN
Algorithm: depth-tracking. Mỗi dòng tiếp theo: depth += count(OPEN) - count(CLOSE). Khi depth == 0 → trả về dòng đó.
Flag -s: trước khi đếm, mask toàn bộ string literals và comments (//, #, /* */, '...', "...", backtick, triple-quote). Dùng khi file có nhiều delimiter trong string/comment.
Pairs phổ biến theo ngôn ngữ
| Ngôn ngữ | Block mở | Block đóng | Ghi chú |
|---|
| JS/TS/Java/Go/Rust/C/C++/C# | \{ | \} | Dùng -s nếu file có { trong string |
| Bất kỳ — argument list | \( | \) | Áp dụng mọi ngôn ngữ |
| Bất kỳ — array/list | \[ | \] | Áp dụng mọi ngôn ngữ |
| HTML/XML | <div\b[^>]*> | </div> | Thay div bằng tên tag |
| Ruby | \bdo\b | \bend\b | Hoặc \bdef\b / \bend\b |
| Lua / Pascal-like | \bdo\b | \bend\b | |
| Shell (bash) | \bthen\b|\bdo\b | \bfi\b|\bdone\b | Phức tạp hơn |
| Python | (không có bracket) | (xem note bên dưới) | Dùng -n tìm def tiếp theo |
Python note: Python dùng indentation thay vì {}. Để tìm cuối hàm, dùng -n "^(def\|class)\s" FUNC_LINE tìm def/class tiếp theo cùng cấp, hoặc đọc từ FUNC_LINE đến dòng trước đó. Với argument list nhiều dòng: -c "\(" "\)" FUNC_LINE 1 vẫn hoạt động.
python findtool.py --file service.ts -c "\{" "\}" 248 1 -s
python findtool.py --file index.html -c "<div\b[^>]*>" "</div>" 10 1
python findtool.py --file user.rb -c "\bdef\b" "\bend\b" 42 1
python findtool.py --file builder.java -c "\(" "\)" 120 1
python findtool.py --file app.go -o "\{" "\}" 298 1
Workflows
1. Đọc một hàm đã biết tên
python findtool.py --file app.js -mr "processOrder"
python findtool.py --file app.js -n "\{" 247
python findtool.py --file app.js -c "\{" "\}" 248 1
view_range [247, 298]
2. Từ repository lạ → đọc hàm
python findtree.py --root ./src --pattern "processOrder"
python findtool.py --file services/order.js -mr "processOrder"
3. Scan cấu trúc tổng thể file
python findtool.py --file service.ts -mr "class\s+\w+" "function\s+\w+" "\bexport\b"
python findtool.py --file service.py -mr "^class\s+\w+" "^def\s+\w+" "^ def\s+\w+"
python findtool.py --file user.rb -mr "^\s*def\s+\w+" "^\s*class\s+\w+"
python findtool.py --file Service.java -mr "public\s+\w" "private\s+\w" "protected\s+\w"
4. Tìm nhiều symbol cùng lúc
python findtool.py --file app.js -mr "processOrder" "cancelOrder" "getUser"
5. Đọc tất cả imports
python findtool.py --file app.ts -mr "^import\s"
python findtool.py --file app.py -mr "^import\s" "^from\s"
python findtool.py --file App.java -mr "^import\s" "^using\s"
python findtool.py --file main.go -mr "^\s*\""
6. Xác định dòng đang thuộc scope nào (ngôn ngữ có {})
python findtool.py --file dao.js -b "\{" X
python findtool.py --file dao.js -c "\{" "\}" OPEN_LINE 1
view_range [OPEN_LINE - 1, OPEN_LINE]
7. Leo scope chain
python findtool.py --file app.js -b "\{" 245 → 198
python findtool.py --file app.js -b "\{" 198 → 134
python findtool.py --file app.js -b "\{" 134 → 12
python findtool.py --file app.js -b "\{" 12 → error → top-level
8. Tìm decorator / annotation
python findtool.py --file routes.py -b "@\w+" FUNC_LINE
python findtool.py --file Controller.java -b "@\w+" FUNC_LINE
python findtool.py --file service.ts -b "@\w+" FUNC_LINE
9. Tìm else / catch / finally
python findtool.py --file handler.js -c "\{" "\}" IF_LINE 1
python findtool.py --file handler.js -n "else|catch|finally" CLOSE_LINE
⚠️ Sai lầm phổ biến
1. Gọi -c trên dòng function name thay vì dòng {
python findtool.py --file app.js -c "\{" "\}" 247 1
python findtool.py --file app.js -n "\{" 247
python findtool.py --file app.js -c "\{" "\}" 248 1
Lý do: Trong nhiều ngôn ngữ, { có thể ở dòng tiếp theo sau tên hàm (Allman style). Không bao giờ đoán.
2. Nhầm lẫn kết quả đầu tiên của -mr là định nghĩa
python findtool.py --file app.js -mr "processOrder"
Số nhỏ nhất chưa chắc là định nghĩa. Đọc thêm vài dòng context để xác nhận, hoặc dùng pattern cụ thể hơn:
python findtool.py --file app.js -mr "function processOrder" "processOrder\s*\("
3. Pattern có ký tự đặc biệt không escape
python findtool.py --file app.py -mr "foo(bar)"
python findtool.py --file app.py -mr "foo\(bar\)"
python findtool.py --file app.py -mr "foo"
Ký tự cần escape trong regex: . ^ $ * + ? { } [ ] \ | ( )
4. Dùng Python {} để match scope hàm
Python không dùng {} cho function/class body. Dùng -c "\{" "\}" sẽ chỉ match dict/set literals.
python findtool.py --file service.py -c "\{" "\}" 42 1
python findtool.py --file service.py -n "^def \|^class " 42
python findtool.py --file service.py -n "^ def " 42
5. Quên rằng -n là sau LINE, không phải tại LINE
python findtool.py --file app.js -n "def " 247
python findtool.py --file app.js -n "def " 246
6. Bỏ qua -s khi file có nhiều { trong string/comment
python findtool.py --file query.ts -c "\{" "\}" 50 1
python findtool.py --file query.ts -c "\{" "\}" 50 1 -s
Nên dùng -s khi: file là template (.html, .ejs, .hbs), SQL inline, hoặc bất kỳ file nào có nhiều { không phải code.
7. Dùng findtool trực tiếp mà không biết file ở đâu
python findtool.py --file src/auth/service.js -mr "validateToken"
python findtree.py --root ./src --pattern "validateToken"
8. Không biết ngôn ngữ dùng { hay không → kiểm tra trước
Trước khi dùng -c "\{" "\}", xác nhận file có { không:
python findtool.py --file service.py -e "\{"
9. Dùng \| thay vì | cho alternation trong Python regex
python findtool.py --file app.java -mr "focusLost\|hidePopup\|showPopup"
python findtool.py --file app.java -mr "focusLost|hidePopup|showPopup"
Lý do nhầm: grep basic mode (BRE) dùng \| cho alternation. Python dùng ERE-style — | đã là alternation, \| là literal pipe.
Khi nào \| hợp lệ: không bao giờ trong Python regex nếu mục đích là alternation.
Bảng quyết định nhanh
| Tình huống | Dùng gì |
|---|
| Chưa biết file nào | findtree --root ... --pattern ... |
Biết tên hàm, muốn đọc body (ngôn ngữ có {}) | -mr "name" → -n "\{" LINE → -c "\{" "\}" OPEN 1 |
Ngôn ngữ không có {} (Python...) | -mr "name" → -n "^def|^class" LINE |
| Nhiều hàm cùng lúc | -mr "fn1" "fn2" "fn3" |
| Pattern có ký tự đặc biệt | escape: \(, \), \{, \., v.v. |
File có nhiều { trong string | thêm -s vào -c/-o |
| Duyệt từng hàm không biết tên | -mr "\{" → -c "\{" "\}" → -n "\{" → lặp |
| Ở dòng X, muốn biết thuộc hàm nào | -b "\{" X → -c "\{" "\}" OPEN 1 verify |
| Đọc hết imports | -mr "^import\s" → min/max → view_range |
| Argument list nhiều dòng | -c "\(" "\)" LINE 1 |
| Tìm else/catch/finally | -c "\{" "\}" IF_LINE 1 → -n "else|catch|finally" |
| Có decorator/annotation không? | -b "@\w+" FUNC_LINE → check khoảng cách |
| HTML tag pair | -c "<tag\b[^>]*>" "</tag>" LINE 1 |
| Ruby/Lua method body | -c "\bdef\b" "\bend\b" LINE 1 |
| Scope ngoài cùng | -b "\{" lặp đến error |
| File có chứa pattern không? | -e "pattern" |
| Chỉ tìm trong file .ts .js | findtree --include "*.ts" "*.js" |
| Dừng sớm khi tìm đủ | findtree --max-results 1 |
Xử lý lỗi
| Lỗi | Nguyên nhân | Cách xử lý |
|---|
"For -n, LINE must be >= 0" | Truyền số âm vào -n | Dùng 0 để tìm từ đầu file |
"For -b, LINE must be >= 1" | Truyền 0 vào -b | Dùng 999999 để tìm từ cuối file |
"Line X contains only 0 occurrence(s) of open pattern" | { không ở dòng đó | Dùng -n "\{" FUNC_LINE để tìm dòng { thực tế |
"No closing match for open pattern" | Không tìm thấy CLOSE trong file | File chưa đóng bracket, hoặc dùng thêm -s |
"No line matching pattern ... was found" | Pattern không khớp trong phạm vi | Kiểm tra lại regex; với -b có thể tăng LINE |
"Invalid regex pattern" | Regex sai cú pháp | Escape: \(, \), \{, \. |
"Root directory not found" | --root không tồn tại | Kiểm tra lại đường dẫn |
"N must be >= 1" | N = 0 trong -c/-o | N bắt đầu từ 1 |
Ví dụ end-to-end
Bài toán: Đọc hàm validateToken trong codebase 50 file, không biết nó nằm ở đâu.
python findtree.py --root ./src --pattern "validateToken"
python findtool.py --file auth/service.ts -mr "validateToken"
python findtool.py --file auth/service.ts -b "@\w+" 312
python findtool.py --file auth/service.ts -n "\{" 312
python findtool.py --file auth/service.ts -c "\{" "\}" 313 1 -s
view_range [310, 389]
Token tiêu thụ: ~80 dòng thay vì hàng nghìn. Tiết kiệm >90%.