Skip to content

Commit 3353153

Browse files
authored
Merge pull request #35 from AuroBreeze/dev
Dev
2 parents c78b1a9 + 2765c8e commit 3353153

File tree

3 files changed

+194
-31
lines changed

3 files changed

+194
-31
lines changed

Release.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,50 @@
11
# Quick-c Release Notes
22

3+
## v1.6.1 (2025-12-11)
4+
5+
### 新增
6+
- 目录/项目扫描异步化(非阻塞):`QuickCCompileDBGenDir``QuickCCompileDBGenProject` 均改为异步分步遍历,避免卡主线程。
7+
- 进度提示(可配置节流):扫描过程中周期性输出进度(文件/目录计数),默认每约 1200ms 一次。
8+
- 配置项:
9+
- `compile_commands.ignore_dirs`(默认 `{ '.git','node_modules','.cache' }`
10+
- `compile_commands.include_hidden`(默认 `true`,遍历以“.”开头的目录)
11+
- `compile_commands.progress_throttle_ms`(默认 `1200`
12+
- `compile_commands.max_depth`(默认 `4``nil` 表示不限制)
13+
14+
### 改进
15+
- 统一体验:项目与目录两条路径使用相同异步扫描器与过滤策略,行为一致。
16+
- 可控深度:`max_depth` 限制递归层数(根为 0),大项目扫描更可控。
17+
- 按上下文写入:当 `outdir='source'` 时,生成位置按上下文决定:
18+
- 单文件:写到“当前文件目录/compile_commands.json”
19+
- 目录扫描:写到“所选目录/compile_commands.json”
20+
- 全项目扫描:写到“项目根/compile_commands.json”
21+
22+
### 使用建议
23+
1) 扫描全项目(异步):`:QuickCCompileDBGenProject`
24+
2) 扫描目录(异步):`:QuickCCompileDBGenDir [dir]`(支持含空格路径与目录补全)
25+
3) 配置示例:
26+
```lua
27+
require('quick-c').setup({
28+
compile_commands = {
29+
ignore_dirs = { '.git', '.cache', 'build', '.venv' },
30+
include_hidden = false,
31+
progress_throttle_ms = 1200,
32+
max_depth = 4,
33+
},
34+
})
35+
```
36+
37+
### 验证建议
38+
1) 设置 `include_hidden=false`,确认 `.hidden/.deps` 等目录被跳过;开启后应被纳入。
39+
2) 设置 `max_depth=2`,确认仅扫描到二级子目录;提高后包含更深层文件。
40+
3) 调整 `progress_throttle_ms`(如 300/1200)观察进度提示频率变化。
41+
42+
### 兼容性
43+
- 非破坏性变更;仅目录/项目扫描路径行为改进与增强。
44+
45+
### 迁移指南
46+
- 无需迁移;如需更细过滤,请在 `ignore_dirs` 中补充目录名。
47+
348
## v1.6.0 (2025-12-04)
449

550
### 新增

lua/quick-c/cc.lua

Lines changed: 145 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,88 @@ local function copy_file(src, dst)
8383
return vim.fn.writefile(data, dst) == 0
8484
end
8585

