# 🔭 Telescope: tìm file và grep trong dự án

By 3T1C

## Mục tiêu của bài này

Sau bài này, bạn sẽ:

- Khai báo Telescope trong `lua/plugins/telescope.lua` và hiểu vì sao cần `plenary.nvim`, `ripgrep`, `fd`.
- Gắn keybinding cho 5 picker dùng nhiều nhất: `find_files`, `live_grep`, `buffers`, symbol, `resume`.
- Đọc kết quả trong picker nhanh bằng preview và các phím mở file (`<CR>`, `<C-v>`, `<C-x>`, `<C-t>`).
- Cấu hình `file_ignore_patterns` để `node_modules` không làm nhiễu kết quả.

Bài trước bạn đã có LSP chạy với `vim.lsp.config` và diagnostics. Telescope không phụ thuộc LSP, nhưng hai thứ cộng lại mới thành vòng lặp điều hướng khép kín: LSP báo lỗi ở đâu, Telescope đưa bạn tới đó.

## Dựng Telescope trong cấu hình capstone

### Bước 1: Cài binary mà Telescope gọi ra

Telescope chỉ là UI. Phần tìm kiếm thật do binary bên ngoài làm:

- `live_grep` gọi `rg` (ripgrep). Không có `rg` thì picker báo lỗi ngay khi mở.
- `find_files` ưu tiên `fd`, không có thì fallback sang tự quét thư mục (chậm hơn nhiều trong repo lớn).

Trên Windows 11, mở PowerShell:

```powershell
winget install BurntSushi.ripgrep.MSVC
winget install sharkdp.fd
```

Đóng hẳn terminal rồi mở lại để PATH cập nhật, sau đó kiểm tra trong Neovim:

```vim
:lua print(vim.fn.exepath("rg"))
:lua print(vim.fn.exepath("fd"))
```

Ra đường dẫn tuyệt đối là xong. Ra chuỗi rỗng nghĩa là Neovim chưa thấy binary, thường vì bạn khởi động Neovim từ terminal cũ.

### Bước 2: Khai báo plugin

```lua
-- lua/plugins/telescope.lua
return {
  "nvim-telescope/telescope.nvim",
  tag = "0.1.8",
  dependencies = { "nvim-lua/plenary.nvim" },
  cmd = "Telescope",
  keys = {
    { "<leader>ff", "<cmd>Telescope find_files<cr>", desc = "Tìm file" },
    { "<leader>fg", "<cmd>Telescope live_grep<cr>", desc = "Grep trong dự án" },
    { "<leader>fb", "<cmd>Telescope buffers<cr>", desc = "Buffer đang mở" },
    { "<leader>fs", "<cmd>Telescope lsp_dynamic_workspace_symbols<cr>", desc = "Symbol toàn workspace" },
    { "<leader>fr", "<cmd>Telescope resume<cr>", desc = "Mở lại picker trước" },
  },
  opts = {
    defaults = {
      file_ignore_patterns = { "node_modules", "%.git/", "dist" },
      sorting_strategy = "ascending",
      layout_config = { prompt_position = "top" },
    },
  },
}
```

Lý do từng dòng:

- `tag = "0.1.8"`: ghim phiên bản để cấu hình không vỡ sau một lần `:Lazy update` trên máy công ty.
- `cmd = "Telescope"`: chỉ nạp plugin khi gọi lệnh hoặc bấm key, giữ thời gian khởi động thấp.
- `keys` khai báo cả `desc`, nên `which-key` (nếu bạn có) hiện mô tả tiếng Việt thay vì dấu hỏi.
- `file_ignore_patterns` dùng **Lua pattern**, không phải regex: `%.git/` chứ không phải `\.git/`. Đây là lỗi phổ biến nhất khiến filter không có tác dụng.
- `prompt_position = "top"`: ô nhập nằm trên, mắt không phải nhảy xuống dưới rồi ngược lên khi gõ.

### Bước 3: Dùng thử

Mở repo capstone, bấm `<leader>ff`, gõ một phần tên file, rồi:

| Phím | Tác dụng |
| --- | --- |
| `<C-n>` / `<C-p>` | Xuống / lên trong danh sách kết quả |
| `<CR>` | Mở ở cửa sổ hiện tại |
| `<C-v>` | Mở vertical split |
| `<C-x>` | Mở horizontal split |
| `<C-t>` | Mở tab mới |
| `?` | Hiện bảng mapping của picker đang mở |

Preview bên phải cho bạn thấy nội dung file hoặc dòng match trước khi quyết định mở. Đó chính là chỗ tiết kiệm thời gian: không mở file sai rồi đóng lại.

```mermaid
flowchart TD
    Start["🔍 Cần nhảy tới đâu?"] --> Q1{"Biết tên file?"}
    Q1 -->|Có| FF["📁 find_files"]
    Q1 -->|Không| Q2{"Nhớ nội dung code?"}
    Q2 -->|Có| FG["🔎 live_grep"]
    Q2 -->|Không| Q3{"File đang mở rồi?"}
    Q3 -->|Có| FB["🗂️ buffers"]
    Q3 -->|Không| FS["🧩 workspace symbols"]
```

