docs: simplify release documentation
Simplify README to focus on quick start and essential usage. Rename configuration.md to advanced.md for clearer positioning. Add v0.1.2 changelog entry. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
23d7f13cc7
commit
d28a4141d4
@@ -4,6 +4,16 @@ All notable changes to `lazy-project-search.nvim` are documented here.
|
||||
|
||||
The project is still pre-1.0. Rule schema and public APIs may evolve before `v1.0.0`.
|
||||
|
||||
## v0.1.2 - 2026-05-21
|
||||
|
||||
Documentation simplification release.
|
||||
|
||||
### Changed
|
||||
|
||||
- Simplified README to focus on quick start and essential usage.
|
||||
- Renamed `docs/configuration.md` to `docs/advanced.md` for clearer positioning.
|
||||
- Removed verbose sections from README, moved advanced details to separate docs.
|
||||
|
||||
## v0.1.1 - 2026-05-20
|
||||
|
||||
Documentation follow-up release.
|
||||
|
||||
@@ -1,68 +1,48 @@
|
||||
# lazy-project-search.nvim
|
||||
|
||||
Project-level search presets for Neovim and LazyVim, powered by Snacks Picker.
|
||||
A tiny project search menu for LazyVim / Neovim.
|
||||
|
||||
Turn repeated searches like `queryKey`, `className`, `hooks/use-*`, or `service/*.ts` into reusable project presets.
|
||||
|
||||
Press one key, pick a search, done.
|
||||
|
||||
[中文文档](README.zh-CN.md)
|
||||
|
||||
Status: usable for daily Neovim/LazyVim workflows. The rule format and public API may still change before v1.0.
|
||||
## What it does
|
||||
|
||||
## Documentation
|
||||
Most projects have a few searches you run again and again.
|
||||
|
||||
- [Configuration](docs/configuration.md)
|
||||
- [Formatting](docs/formatting.md)
|
||||
- [Validation and tests](docs/validation.md)
|
||||
- [Changelog](CHANGELOG.md)
|
||||
For example, in a React project you may often search for:
|
||||
|
||||
## Why
|
||||
- `queryKey`
|
||||
- `className`
|
||||
- custom hooks
|
||||
- route definitions
|
||||
- service layer files
|
||||
- TODO / FIXME
|
||||
- environment variable usage
|
||||
|
||||
Every real project develops its own search habits.
|
||||
This plugin lets you save those searches as project-local presets and open them from one fast picker.
|
||||
|
||||
In a React codebase, you may repeatedly look for:
|
||||
|
||||
- route files and route definitions
|
||||
- TanStack Query hooks and `queryKey`
|
||||
- service layer files, excluding tests
|
||||
- feature module entry files
|
||||
- cross-feature imports
|
||||
- UI component imports
|
||||
- TODO/FIXME and environment variable usage
|
||||
|
||||
Running ad-hoc grep commands for these patterns works, but the knowledge stays in your head. This plugin turns those project-specific searches into editable JSON presets, then exposes them through one fast picker.
|
||||
|
||||
Rules are stored outside your repository:
|
||||
Rules are stored outside your source repository:
|
||||
|
||||
```text
|
||||
~/.local/share/nvim/project-search/rules/<project-hash>.json
|
||||
~/.local/share/nvim/project-search/rules/
|
||||
```
|
||||
|
||||
That keeps source trees clean while still letting every project have its own search rules.
|
||||
So your project stays clean.
|
||||
|
||||
## What It Gives You
|
||||
|
||||
- Fast normal-mode entry point, recommended as `<C-p>`
|
||||
- Per-project JSON rule files
|
||||
- Auto-initialization on first use
|
||||
- Search rules for `files`, `grep`, and `files_regex`
|
||||
- Template detection for common, React, Vue, and NestJS projects
|
||||
- User template directories for personal/team presets
|
||||
- Rule previews in Snacks Picker
|
||||
- Cached rule validation by file mtime/size so opening the picker stays fast
|
||||
- Search presets grouped separately from management actions
|
||||
- A stable `:ProjectSearch` command with subcommands for edit/reset/validate/reload/templates/health
|
||||
|
||||
## React Project Example
|
||||
|
||||
The picker below is from a React project with route, TanStack Query, service layer, feature module, and UI import presets. Search rules stay at the top, while rule-management actions are grouped at the bottom.
|
||||
## Preview
|
||||
|
||||

|
||||
|
||||
This example shows a service-directory rule that finds API-layer files while excluding test files:
|
||||
## Install with LazyVim
|
||||
|
||||