86+
local function collect_sources_recursive(root, ignore_set)
87+
local uv = vim.loop
88+
local results = {}
89+
local function scan(dir)
90+
local fs = uv.fs_scandir(dir)
91+
if not fs then return end
92+
while true do
93+
local name, t = uv.fs_scandir_next(fs)
94+
if not name then break end
95+
local path = dir .. '/' .. name
96+
if t == 'directory' then
97+
if not ignore_set[name] then
98+
scan(path)
99+
end
100+
else
101+
local ext = (name:match('%.([%w]+)$') or ''):lower()
102+
if ext == 'c' or ext == 'cpp' or ext == 'cc' or ext == 'cxx' then
103+
table.insert(results, path)
104+
end
105+
end
106+
end
107+
end
108+
scan(root)
109+
return results
110+
end
111+
112+
local function collect_sources_async(root, ignore_set, include_hidden, max_depth, on_progress, on_done)
113+
local uv = vim.loop
114+
local queue = { { root, 0 } }
115+
local results = {}
116+
local scanners = {}
117+
local dir_count, file_count = 0, 0
118+
local function step()
119+
local budget = 600
120+
while budget > 0 do
121+
local item = queue[#queue]
122+
local current, depth = nil, 0
123+
if item then current, depth = item[1], item[2] or 0 end
124+
if not current then
125+
on_done(results)
126+
return
127+
end
128+
local fs = scanners[current]
129+
if not fs then
130+
fs = uv.fs_scandir(current)
131+
scanners[current] = fs or false
132+
if not fs then
133+
queue[#queue] = nil
134+
end
135+
else
136+
local name, t = uv.fs_scandir_next(fs)
137+
if not name then
138+
queue[#queue] = nil
139+
else
140+
local path = current .. '/' .. name
141+
if t == 'directory' then
142+
if not ignore_set[name] then
143+
if include_hidden or not name:match('^%.') then
144+
if (not max_depth) or (depth + 1 <= max_depth) then
145+
queue[#queue + 1] = { path, depth + 1 }
146+
dir_count = dir_count + 1
147+
end
148+
end
149+
end
150+
else
151+
local ext = (name:match('%.([%w]+)$') or ''):lower()
152+
if ext == 'c' or ext == 'cpp' or ext == 'cc' or ext == 'cxx' then
153+
results[#results + 1] = path
154+
file_count = file_count + 1
155+
end
156+
end
157+
budget = budget - 1
158+
end
159+
end
160+
if budget <= 0 then break end
161+
end
162+
if on_progress then on_progress(file_count, dir_count) end
163+
vim.defer_fn(step, 1)
164+
end
165+
step()
166+
end
167+
86168
function CC.generate(config, notify)
87169
local ft = vim.bo.filetype
88170
if ft ~= 'c' and ft ~= 'cpp' then
@@ -239,23 +321,37 @@ end
239321
-- Non-CMake: scan project for sources and generate
240322
function CC.generate_for_project(config, notify)
241323
local cwd = vim.fn.getcwd()
242-
local patterns = { '**/*.c', '**/*.cpp', '**/*.cc', '**/*.cxx' }
243-
local seen, sources = {}, {}
244-
for _, pat in ipairs(patterns) do
245-
local list = vim.fn.glob(pat, true, true)
246-
for _, f in ipairs(list) do
247-
local p = vim.fn.fnamemodify(f, ':p')
248-
if vim.fn.filereadable(p) == 1 and not seen[p] then
249-
seen[p] = true
250-
table.insert(sources, p)
324+
local ccfg = config.compile_commands or {}
325+
local ignores = {}
326+
for _, v in ipairs(ccfg.ignore_dirs or { '.git', 'node_modules', '.cache' }) do ignores[v] = true end
327+
local include_hidden = ccfg.include_hidden ~= false
328+
local max_depth = ccfg.max_depth
329+
local throttle = tonumber(ccfg.progress_throttle_ms) or 600
330+
local last = 0
331+
collect_sources_async(cwd, ignores, include_hidden, max_depth, function(files, dirs)
332+
local uv = vim.loop
333+
if uv and uv.now then
334+
local now = uv.now()
335+
if now - (last or 0) >= throttle then
336+
notify.info(string.format('Scanning project: %d files, %d dirs', files or 0, dirs or 0))
337+
last = now
251338
end
252339
end
253-
end
254-
if #sources == 0 then
255-
notify.warn 'No C/C++ sources found under project root'
256-
return
257-
end
258-
CC.generate_for_sources(config, notify, sources)
340+
end, function(list)
341+
local seen, sources = {}, {}
342+
for _, p in ipairs(list) do
343+
local abs = vim.fn.fnamemodify(p, ':p')
344+
if vim.fn.filereadable(abs) == 1 and not seen[abs] then
345+
seen[abs] = true
346+
sources[#sources + 1] = abs
347+
end
348+
end
349+
if #sources == 0 then
350+
notify.warn 'No C/C++ sources found under project root'
351+
return
352+
end
353+
CC.generate_for_sources(config, notify, sources)
354+
end)
259355
end
260356

261357
-- Non-CMake: generate for all sources under a specified directory
@@ -270,24 +366,42 @@ function CC.generate_for_dir(config, notify, dir)
270366
notify.err('Not a directory: ' .. tostring(dir))
271367
return
272368
end
273-
local patterns = { '**/*.c', '**/*.cpp', '**/*.cc', '**/*.cxx' }
274-
local seen, sources = {}, {}
275-
for _, pat in ipairs(patterns) do
276-
-- Use globpath to search inside the specified directory recursively
277-
local list = vim.fn.globpath(dir, pat, true, true)
278-
for _, f in ipairs(list) do
279-
local p = vim.fn.fnamemodify(f, ':p')
280-
if vim.fn.filereadable(p) == 1 and not seen[p] then
281-
seen[p] = true
282-
table.insert(sources, p)
369+
local ccfg = config.compile_commands or {}
370+
local ignores = {}
371+
for _, v in ipairs(ccfg.ignore_dirs or { '.git', 'node_modules', '.cache' }) do ignores[v] = true end
372+
local include_hidden = ccfg.include_hidden ~= false
373+
local max_depth = ccfg.max_depth
374+
local throttle = tonumber(ccfg.progress_throttle_ms) or 600
375+
local last = 0
376+
collect_sources_async(dir, ignores, include_hidden, max_depth, function(files, dirs)
377+
local uvn = vim.loop
378+
if uvn and uvn.now then
379+
local now = uvn.now()
380+
if now - (last or 0) >= throttle then
381+
notify.info(string.format('Scanning dir: %d files, %d dirs', files or 0, dirs or 0))
382+
last = now
283383
end
284384
end
285-
end
286-
if #sources == 0 then
287-
notify.warn('No C/C++ sources found under: ' .. dir)
288-
return
289-
end
290-
CC.generate_for_sources(config, notify, sources)
385+
end, function(list)
386+
local seen, sources = {}, {}
387+
for _, p in ipairs(list) do
388+
local abs = vim.fn.fnamemodify(p, ':p')
389+
if vim.fn.filereadable(abs) == 1 and not seen[abs] then
390+
seen[abs] = true
391+
sources[#sources + 1] = abs
392+
end
393+
end
394+
if #sources == 0 then
395+
notify.warn('No C/C++ sources found under: ' .. dir)
396+
return
397+
end
398+
local cfg = vim.tbl_deep_extend('force', {}, config)
399+
cfg.compile_commands = cfg.compile_commands or {}
400+
if cfg.compile_commands.outdir == 'source' then
401+
cfg.compile_commands.outdir = dir
402+
end
403+
CC.generate_for_sources(cfg, notify, sources)
404+
end)
291405
end
292406

293407
return CC

lua/quick-c/config.lua

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ C.defaults = {
6666
-- 相对路径 : 相对 :pwd
6767
-- 绝对路径 : 例如 'C:/proj/compile_commands'
6868
outdir = 'source',
69+
ignore_dirs = { '.git', 'node_modules', '.cache' },
70+
include_hidden = true,
71+
progress_throttle_ms = 1200,
72+
max_depth = 4,
6973
-- 当 mode = 'use' 时,从此路径复制 compile_commands.json
7074
use_path = nil,
7175
},

0 commit comments

Comments
 (0)