## Thực hành trên repo capstone

Làm trên chính repo bạn sẽ dùng cho công việc, không dùng repo mẫu.

**Bài 1.** Mở Neovim ở thư mục gốc repo, bấm `<leader>fg`, gõ `TODO`. Ghi lại số kết quả và kiểm tra xem có dòng nào trong `node_modules` lọt vào không.

**Bài 2.** Bấm `<leader>fg`, gõ tên một hàm bạn biết là có trong repo, nhưng chỉ gõ 3 ký tự đầu. Dùng `<C-n>` chọn kết quả thứ ba, rồi `<C-v>` để mở vertical split. Sau đó bấm `<leader>fb` xem buffer đó có trong danh sách không.

**Bài 3.** Đặt con trỏ lên một hàm, bấm `<leader>fs`, gõ tên hàm. So sánh với `:Telescope lsp_document_symbols`: cái nào chỉ quét file hiện tại?

**Gợi ý và đáp án**

**Bài 1.** Nếu vẫn thấy `node_modules`, gần như chắc chắn `file_ignore_patterns` viết sai kiểu pattern (`\.git/` thay vì `%.git/`), hoặc bạn đang mở Neovim ở thư mục cha chứ không phải gốc repo. `live_grep` cũng tôn trọng `.gitignore`, nên nếu `node_modules` đã nằm trong `.gitignore` thì không cần khai báo lại, nhưng khai báo vẫn an toàn.

**Bài 2.** `<C-v>` mở file ở split dọc, buffer cũ vẫn còn, nên `<leader>fb` phải liệt kê cả hai. Đây là lý do `buffers` nhanh hơn `find_files`: nó không chạm đĩa.

**Bài 3.** `lsp_dynamic_workspace_symbols` quét toàn workspace (mọi file project), còn `lsp_document_symbols` chỉ quét file hiện tại. Dùng cái đầu khi bạn chỉ nhớ tên hàm, dùng cái sau khi đã ở đúng file và muốn nhảy trong file.

## Lỗi thường gặp khi dùng Telescope trên Windows 11