|
||||
Create:
|
||||
|
||||
## Installation With LazyVim
|
||||
|
||||
Create `~/.config/nvim/lua/plugins/lazy-project-search.lua`:
|
||||
```text
|
||||
~/.config/nvim/lua/plugins/lazy-project-search.lua
|
||||
```
|
||||
|
||||
```lua
|
||||
return {
|
||||
@@ -84,8 +64,6 @@ return {
|
||||
},
|
||||
opts = {
|
||||
keymap = false,
|
||||
storage_dir = vim.fn.stdpath("data") .. "/project-search/rules",
|
||||
auto_init = true,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -109,211 +87,11 @@ Enable:
|
||||
editor.snacks_picker
|
||||
```
|
||||
|
||||
## Installation With Plain Neovim
|
||||
|
||||
LazyVim is not required. You can use this plugin in a regular Neovim setup as long as `snacks.nvim` is installed with picker enabled.
|
||||
|
||||
Example with lazy.nvim:
|
||||
|
||||
```lua
|
||||
return {
|
||||
{
|
||||
"folke/snacks.nvim",
|
||||
priority = 1000,
|
||||
lazy = false,
|
||||
opts = {
|
||||
picker = {
|
||||
enabled = true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CoderLambert/lazy-project-search.nvim",
|
||||
main = "project_search",
|
||||
dependencies = {
|
||||
"folke/snacks.nvim",
|
||||
},
|
||||
cmd = {
|
||||
"ProjectSearch",
|
||||
},
|
||||
keys = {
|
||||
{
|
||||
"<C-p>",
|
||||
"<cmd>ProjectSearch<cr>",
|
||||
desc = "Project Search",
|
||||
},
|
||||
},
|
||||
opts = {
|
||||
keymap = false,
|
||||
storage_dir = vim.fn.stdpath("data") .. "/project-search/rules",
|
||||
auto_init = true,
|
||||
root_markers = {
|
||||
".git",
|
||||
"package.json",
|
||||
"pnpm-workspace.yaml",
|
||||
"lazy-lock.json",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Without LazyVim, project root detection uses `root_markers`. You can override it completely:
|
||||
|
||||
```lua
|
||||
opts = {
|
||||
root = function()
|
||||
return vim.fs.root(0, { ".git", "package.json" }) or vim.fn.getcwd()
|
||||
end,
|
||||
}
|
||||
```
|
||||
|
||||
## Keymap Recommendations
|
||||
|
||||
The recommended mapping is normal-mode `<C-p>`:
|
||||
|
||||
```lua
|
||||
keys = {
|
||||
{
|
||||
"<C-p>",
|
||||
"<cmd>ProjectSearch<cr>",
|
||||
desc = "Project Search",
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Why `<C-p>`:
|
||||
|
||||
- Fast single chord for a frequently used project picker.
|
||||
- Mnemonic for Project Search or Project Picker.
|
||||
- Avoids LazyVim's common `<leader>p` yank-history mapping.
|
||||
- Does not affect insert-mode `<C-p>` completion navigation.
|
||||
|
||||
Useful alternatives:
|
||||
|
||||
| Keymap | When to use |
|
||||
| --- | --- |
|
||||
| `<C-p>` | Recommended when normal-mode `<C-p>` is free. |
|
||||
| `<leader>sP` | Best conflict-free fallback inside LazyVim's search namespace. |
|
||||
| `<leader>fP` | Good if you prefer grouping project search under file/find commands. |
|
||||
|
||||
Avoid `<leader>p` in LazyVim setups because it is commonly used for Yank History. Avoid `<leader><space>` and `<leader>fp` because LazyVim uses them for Find Files and Projects.
|
||||
|
||||
## How To Use It In Your Project
|
||||
|
||||
1. Open a project in Neovim.
|
||||
2. Press `<C-p>` or run `:ProjectSearch`.
|
||||
3. On first use, the plugin creates a JSON rules file for the current project and opens it.
|
||||
4. Edit the generated presets to match your project conventions.
|
||||
5. Press `<C-p>` again and run searches from the picker.
|
||||
|
||||
The useful workflow is:
|
||||
|
||||
- Start from generated common/React/Vue/Nest presets.
|
||||
- Add rules for project-specific directories such as `features`, `routes`, `service`, `modules`, or `packages`.
|
||||
- Turn repeated manual searches into named rules.
|
||||
- Keep rules specific enough to be useful, but broad enough to survive refactors.
|
||||
|
||||
Good candidates for custom rules:
|
||||
|
||||
| Need | Rule type |
|
||||
| --- | --- |
|
||||
| Open a common directory quickly | `files` |
|
||||
| Search code text such as `queryKey`, `className`, `TODO` | `grep` |
|
||||
| Find files by path conventions such as `hooks/use-*` | `files_regex` |
|
||||
|
||||
## Commands
|
||||
|
||||
The recommended command interface uses one stable lazy.nvim entry point:
|
||||
|
||||
```vim
|
||||
:ProjectSearch
|
||||
:ProjectSearch edit
|
||||
:ProjectSearch init
|
||||
:ProjectSearch init!
|
||||
:ProjectSearch reset
|
||||
:ProjectSearch path
|
||||
:ProjectSearch validate
|
||||
:ProjectSearch reload
|
||||
:ProjectSearch templates
|
||||
:ProjectSearch health
|
||||
:ProjectSearch help
|
||||
```
|
||||
|
||||
Backward-compatible command aliases are still registered after the plugin loads:
|
||||
|
||||
```vim
|
||||
:ProjectSearchEdit
|
||||
:ProjectSearchInit
|
||||
:ProjectSearchInit!
|
||||
:ProjectSearchReset
|
||||
:ProjectSearchPath
|
||||
:ProjectSearchValidate
|
||||
:ProjectSearchReload
|
||||
:ProjectSearchTemplates
|
||||
:ProjectSearchHealth
|
||||
```
|
||||
|
||||
`ProjectSearch validate` validates the current project's JSON rules and reports errors/warnings. `ProjectSearch reload` clears the in-memory rules cache and reloads rules from disk.
|
||||
|
||||
## Configuration
|
||||
|
||||
For the complete configuration reference and rule schema, see [docs/configuration.md](docs/configuration.md).
|
||||
|
||||
```lua
|
||||
require("project_search").setup({
|
||||
keymap = "<leader>sP",
|
||||
auto_init = true,
|
||||
storage_dir = vim.fn.stdpath("data") .. "/project-search/rules",
|
||||
template_dirs = {
|
||||
vim.fn.stdpath("config") .. "/project-search/templates",
|
||||
vim.fn.stdpath("data") .. "/project-search/templates",
|
||||
},
|
||||
root = nil,
|
||||
root_markers = {
|
||||
".git",
|
||||
"package.json",
|
||||
"pnpm-workspace.yaml",
|
||||
"pnpm-lock.yaml",
|
||||
"yarn.lock",
|
||||
"package-lock.json",
|
||||
"lazy-lock.json",
|
||||
"stylua.toml",
|
||||
"selene.toml",
|
||||
},
|
||||
default_excludes = {
|
||||
".git",
|
||||
"node_modules",
|
||||
"dist",
|
||||
"build",
|
||||
".next",
|
||||
".nuxt",
|
||||
"coverage",
|
||||
},
|
||||
templates = {
|
||||
common = true,
|
||||
react = true,
|
||||
vue = true,
|
||||
nest = true,
|
||||
user = {},
|
||||
},
|
||||
picker = {
|
||||
title = "Project Search",
|
||||
layout = "default",
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
If you use lazy.nvim `keys`, keep `keymap = false` in `opts` to avoid registering the key twice.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Neovim 0.10+
|
||||
- `folke/snacks.nvim`
|
||||
- `ripgrep` for grep presets
|
||||
- `fd` or `fdfind` for `files_regex` presets
|
||||
Install `ripgrep` and `fd`.
|
||||
|
||||
Ubuntu/Linux Mint:
|
||||
Ubuntu / Linux Mint:
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
@@ -323,31 +101,56 @@ mkdir -p ~/.local/bin
|
||||
ln -sf "$(command -v fdfind)" ~/.local/bin/fd
|
||||
```
|
||||
|
||||
## Rule Types
|
||||
Arch Linux:
|
||||
|
||||
### files
|
||||
|
||||
Use `files` when you want a file picker rooted at a specific project directory.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "common.files.src",
|
||||
"name": "Files: src",
|
||||
"description": "Open a file picker rooted at src.",
|
||||
"type": "files",
|
||||
"cwd": "src"
|
||||
}
|
||||
```bash
|
||||
sudo pacman -S ripgrep fd
|
||||
```
|
||||
|
||||
### grep
|
||||
macOS:
|
||||
|
||||
Use `grep` when you want to search inside files.
|
||||
```bash
|
||||
brew install ripgrep fd
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Open a project and run:
|
||||
|
||||
```vim
|
||||
:ProjectSearch
|
||||
```
|
||||
|
||||
Or press:
|
||||
|
||||
```text
|
||||
<C-p>
|
||||
```
|
||||
|
||||
On first use, the plugin creates a rules file for the current project.
|
||||
|
||||
Edit that JSON file, save it, then open `:ProjectSearch` again.
|
||||
|
||||
## Common commands
|
||||
|
||||
```vim
|
||||
:ProjectSearch
|
||||
:ProjectSearch edit
|
||||
:ProjectSearch validate
|
||||
:ProjectSearch reload
|
||||
:ProjectSearch reset
|
||||
:ProjectSearch path
|
||||
:ProjectSearch health
|
||||
```
|
||||
|
||||
## Example rule
|
||||
|
||||
Search `queryKey` in React files:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "react.query_key",
|
||||
"name": "React: queryKey",
|
||||
"description": "Search TanStack Query queryKey usage.",
|
||||
"type": "grep",
|
||||
"search": "queryKey",
|
||||
"dirs": ["src", "app"],
|
||||
@@ -355,131 +158,36 @@ Use `grep` when you want to search inside files.
|
||||
}
|
||||
```
|
||||
|
||||
Regex grep:
|
||||
Find hook files like `hooks/use-user-panel.ts`:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "react.query_hooks",
|
||||
"name": "TanStack Query: hooks",
|
||||
"description": "Search query-related React hooks.",
|
||||
"type": "grep",
|
||||
"regex": true,
|
||||
"search": "useQuery|useMutation|useInfiniteQuery",
|
||||
"dirs": ["src"],
|
||||
"glob": ["*.ts", "*.tsx"]
|
||||
}
|
||||
```
|
||||
|
||||
### files_regex
|
||||
|
||||
Use `files_regex` when you want to find files by path convention.
|
||||
|
||||
`files_regex` is backed by `fd`/`fdfind`, so its regex syntax follows Rust regex rules. Look-around is not supported. Avoid `(?=...)`, `(?!...)`, `(?<=...)`, and `(?<!...)`.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "react.hooks.kebab",
|
||||
"name": "Hooks: use-* kebab files",
|
||||
"description": "Find hook files such as hooks/use-claw-history-panel.ts.",
|
||||
"id": "react.hooks",
|
||||
"name": "Hooks: use-* files",
|
||||
"type": "files_regex",
|
||||
"regex": "(^|/)hooks/use-[a-z0-9-]+\\.(ts|tsx|js|jsx)$",
|
||||
"dirs": ["src", "app", "packages"],
|
||||
"exclude": ["node_modules", "dist", "build", ".next"]
|
||||
"dirs": ["src", "app", "packages"]
|
||||
}
|
||||
```
|
||||
|
||||
Use `exclude` for negative file-name filters. For example, to find service layer files but exclude test files:
|
||||
Open files under `src`:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "project.service_files",
|
||||
"name": "Service: API layer files",
|
||||
"description": "Find TypeScript files under service directories, excluding test files.",
|
||||
"type": "files_regex",
|
||||
"regex": "service/[^/]+\\.(ts|tsx)$",
|
||||
"dirs": ["src"],
|
||||
"exclude": ["*.test.ts", "*.test.tsx", "*.spec.ts", "*.spec.tsx"]
|
||||
"id": "files.src",
|
||||
"name": "Files: src",
|
||||
"type": "files",
|
||||
"cwd": "src"
|
||||
}
|
||||
```
|
||||
|
||||
Do not write that rule with lookbehind, because `fd` will reject it:
|
||||
## Rule types
|
||||
|
||||
```json
|
||||
{
|
||||
"regex": "service/[^/]+(?<!\\.test|\\.spec)\\.(ts|tsx)$"
|
||||
}
|
||||
```
|
||||
|
||||
If `fd` rejects a regex, Project Search reports the underlying `fd` error instead of silently showing an empty result.
|
||||
|
||||
`dirs`, `glob`, `exclude`, and `args` may be written as either a string or a string array. Project Search normalizes string values into arrays before running presets.
|
||||
|
||||
## Picker Layout
|
||||
|
||||
The main panel keeps executable search rules first and management actions at the bottom:
|
||||
|
||||
```text
|
||||
── Common ──
|
||||
Files: src files
|
||||
|
||||
── React ──
|
||||
React: className grep
|
||||
|
||||
── Service ──
|
||||
Service: API layer files files_regex
|
||||
|
||||
── Manage ──
|
||||
Edit current project search rules
|
||||
Reset current project rules from template
|
||||
Validate current project rules
|
||||
Reload current project rules
|
||||
Copy current rules path
|
||||
```
|
||||
|
||||
Rule previews are generated on demand when the preview pane needs them, so opening the panel stays fast even with many presets.
|
||||
|
||||
## Example Rules For A React Project
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 1,
|
||||
"meta": {
|
||||
"projectRoot": "/home/lambert/githubRepos/your-project",
|
||||
"template": "react",
|
||||
"createdAt": "2026-05-20T00:00:00Z",
|
||||
"note": "This file is stored outside your project. Edit presets to customize Project Search."
|
||||
},
|
||||
"presets": [
|
||||
{
|
||||
"id": "react.hooks.kebab",
|
||||
"name": "Hooks: use-* kebab files",
|
||||
"description": "Find hook files such as hooks/use-claw-history-panel.ts.",
|
||||
"type": "files_regex",
|
||||
"regex": "(^|/)hooks/use-[a-z0-9-]+\\.(ts|tsx|js|jsx)$",
|
||||
"dirs": ["src", "app", "packages"]
|
||||
},
|
||||
{
|
||||
"id": "react.query_hooks",
|
||||
"name": "TanStack Query: hooks",
|
||||
"description": "Search query-related React hooks.",
|
||||
"type": "grep",
|
||||
"regex": true,
|
||||
"search": "useQuery|useMutation|useInfiniteQuery",
|
||||
"dirs": ["src"],
|
||||
"glob": ["*.ts", "*.tsx"]
|
||||
},
|
||||
{
|
||||
"id": "project.service_files",
|
||||
"name": "Service: API layer files",
|
||||
"description": "Find TypeScript files under service directories, excluding test files.",
|
||||
"type": "files_regex",
|
||||
"regex": "service/[^/]+\\.(ts|tsx)$",
|
||||
"dirs": ["src"],
|
||||
"exclude": ["*.test.ts", "*.test.tsx", "*.spec.ts", "*.spec.tsx"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
| Type | Use for |
|
||||
| --- | --- |
|
||||
| `files` | Open a file picker in a directory |
|
||||
| `grep` | Search text in files |
|
||||
| `files_regex` | Find files by path pattern |
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
@@ -489,19 +197,30 @@ Run:
|
||||
:ProjectSearch health
|
||||
```
|
||||
|
||||
or:
|
||||
Or:
|
||||
|
||||
```vim
|
||||
:checkhealth project_search
|
||||
```
|
||||
|
||||
The health check validates the current project rules when a rules file exists.
|
||||
Common checks:
|
||||
|
||||
Common issues:
|
||||
|
||||
| Symptom | Check |
|
||||
| Problem | Check |
|
||||
| --- | --- |
|
||||
| `grep` rules are empty | Make sure `ripgrep` is installed. |
|
||||
| `files_regex` rules are empty | Make sure `fd`/`fdfind` is installed and the regex is supported by Rust regex. |
|
||||
| First use opens a JSON file | That is expected. Edit and save the generated project rules, then open the picker again. |
|
||||
| A keymap does nothing | Check `:verbose nmap <C-p>` and choose a conflict-free key in your lazy.nvim spec. |
|
||||
| `grep` result is empty | Make sure `ripgrep` is installed |
|
||||
| `files_regex` result is empty | Make sure `fd` is installed |
|
||||
| First use opens a JSON file | This is expected. Edit and save it |
|
||||
| Keymap does nothing | Check `:verbose nmap <C-p>` |
|
||||
|
||||
## More docs
|
||||
|
||||
- [Advanced configuration](docs/advanced.md)
|
||||
- [Formatting](docs/formatting.md)
|
||||
- [Validation and tests](docs/validation.md)
|
||||
- [Changelog](CHANGELOG.md)
|
||||
|
||||
## Status
|
||||
|
||||
Usable for daily LazyVim / Neovim workflows.
|
||||
|
||||
The rule format may still change before `v1.0.0`.
|
||||
+100
-376
@@ -1,67 +1,48 @@
|
||||
# lazy-project-search.nvim
|
||||
|
||||
基于 Neovim/LazyVim 和 Snacks Picker 的项目级搜索规则面板。
|
||||
一个给 LazyVim / Neovim 用的轻量项目搜索菜单。
|
||||
|
||||
把你在项目里经常重复搜的内容,比如 `queryKey`、`className`、`hooks/use-*`、`service/*.ts`,沉淀成可复用的搜索规则。
|
||||
|
||||
按一个快捷键,选择规则,直接搜索。
|
||||
|
||||
[English README](README.md)
|
||||
|
||||
状态:已经可以用于日常 Neovim/LazyVim 工作流。规则格式和公开 API 在 v1.0 前仍可能调整。
|
||||
|
||||
## 文档
|
||||
|
||||
- [配置说明](docs/configuration.md)
|
||||
- [格式化说明](docs/formatting.md)
|
||||
- [校验与测试](docs/validation.md)
|
||||
- [更新日志](CHANGELOG.md)
|
||||
|
||||
## 它解决什么问题
|
||||
|
||||
真实项目通常都有自己的代码组织习惯。
|
||||
真实项目里,总有一些搜索会反复执行。
|
||||
|
||||
在 React 项目里,你可能经常反复查找:
|
||||
比如 React 项目里经常要搜:
|
||||
|
||||
- 路由文件和路由定义
|
||||
- TanStack Query hooks 和 `queryKey`
|
||||
- service 层文件,并排除测试文件
|
||||
- feature 模块入口
|
||||
- 跨 feature 的 import
|
||||
- UI 组件 import
|
||||
- TODO/FIXME 和环境变量使用
|
||||
- `queryKey`
|
||||
- `className`
|
||||
- 自定义 hooks
|
||||
- 路由定义
|
||||
- service 层文件
|
||||
- TODO / FIXME
|
||||
- 环境变量使用
|
||||
|
||||
每次手动 grep 虽然能解决问题,但这些搜索经验都停留在脑子里。这个插件把这些高频搜索沉淀成可编辑的 JSON 规则,并通过一个快速面板统一执行。
|
||||
这个插件可以把这些搜索保存成项目规则,并通过一个快速 picker 统一打开。
|
||||
|
||||
规则文件存储在项目外部:
|
||||
规则文件存放在项目外部:
|
||||
|
||||
```text
|
||||
~/.local/share/nvim/project-search/rules/<project-hash>.json
|
||||
~/.local/share/nvim/project-search/rules/
|
||||
```
|
||||
|
||||
这样不会污染源码,也不会误提交到业务仓库,同时每个项目都可以拥有独立规则。
|
||||
不会污染业务仓库,也不会误提交。
|
||||
|
||||
## 功能
|
||||
|
||||
- 推荐使用 `<C-p>` 快速唤出
|
||||
- 每个项目独立 JSON 规则文件
|
||||
- 第一次使用自动初始化规则
|
||||
- 支持 `files`、`grep`、`files_regex` 三种规则
|
||||
- 自动检测 common、React、Vue、NestJS 模板
|
||||
- 支持用户模板目录,便于沉淀个人/团队规则
|
||||
- 在 Snacks Picker 右侧预览规则详情
|
||||
- 搜索规则和管理动作分组展示
|
||||
- 稳定的 `:ProjectSearch` 单入口命令,支持 edit/reset/validate/reload/templates/health 等子命令
|
||||
|
||||
## React 项目示例
|
||||
|
||||
下面是一个 React 项目的使用效果,包含 route、TanStack Query、service layer、feature module、UI import 等规则。搜索规则在上方,规则管理动作在底部。
|
||||
## 预览
|
||||
|
||||

