Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ cli/.*.bun-build
cli/node_modules/
.DS_Store
*.log

node_modules/
43 changes: 30 additions & 13 deletions lua/tau/context_picker.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,30 @@ local _open = false

vim.api.nvim_set_hl(0, "TauContextCursorLine", { link = "CursorLine" })

local function add_candidate(candidates, seen, path)
local abs = vim.fn.fnamemodify(path, ":p")
if seen[abs] or vim.fn.isdirectory(abs) ~= 0 or vim.fn.filereadable(abs) == 0 then return end

seen[abs] = true
candidates[#candidates + 1] = { abs = abs, rel = vim.fn.fnamemodify(abs, ":~:.") }
end

--- List cwd files, respecting git ignore rules when cwd is inside a Git repo.
--- @return string[]
local function list_cwd_files()
local cwd = vim.loop.cwd() or vim.fn.getcwd()

if vim.fn.executable("git") == 1 then
local files = vim.fn.systemlist({ "git", "-C", cwd, "ls-files", "--cached", "--others", "--exclude-standard", "--", "." })
if vim.v.shell_error == 0 then
return files
end
end

-- Fallback for non-Git directories. This does not understand .gitignore.
return vim.fn.glob("**/*", false, true)
end

--- Collect candidate file paths, deduplicated and sorted.
--- @return {abs: string, rel: string}[]
local function get_candidates()
Expand All @@ -20,23 +44,16 @@ local function get_candidates()
if vim.bo[buf].buflisted and vim.bo[buf].buftype == "" then
local name = vim.api.nvim_buf_get_name(buf)
if name ~= "" then
local abs = vim.fn.fnamemodify(name, ":p")
if not seen[abs] then
seen[abs] = true
candidates[#candidates + 1] = { abs = abs, rel = vim.fn.fnamemodify(abs, ":~:.") }
end
add_candidate(candidates, seen, name)
end
end
end

-- All files in the working directory
for _, rel_path in ipairs(vim.fn.glob("**/*", false, true)) do
if vim.fn.isdirectory(rel_path) == 0 then
local abs = vim.fn.fnamemodify(rel_path, ":p")
if not seen[abs] then
seen[abs] = true
candidates[#candidates + 1] = { abs = abs, rel = vim.fn.fnamemodify(abs, ":~:.") }
end
-- Files in cwd. In Git repos this uses `git ls-files --exclude-standard`,
-- so .gitignore/.git/info/exclude/global excludes are honored.
for _, rel_path in ipairs(list_cwd_files()) do
if rel_path ~= "" then
add_candidate(candidates, seen, rel_path)
end
end

Expand Down
32 changes: 32 additions & 0 deletions tests/context_picker_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ local function find_map(buf, lhs)
return nil
end

local function assert_no_line_contains(lines, needle, message)
for _, line in ipairs(lines) do
if line:find(needle, 1, true) then
fail((message or "unexpected line") .. ": " .. line)
end
end
end

local start_dir = vim.loop.cwd()
local temp_dir = vim.fn.tempname()
vim.fn.mkdir(temp_dir, "p")
Expand Down Expand Up @@ -83,6 +91,30 @@ local ok, err = xpcall(function()

assert_truthy(not context_files.contains_abs(current_file), "expected locked current file not to be toggled into context")
assert_equal(vim.api.nvim_buf_get_lines(buf, 1, 2, false)[1], " ◎ b.txt", "expected locked current-file row to remain unchanged")

local q_map = find_map(buf, "q")
assert_truthy(q_map, "expected buffer-local q mapping")
q_map.callback()

local git_dir = vim.fn.tempname()
vim.fn.mkdir(git_dir .. "/node_modules/pkg", "p")
vim.fn.writefile({ "node_modules/" }, git_dir .. "/.gitignore")
vim.fn.writefile({ "visible" }, git_dir .. "/visible.txt")
vim.fn.writefile({ "ignored" }, git_dir .. "/node_modules/pkg/index.js")

vim.cmd("cd " .. vim.fn.fnameescape(git_dir))
vim.fn.system({ "git", "init", "-q" })
assert_equal(vim.v.shell_error, 0, "expected git init to succeed")

require("tau.context_picker").open()
local git_buf = vim.api.nvim_get_current_buf()
local lines = vim.api.nvim_buf_get_lines(git_buf, 0, -1, false)

assert_truthy(vim.tbl_contains(lines, " .gitignore"), "expected .gitignore to be listed")
assert_truthy(vim.tbl_contains(lines, " visible.txt"), "expected visible untracked file to be listed")
assert_no_line_contains(lines, "node_modules", "expected .gitignore'd node_modules to be excluded")

vim.fn.delete(git_dir, "rf")
end, debug.traceback)

vim.cmd("cd " .. vim.fn.fnameescape(start_dir))
Expand Down
Loading