Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Wrokspace Folders + embedded projects #178

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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 Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
test:
nvim --headless --noplugin -u lua/tests/minimal.vim -c "PlenaryBustedDirectory lua/tests/ {minimal_init = 'lua/tests/minimal.vim'}"
64 changes: 59 additions & 5 deletions lua/project_nvim/project.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,64 @@ local M = {}
M.attached_lsp = false
M.last_project = nil

---@alias buf_name string this is the name of the buffer (the path/filename that is opened in the buffer)
---@alias buf_file_location string this is the buf_name minus the filename (just the path)

--- regex is relatively expensive, so store buf_file_path in map
---@type table<buf_name, buf_file_location>
local buf_name_to_file_path_map = {}

vim.api.nvim_create_autocmd("BufDelete", {
pattern = "*",
callback = function()
local buf_name = vim.api.nvim_buf_get_name(0)
buf_name_to_file_path_map[buf_name] = nil
end,
})

---@param client vim.lsp.Client
---@param buf_name buf_name
function M._lsp_get_buf_root(client, buf_name)
local buf_file_path = buf_name_to_file_path_map[buf_name]
if not buf_file_path then
-- strip off filename
buf_file_path = buf_name:match('(.*)/.*$')
buf_name_to_file_path_map[buf_name] = buf_file_path
else
end

local root_dir
-- LSP clients can have multiple workspace folders
if client.workspace_folders then
for _, workspace_folder in pairs(client.workspace_folders) do
local folder_name = vim.uri_to_fname(workspace_folder.uri)
if folder_name and vim.startswith(buf_file_path, folder_name) then
if #folder_name == #buf_file_path then
return folder_name
end
if not root_dir then
root_dir = folder_name
elseif #folder_name > #root_dir then
root_dir = folder_name
end
end
end
end

if root_dir then
return root_dir
end

-- Fall back to root_dir
return client.config.root_dir
end

function M.find_lsp_root()
-- Get lsp client for current buffer
-- Returns nil or string
local buf_ft = vim.api.nvim_buf_get_option(0, "filetype")
local clients = vim.lsp.buf_get_clients()
local buf_ft = vim.api.nvim_get_option_value('filetype', { buf = 0 })
local buf_name = vim.api.nvim_buf_get_name(0)
local clients = vim.lsp.get_clients({ bufnr = 0 })
if next(clients) == nil then
return nil
end
Expand All @@ -22,7 +75,8 @@ function M.find_lsp_root()
local filetypes = client.config.filetypes
if filetypes and vim.tbl_contains(filetypes, buf_ft) then
if not vim.tbl_contains(config.options.ignore_lsp, client.name) then
return client.config.root_dir, client.name
local lsp_root = M._lsp_get_buf_root(client, buf_name)
return lsp_root, client.name
end
end
end
Expand Down Expand Up @@ -214,7 +268,7 @@ function M.get_project_root()
end

function M.is_file()
local buf_type = vim.api.nvim_buf_get_option(0, "buftype")
local buf_type = vim.api.nvim_get_option_value('buftype', { buf = 0 })

local whitelisted_buf_type = { "", "acwrite" }
local is_in_whitelist = false
Expand Down Expand Up @@ -270,7 +324,7 @@ function M.init()
]])

autocmds[#autocmds + 1] =
'autocmd VimLeavePre * lua require("project_nvim.utils.history").write_projects_to_history()'
'autocmd VimLeavePre * lua require("project_nvim.utils.history").write_projects_to_history()'

vim.cmd([[augroup project_nvim
au!
Expand Down
26 changes: 26 additions & 0 deletions lua/tests/minimal.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
set rtp +=.
set rtp +=../plenary.nvim/
set rtp +=../nvim-treesitter
set rtp +=../nvim-lspconfig/

runtime! plugin/plenary.vim
runtime! plugin/nvim-treesitter.vim
runtime! plugin/playground.vim
runtime! plugin/nvim-lspconfig.vim

set noswapfile
set nobackup

filetype indent off
set nowritebackup
set noautoindent
set nocindent
set nosmartindent
set indentexpr=
set shada="NONE"

lua << EOF
_G.test_rename = true
_G.test_close = true
require("plenary/busted")
EOF
34 changes: 34 additions & 0 deletions lua/tests/project_lsp_get_buf_root_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
local eq = assert.are.same
local busted = require('plenary/busted')

local lsp_get_buf_root = require("project_nvim.project")._lsp_get_buf_root

describe('M._get_buf_root()):', function()
it("testing M._get_buf_root() returns correct buf_root for embedded projects", function()
local outter_project = "/Users/kkrime/outter_project"
local inner_project = "/Users/kkrime/outter_project/inner_project"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unsure if it really matters, but it seems some more universal paths like /tmp/outer_project could work better

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It really doesn't make any difference, you can change it you feel strongly about it, no problem with me


local client = {}
client["workspace_folders"] = { { uri = "file://" .. outter_project }, { uri = "file://" .. inner_project } }

-- file in project root
local buf_name = outter_project .. "/main.file"
local res = lsp_get_buf_root(client, buf_name)
eq(res, outter_project)

-- file in project root
buf_name = inner_project .. "/main.file"
res = lsp_get_buf_root(client, buf_name)
eq(res, inner_project)

-- file deep inside the project
buf_name = outter_project .. "/folder/folder/helper.file"
res = lsp_get_buf_root(client, buf_name)
eq(res, outter_project)

-- file deep inside the project
buf_name = inner_project .. "/folder/folder/helper.file"
res = lsp_get_buf_root(client, buf_name)
eq(res, inner_project)
end)
end)