|
||||
|
||||
这个示例展示了如何查找 service 目录下的 API 层文件,并排除测试文件:
|
||||
|
||||

|
||||
|
||||
## LazyVim 安装
|
||||
|
||||
创建 `~/.config/nvim/lua/plugins/lazy-project-search.lua`:
|
||||
创建:
|
||||
|
||||
```text
|
||||
~/.config/nvim/lua/plugins/lazy-project-search.lua
|
||||
```
|
||||
|
||||
```lua
|
||||
return {
|
||||
@@ -83,8 +64,6 @@ return {
|
||||
},
|
||||
opts = {
|
||||
keymap = false,
|
||||
storage_dir = vim.fn.stdpath("data") .. "/project-search/rules",
|
||||
auto_init = true,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -108,211 +87,11 @@ LazyVim 用户需要启用 Snacks Picker:
|
||||
editor.snacks_picker
|
||||
```
|
||||
|
||||
## 原生 Neovim 安装
|
||||
|
||||
这个插件不强依赖 LazyVim。只要你的 Neovim 安装了 `snacks.nvim`,并启用了 picker,就可以使用。
|
||||
|
||||
lazy.nvim 示例:
|
||||
|
||||
```lua
|
||||
return {
|
||||
{
|
||||
"folke/snacks.nvim",
|
||||
priority = 1000,
|
||||
lazy = false,
|
||||
opts = {
|
||||
picker = {
|
||||
enabled = true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"CoderLambert/lazy-project-search.nvim",
|
||||
main = "project_search",
|
||||
dependencies = {
|
||||
"folke/snacks.nvim",
|
||||
},
|
||||
cmd = {
|
||||
"ProjectSearch",
|
||||
},
|
||||
keys = {
|
||||
{
|
||||
"<C-p>",
|
||||
"<cmd>ProjectSearch<cr>",
|
||||
desc = "Project Search",
|
||||
},
|
||||
},
|
||||
opts = {
|
||||
keymap = false,
|
||||
storage_dir = vim.fn.stdpath("data") .. "/project-search/rules",
|
||||
auto_init = true,
|
||||
root_markers = {
|
||||
".git",
|
||||
"package.json",
|
||||
"pnpm-workspace.yaml",
|
||||
"lazy-lock.json",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
没有 LazyVim 时,项目根目录通过 `root_markers` 检测。你也可以完全自定义:
|
||||
|
||||
```lua
|
||||
opts = {
|
||||
root = function()
|
||||
return vim.fs.root(0, { ".git", "package.json" }) or vim.fn.getcwd()
|
||||
end,
|
||||
}
|
||||
```
|
||||
|
||||
## 快捷键建议
|
||||
|
||||
推荐 normal mode 使用 `<C-p>`:
|
||||
|
||||
```lua
|
||||
keys = {
|
||||
{
|
||||
"<C-p>",
|
||||
"<cmd>ProjectSearch<cr>",
|
||||
desc = "Project Search",
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
为什么推荐 `<C-p>`:
|
||||
|
||||
- 高频功能,一键组合更快。
|
||||
- 语义上可以理解成 Project Search / Project Picker。
|
||||
- 避开 LazyVim 常见的 `<leader>p` Yank History 映射。
|
||||
- 不影响 insert mode 下 `<C-p>` 的补全候选切换。
|
||||
|
||||
可选方案:
|
||||
|
||||
| 快捷键 | 适用场景 |
|
||||
| --- | --- |
|
||||
| `<C-p>` | normal mode 没有冲突时推荐使用。 |
|
||||
| `<leader>sP` | 放在 LazyVim search 命名空间下,冲突概率低。 |
|
||||
| `<leader>fP` | 如果你希望把项目搜索归到 file/find 类命令下。 |
|
||||
|
||||
不建议在 LazyVim 里使用 `<leader>p`,因为它常被 Yank History 占用;也不建议使用 `<leader><space>` 和 `<leader>fp`,因为 LazyVim 默认分别用于 Find Files 和 Projects。
|
||||
|
||||
## 如何结合自己的项目使用
|
||||
|
||||
1. 在 Neovim 中打开你的项目。
|
||||
2. 按 `<C-p>` 或执行 `:ProjectSearch`。
|
||||
3. 第一次使用时,插件会为当前项目创建 JSON 规则文件并打开。
|
||||
4. 根据你的项目结构编辑规则。
|
||||
5. 再次按 `<C-p>`,从面板里执行搜索。
|
||||
|
||||
推荐工作流:
|
||||
|
||||
- 先从自动生成的 common/React/Vue/Nest 规则开始。
|
||||
- 为项目特有目录添加规则,例如 `features`、`routes`、`service`、`modules`、`packages`。
|
||||
- 把反复手动 grep 的搜索沉淀成命名规则。
|
||||
- 规则不要过窄,避免一次重构就失效;也不要过宽,否则搜索结果噪音太多。
|
||||
|
||||
适合做成规则的场景:
|
||||
|
||||
| 需求 | 规则类型 |
|
||||
| --- | --- |
|
||||
| 快速打开常用目录 | `files` |
|
||||
| 搜索 `queryKey`、`className`、`TODO` 等代码文本 | `grep` |
|
||||
| 按路径约定找文件,例如 `hooks/use-*` | `files_regex` |
|
||||
|
||||
## 命令
|
||||
|
||||
推荐使用稳定的单入口命令:
|
||||
|
||||
```vim
|
||||
:ProjectSearch
|
||||
:ProjectSearch edit
|
||||
:ProjectSearch init
|
||||
:ProjectSearch init!
|
||||
:ProjectSearch reset
|
||||
:ProjectSearch path
|
||||
:ProjectSearch validate
|
||||
:ProjectSearch reload
|
||||
:ProjectSearch templates
|
||||
:ProjectSearch health
|
||||
:ProjectSearch help
|
||||
```
|
||||
|
||||
插件加载后仍然会注册兼容旧习惯的别名命令:
|
||||
|
||||
```vim
|
||||
:ProjectSearchEdit
|
||||
:ProjectSearchInit
|
||||
:ProjectSearchInit!
|
||||
:ProjectSearchReset
|
||||
:ProjectSearchPath
|
||||
:ProjectSearchValidate
|
||||
:ProjectSearchReload
|
||||
:ProjectSearchTemplates
|
||||
:ProjectSearchHealth
|
||||
```
|
||||
|
||||
`ProjectSearch validate` 用于校验当前项目 JSON 规则并显示错误/警告。`ProjectSearch reload` 用于清空内存缓存并从磁盘重新读取规则。
|
||||
|
||||
## 配置
|
||||
|
||||
完整配置项和规则字段说明见 [docs/configuration.md](docs/configuration.md)。
|
||||
|
||||
```lua
|
||||
require("project_search").setup({
|
||||
keymap = "<leader>sP",
|
||||
auto_init = true,
|
||||
storage_dir = vim.fn.stdpath("data") .. "/project-search/rules",
|
||||
template_dirs = {
|
||||
vim.fn.stdpath("config") .. "/project-search/templates",
|
||||
vim.fn.stdpath("data") .. "/project-search/templates",
|
||||
},
|
||||
root = nil,
|
||||
root_markers = {
|
||||
".git",
|
||||
"package.json",
|
||||
"pnpm-workspace.yaml",
|
||||
"pnpm-lock.yaml",
|
||||
"yarn.lock",
|
||||
"package-lock.json",
|
||||
"lazy-lock.json",
|
||||
"stylua.toml",
|
||||
"selene.toml",
|
||||
},
|
||||
default_excludes = {
|
||||
".git",
|
||||
"node_modules",
|
||||
"dist",
|
||||
"build",
|
||||
".next",
|
||||
".nuxt",
|
||||
"coverage",
|
||||
},
|
||||
templates = {
|
||||
common = true,
|
||||
react = true,
|
||||
vue = true,
|
||||
nest = true,
|
||||
user = {},
|
||||
},
|
||||
picker = {
|
||||
title = "Project Search",
|
||||
layout = "default",
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
如果你已经通过 lazy.nvim 的 `keys` 配置快捷键,建议在 `opts` 中设置 `keymap = false`,避免重复注册。
|
||||
|
||||
## 依赖
|
||||
|
||||
- Neovim 0.10+
|
||||
- `folke/snacks.nvim`
|
||||
- `grep` 规则需要 `ripgrep`
|
||||
- `files_regex` 规则需要 `fd` 或 `fdfind`
|
||||
安装 `ripgrep` 和 `fd`。
|
||||
|
||||
Ubuntu/Linux Mint:
|
||||
Ubuntu / Linux Mint:
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
@@ -322,31 +101,56 @@ mkdir -p ~/.local/bin
|
||||
ln -sf "$(command -v fdfind)" ~/.local/bin/fd
|
||||
```
|
||||
|
||||
## 规则类型
|
||||
Arch Linux:
|
||||
|
||||
### files
|
||||
|
||||
用于在指定项目目录下打开文件选择器。
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "common.files.src",
|
||||
"name": "Files: src",
|
||||
"description": "Open a file picker rooted at src.",
|
||||
"type": "files",
|
||||
"cwd": "src"
|
||||
}
|
||||
```bash
|
||||
sudo pacman -S ripgrep fd
|
||||
```
|
||||
|
||||
### grep
|
||||
macOS:
|
||||
|
||||
用于搜索文件内容。
|
||||
```bash
|
||||
brew install ripgrep fd
|
||||
```
|
||||
|
||||
## 使用
|
||||
|
||||
打开项目后执行:
|
||||
|
||||
```vim
|
||||
:ProjectSearch
|
||||
```
|
||||
|
||||
或者按:
|
||||
|
||||
```text
|
||||
<C-p>
|
||||
```
|
||||
|
||||
第一次使用时,插件会为当前项目创建规则文件。
|
||||
|
||||
编辑那个 JSON 文件,保存后再次打开 `:ProjectSearch` 即可。
|
||||
|
||||
## 常用命令
|
||||
|
||||
```vim
|
||||
:ProjectSearch
|
||||
:ProjectSearch edit
|
||||
:ProjectSearch validate
|
||||
:ProjectSearch reload
|
||||
:ProjectSearch reset
|
||||
:ProjectSearch path
|
||||
:ProjectSearch health
|
||||
```
|
||||
|
||||
## 规则示例
|
||||
|
||||
搜索 React 文件中的 `queryKey`:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "react.query_key",
|
||||
"name": "React: queryKey",
|
||||
"description": "Search TanStack Query queryKey usage.",
|
||||
"type": "grep",
|
||||
"search": "queryKey",
|
||||
"dirs": ["src", "app"],
|
||||
@@ -354,129 +158,36 @@ ln -sf "$(command -v fdfind)" ~/.local/bin/fd
|
||||
}
|
||||
```
|
||||
|
||||
正则 grep 示例:
|
||||
查找 hook 文件如 `hooks/use-user-panel.ts`:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "react.query_hooks",
|
||||
"name": "TanStack Query: hooks",
|
||||
"description": "Search query-related React hooks.",
|
||||
"type": "grep",
|
||||
"regex": true,
|
||||
"search": "useQuery|useMutation|useInfiniteQuery",
|
||||
"dirs": ["src"],
|
||||
"glob": ["*.ts", "*.tsx"]
|
||||
}
|
||||
```
|
||||
|
||||
### files_regex
|
||||
|
||||
用于按文件路径约定查找文件。
|
||||
|
||||
`files_regex` 底层使用 `fd`/`fdfind`,所以正则语法遵循 Rust regex 规则。不支持 look-around。请避免使用 `(?=...)`、`(?!...)`、`(?<=...)` 和 `(?<!...)`。
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "react.hooks.kebab",
|
||||
"name": "Hooks: use-* kebab files",
|
||||
"description": "Find hook files such as hooks/use-claw-history-panel.ts.",
|
||||
"id": "react.hooks",
|
||||
"name": "Hooks: use-* 文件",
|
||||
"type": "files_regex",
|
||||
"regex": "(^|/)hooks/use-[a-z0-9-]+\\.(ts|tsx|js|jsx)$",
|
||||
"dirs": ["src", "app", "packages"],
|
||||
"exclude": ["node_modules", "dist", "build", ".next"]
|
||||
"dirs": ["src", "app", "packages"]
|
||||
}
|
||||
```
|
||||
|
||||
如果要排除测试文件,请用 `exclude`,不要用 lookbehind:
|
||||
打开 `src` 目录下的文件:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "project.service_files",
|
||||
"name": "Service: API layer files",
|
||||
"description": "Find TypeScript files under service directories, excluding test files.",
|
||||
"type": "files_regex",
|
||||
"regex": "service/[^/]+\\.(ts|tsx)$",
|
||||
"dirs": ["src"],
|
||||
"exclude": ["*.test.ts", "*.test.tsx", "*.spec.ts", "*.spec.tsx"]
|
||||
"id": "files.src",
|
||||
"name": "Files: src",
|
||||
"type": "files",
|
||||
"cwd": "src"
|
||||
}
|
||||
```
|
||||
|
||||
不要这样写,因为 `fd` 会拒绝 lookbehind:
|
||||
## 规则类型
|
||||
|
||||
```json
|
||||
{
|
||||
"regex": "service/[^/]+(?<!\\.test|\\.spec)\\.(ts|tsx)$"
|
||||
}
|
||||
```
|
||||
|
||||
如果 `fd` 拒绝某个正则,Project Search 会显示底层 `fd` 错误,而不是只显示空结果。
|
||||
|
||||
## 面板布局
|
||||
|
||||
主面板优先显示可执行搜索规则,管理动作放到底部:
|
||||
|
||||
```text
|
||||
── Common ──
|
||||
Files: src files
|
||||
|
||||
── React ──
|
||||
React: className grep
|
||||
|
||||
── Service ──
|
||||
Service: API layer files files_regex
|
||||
|
||||
── Manage ──
|
||||
Edit current project search rules
|
||||
Reset current project rules from template
|
||||
Validate current project rules
|
||||
Reload current project rules
|
||||
Copy current rules path
|
||||
```
|
||||
|
||||
规则预览是按需生成的,只有预览窗口需要展示某条规则时才会生成内容,所以即使 preset 很多,打开面板也会保持快速。
|
||||
|
||||
## React 项目规则示例
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 1,
|
||||
"meta": {
|
||||
"projectRoot": "/home/lambert/githubRepos/your-project",
|
||||
"template": "react",
|
||||
"createdAt": "2026-05-20T00:00:00Z",
|
||||
"note": "This file is stored outside your project. Edit presets to customize Project Search."
|
||||
},
|
||||
"presets": [
|
||||
{
|
||||
"id": "react.hooks.kebab",
|
||||
"name": "Hooks: use-* kebab files",
|
||||
"description": "Find hook files such as hooks/use-claw-history-panel.ts.",
|
||||
"type": "files_regex",
|
||||
"regex": "(^|/)hooks/use-[a-z0-9-]+\\.(ts|tsx|js|jsx)$",
|
||||
"dirs": ["src", "app", "packages"]
|
||||
},
|
||||
{
|
||||
"id": "react.query_hooks",
|
||||
"name": "TanStack Query: hooks",
|
||||
"description": "Search query-related React hooks.",
|
||||
"type": "grep",
|
||||
"regex": true,
|
||||
"search": "useQuery|useMutation|useInfiniteQuery",
|
||||
"dirs": ["src"],
|
||||
"glob": ["*.ts", "*.tsx"]
|
||||
},
|
||||
{
|
||||
"id": "project.service_files",
|
||||
"name": "Service: API layer files",
|
||||
"description": "Find TypeScript files under service directories, excluding test files.",
|
||||
"type": "files_regex",
|
||||
"regex": "service/[^/]+\\.(ts|tsx)$",
|
||||
"dirs": ["src"],
|
||||
"exclude": ["*.test.ts", "*.test.tsx", "*.spec.ts", "*.spec.tsx"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
| 类型 | 用途 |
|
||||
| --- | --- |
|
||||
| `files` | 在目录下打开文件选择器 |
|
||||
| `grep` | 搜索文件内容 |
|
||||
| `files_regex` | 按路径模式查找文件 |
|
||||
|
||||
## 排错
|
||||
|
||||
@@ -494,9 +205,22 @@ ln -sf "$(command -v fdfind)" ~/.local/bin/fd
|
||||
|
||||
常见问题:
|
||||
|
||||
| 现象 | 检查项 |
|
||||
| 问题 | 检查项 |
|
||||
| --- | --- |
|
||||
| `grep` 规则没有结果 | 确认已安装 `ripgrep`。 |
|
||||
| `files_regex` 规则没有结果 | 确认已安装 `fd`/`fdfind`,并且正则符合 Rust regex 规则。 |
|
||||
| 第一次使用打开 JSON 文件 | 这是预期行为。编辑并保存当前项目规则后,再次打开面板即可。 |
|
||||
| 快捷键没有反应 | 执行 `:verbose nmap <C-p>`,确认是否有冲突,并在 lazy.nvim spec 中换一个键。 |
|
||||
| `grep` 没有结果 | 确认已安装 `ripgrep` |
|
||||
| `files_regex` 没有结果 | 确认已安装 `fd` |
|
||||
| 第一次打开 JSON 文件 | 这是预期行为,编辑保存即可 |
|
||||
| 快捷键没有反应 | 执行 `:verbose nmap <C-p>` 检查冲突 |
|
||||
|
||||
## 更多文档
|
||||
|
||||
- [高级配置](docs/advanced.md)
|
||||
- [格式化说明](docs/formatting.md)
|
||||
- [校验与测试](docs/validation.md)
|
||||
- [更新日志](CHANGELOG.md)
|
||||
|
||||
## 状态
|
||||
|
||||
可以用于日常 LazyVim / Neovim 工作流。
|
||||
|
||||
规则格式在 `v1.0.0` 前可能还会调整。
|
||||
@@ -1,4 +1,4 @@
|
||||
# Configuration
|
||||
# Advanced Configuration
|
||||
|
||||
This document describes the main configuration options and rule schema for `lazy-project-search.nvim`.
|
||||
|
||||
Reference in New Issue
Block a user