- **`live_grep` báo "rg not found"**: binary chưa có trong PATH của tiến trình Neovim. Kiểm tra bằng `:lua print(vim.fn.exepath("rg"))`, đừng đoán.
- **`find_files` chậm bất thường**: `fd` chưa cài, Telescope đang tự quét. Cài `fd` là hết.
- **Filter không ăn**: nhớ `file_ignore_patterns` là Lua pattern. `*` và `\` không hoạt động như regex quen thuộc.
- **Không gõ được dấu tiếng Việt trong prompt**: đó là giới hạn của input method tại cửa sổ prompt, không phải lỗi Telescope. Cứ gõ không dấu để tìm, tên file và code vẫn khớp bình thường.
- **Cài `telescope-fzf-native.nvim` rồi build lỗi**: extension này cần `make` và trình biên dịch. Trên Windows 11 đây là nguồn lỗi lớn mà lợi ích không tương xứng. Bỏ qua nó ở giai đoạn này.

## Mẹo dùng picker như người có nghề

- **Một picker, một câu hỏi.** Trước khi bấm key, tự hỏi "mình đang tìm tên file, nội dung, hay symbol?". Trả lời sai câu hỏi là mở sai picker, gõ lại từ đầu.
- **`resume` là phím quý nhất trong 5 phím trên.** Bạn vừa tìm xong, mở file, đọc một đoạn, cần quay lại danh sách cũ: `<leader>fr`. Không gõ lại pattern.
- **Grep bằng từ dưới con trỏ** khi đang đọc code: `:Telescope grep_string`. Nhanh hơn copy tên hàm rồi dán vào `live_grep`.
- **Đừng mở quá 6-7 buffer.** `<leader>fb` chỉ hữu ích khi danh sách còn ngắn. Nhiều hơn thì dùng `:bd` dọn bớt.
- **Ghim tag phiên bản Telescope.** Plugin này thay đổi mapping giữa các bản; ghim tag giúp cấu hình của bạn tái lập được trên máy thứ hai.

## Tóm lại

Telescope = UI của Neovim + binary tìm kiếm của hệ điều hành. Cài `ripgrep` và `fd` trước, khai báo plugin với `cmd` và `keys` để giữ startup nhanh, rồi luyện 5 picker (`ff`, `fg`, `fb`, `fs`, `fr`) cho tới khi phản xạ. Nhớ hai chi tiết dễ sai: `file_ignore_patterns` dùng Lua pattern, và `<leader>fr` đưa bạn về picker vừa dùng.

Bài tiếp theo chuyển sang Treesitter: bật parser để có highlight chính xác theo cú pháp và folding theo cấu trúc code, thay vì dựa vào regex.

Kiểm tra nhanh: `live_grep` cần binary nào? _____. `find_files` ưu tiên binary nào? _____. Phím mở kết quả ở vertical split là _____. Phím mở lại picker vừa dùng là _____. `file_ignore_patterns` dùng cú pháp _____ chứ không phải regex.

Front: Telescope dùng binary nào cho live_grep?
Back: ripgrep (rg), nên phải cài và có trong PATH.

Front: Telescope dùng binary nào cho find_files?
Back: fd; nếu không có, nó fallback sang tự quét thư mục nên chậm hơn.

Front: Plugin nào là dependency bắt buộc của telescope.nvim?
Back: plenary.nvim.

Front: Phím di chuyển xuống và lên trong danh sách kết quả?
Back: <C-n> xuống, <C-p> lên.

Front: Mở kết quả ở vertical split, horizontal split và tab mới?
Back: <C-v> dọc, <C-x> ngang, <C-t> tab mới.

Front: Phím nào hiện bảng mapping của picker đang mở?
Back: Dấu ? mở which_key của picker.

Front: file_ignore_patterns dùng cú pháp gì?
Back: Lua pattern, ví dụ %.git/ chứ không phải \.git/.

Front: builtin nào tìm symbol trên toàn workspace?
Back: lsp_dynamic_workspace_symbols.

Front: builtin nào chỉ tìm symbol trong file hiện tại?
Back: lsp_document_symbols.

Front: builtin nào mở lại picker vừa dùng mà không gõ lại pattern?
Back: resume, gắn với <leader>fr trong bài.

Front: Vì sao khai báo cmd = "Telescope" trong spec lazy.nvim?
Back: Để plugin chỉ nạp khi gọi lệnh, giữ thời gian khởi động thấp.

Front: Vì sao nên ghim tag phiên bản telescope.nvim?
Back: Mapping và API thay đổi giữa các bản, ghim tag giúp cấu hình tái lập được.

Front: Telescope có giúp ích gì khi LSP đã báo lỗi?
Back: Đưa bạn tới đúng file và dòng có lỗi bằng find_files, live_grep hoặc workspace symbols.

Front: Vì sao tạm bỏ qua telescope-fzf-native.nvim trên Windows 11?
Back: Nó cần make và trình biên dịch để build, dễ lỗi mà lợi ích chưa tương xứng.

---

## Contents

Part of [🛠️ Config neovim trên win 11](https://everwise.study/courses/config-neovim-tren-win-11.md)

- **🧱 Nền tảng cấu hình bằng Lua và plugin manager**
  - [📁 Bộ khung init.lua và cách tổ chức file cấu hình trên Windows 11](https://everwise.study/courses/config-neovim-tren-win-11/bo-khung-init-lua-tren-windows-11.md)
  - [📦 Quản lý plugin với lazy.nvim và hướng mở rộng với vim.pack](https://everwise.study/courses/config-neovim-tren-win-11/quan-ly-plugin-lazy-nvim-va-vim-pack.md) (sign-in required)
  - [⌨️ Keybinding, leader key và workflow làm việc hiệu quả](https://everwise.study/courses/config-neovim-tren-win-11/keybinding-leader-key-va-workflow.md)
  - [✅ Checkpoint: Nền tảng cấu hình Lua và plugin manager](https://everwise.study/courses/config-neovim-tren-win-11/checkpoint-nen-tang-cau-hinh-lua.md)
- **🧠 Đưa Neovim lên mức IDE: LSP, Telescope, Treesitter**
  - [🔍 LSP, autocomplete và diagnostics](https://everwise.study/courses/config-neovim-tren-win-11/lsp-autocomplete-va-diagnostics.md)
  - [🔭 Telescope: tìm file và grep trong dự án](https://everwise.study/courses/config-neovim-tren-win-11/telescope-tim-file-va-grep.md) — this lesson
  - [🌳 Treesitter: cú pháp, highlight và folding](https://everwise.study/courses/config-neovim-tren-win-11/treesitter-cu-phap-va-folding.md)
  - [✅ Checkpoint: LSP, Telescope và Treesitter](https://everwise.study/courses/config-neovim-tren-win-11/checkpoint-lsp-telescope-treesitter.md)
- **🚀 Capstone: cấu hình hoàn chỉnh dùng cho công việc thật**
  - [🌿 Tích hợp Git và terminal trong Neovim](https://everwise.study/courses/config-neovim-tren-win-11/tich-hop-git-va-terminal.md)
  - [🩺 Khắc phục lỗi đặc thù trên Windows 11](https://everwise.study/courses/config-neovim-tren-win-11/khac-phuc-loi-dac-thu-tren-windows-11.md)
  - [🏗️ Capstone: đóng gói cấu hình Neovim cho công việc thật](https://everwise.study/courses/config-neovim-tren-win-11/capstone-dong-goi-cau-hinh-neovim.md) (premium content)
  - [✅ Checkpoint: Capstone và xử lý sự cố trên Windows](https://everwise.study/courses/config-neovim-tren-win-11/checkpoint-capstone-windows.md) (premium content)
- [Course cheatsheet](https://everwise.study/courses/config-neovim-tren-win-11/cheatsheet.md) (premium content)
