Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 3 additions & 1 deletion lua/opencode/ui/completion/files.lua
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ local function create_file_item(file, suffix, priority)
local dir = vim.fn.fnamemodify(file, ':h')
local file_path = dir == '.' and filename or dir .. '/' .. filename
local detail = dir == '.' and filename or dir .. '/' .. filename
local full_path = vim.fn.fnamemodify(file, ':p')
-- Build absolute path without resolving symlinks so that files inside
-- symlinked directories within cwd pass the is_path_in_cwd check.
local full_path = file:sub(1, 1) == '/' and file or (vim.fn.getcwd() .. '/' .. file)
Comment thread
sudo-tee marked this conversation as resolved.
local display_label = file_path

local file_config = config.ui.completion.file_sources
Expand Down
8 changes: 8 additions & 0 deletions lua/opencode/util.lua
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,14 @@ end

function M.is_path_in_cwd(path)
local cwd = vim.fn.getcwd()
-- For relative paths, build the logical absolute path without resolving symlinks
-- so that files inside symlinked directories within cwd are accepted.
if path:sub(1, 1) ~= '/' then
local logical = vim.fn.simplify(cwd .. '/' .. path)
if logical:sub(1, #cwd) == cwd then
return true
end
end
local abs_path = vim.fn.fnamemodify(path, ':p')
return abs_path:sub(1, #cwd) == cwd
Comment thread
sudo-tee marked this conversation as resolved.
Outdated
end
Expand Down
38 changes: 38 additions & 0 deletions tests/unit/util_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -378,3 +378,41 @@ describe('util.parse_quick_context_args', function()
end)
end
end)

describe('util.is_path_in_cwd', function()
local original_getcwd
local test_cwd = '/tmp/test_project'

before_each(function()
original_getcwd = vim.fn.getcwd
vim.fn.getcwd = function()
return test_cwd
end
end)

after_each(function()
vim.fn.getcwd = original_getcwd
end)

it('accepts a relative path inside cwd', function()
assert.is_true(util.is_path_in_cwd('src/foo.lua'))
end)

it('accepts an absolute path inside cwd', function()
assert.is_true(util.is_path_in_cwd(test_cwd .. '/src/foo.lua'))
end)

it('rejects an absolute path outside cwd', function()
assert.is_false(util.is_path_in_cwd('/tmp/outside/foo.lua'))
end)

it('rejects a relative path that escapes cwd via ..', function()
assert.is_false(util.is_path_in_cwd('../outside/foo.lua'))
end)

it('accepts a relative path through a symlinked directory in cwd', function()
-- Simulate the symlink case: relative path stays logical (not resolved)
-- e.g. linked_folder -> /tmp/external, linked_folder/test.txt is valid
assert.is_true(util.is_path_in_cwd('linked_folder/test.txt'))
end)
Comment thread
sudo-tee marked this conversation as resolved.
end)
Loading