Skip to content

Commit f0835c1

Browse files
committed
Neovim: WIP on navigation workflow
1 parent 98cf182 commit f0835c1

10 files changed

+897
-29
lines changed

.config/nvim/lazy-lock.json

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"gitsigns.nvim": { "branch": "main", "commit": "5f808b5e4fef30bd8aca1b803b4e555da07fc412" },
1414
"lazy.nvim": { "branch": "main", "commit": "7c493713bc2cb392706866eeba53aaef6c8e9fc6" },
1515
"lspkind.nvim": { "branch": "master", "commit": "d79a1c3299ad0ef94e255d045bed9fa26025dab6" },
16+
"lspsaga.nvim": { "branch": "main", "commit": "2710a0ad97b5aaff404cd4756c296df454b3f726" },
1617
"lualine.nvim": { "branch": "master", "commit": "2a5bae925481f999263d6f5ed8361baef8df4f83" },
1718
"neodev.nvim": { "branch": "main", "commit": "46aa467dca16cf3dfe27098042402066d2ae242d" },
1819
"neogit": { "branch": "master", "commit": "40038473707c54a846bd11ecaf5933dd45858972" },

.config/nvim/lua/core.lua

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
require("core.leader-key")
22
require("core.config")
3+
require("core.buffers")
34
require("core.autocommands")
45
require("core.globals")

.config/nvim/lua/core/autocommands.lua

+23-12
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
local F = require("core.functions")
2+
13
--------------------------------------------
24
--- Commands ---
35

@@ -13,10 +15,9 @@ vim.cmd [[
1315
--- Autocommands ---
1416

1517
-- Cut off trailing whitespace and trailing blank lines
16-
local core = require("core.functions")
1718
vim.api.nvim_create_autocmd({ "BufWritePre" }, {
1819
pattern = "*",
19-
callback = core.trim_buffer,
20+
callback = F.trim_buffer,
2021
})
2122

2223
-- Highlight on yank
@@ -29,14 +30,24 @@ vim.api.nvim_create_autocmd("TextYankPost", {
2930
})
3031

3132
-- Show message when autosaving
32-
local group = vim.api.nvim_create_augroup('autosave', {})
33-
vim.api.nvim_create_autocmd('User', {
34-
pattern = 'AutoSaveWritePost',
35-
group = group,
36-
callback = function(opts)
37-
if opts.data.saved_buffer ~= nil then
38-
local filename = vim.api.nvim_buf_get_name(opts.data.saved_buffer)
39-
vim.notify("Wrote " .. filename, vim.log.levels.INFO)
40-
end
41-
end,
33+
local autosave_group = vim.api.nvim_create_augroup("autosave", {})
34+
vim.api.nvim_create_autocmd("User", {
35+
pattern = "AutoSaveWritePost",
36+
group = autosave_group,
37+
callback = function(opts)
38+
if opts.data.saved_buffer ~= nil then
39+
local filename = vim.api.nvim_buf_get_name(opts.data.saved_buffer)
40+
vim.notify("Wrote " .. filename, vim.log.levels.INFO)
41+
end
42+
end,
43+
})
44+
45+
-- Create an autocommand for full window buffers
46+
vim.api.nvim_create_autocmd("BufWinEnter", {
47+
-- callback = require("core.buffers").add_buffer
48+
callback = function()
49+
require("core.buffers").add_buffer()
50+
LOG(require("core.buffers").buffers)
51+
end,
52+
desc = "Track all full window buffers visited",
4253
})

.config/nvim/lua/core/buffers.lua

+213
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
local F = require("core.functions")
2+
3+
-- Module for managing buffers, these are used for navigation
4+
5+
local M = {}
6+
7+
-- Buffer table structure:
8+
-- {
9+
-- "Group" = { "buffer1", "buffer2", active_index = 1 }
10+
-- }
11+
M.buffers = {}
12+
13+
M.buffer_default_group = "Other"
14+
15+
M.buffer_matcher = {
16+
-- match = truthy, function() -> thruthy, or string matching buffer filename
17+
-- group = string, function() -> string
18+
{ match = F.find_project_root, group = F.find_project_root },
19+
{ match = true, group = "Other" }, -- default
20+
}
21+
22+
--------------------------------------------
23+
24+
local get_buffer_name = function()
25+
local buf = vim.api.nvim_get_current_buf()
26+
local buffer_name = vim.api.nvim_buf_get_name(buf)
27+
if not buffer_name or buffer_name == "" then return nil end
28+
return buffer_name
29+
end
30+
31+
M.add_buffer = function()
32+
local buffer_name = get_buffer_name()
33+
if not buffer_name then return end
34+
35+
-- Evaluate group
36+
local eval_group = function(config_group)
37+
if not config_group then return M.buffer_default_group end
38+
if type(config_group) == "function" then return config_group() end
39+
return config_group
40+
end
41+
42+
-- Add if buffer does not exist yet
43+
local add = function(config_group)
44+
local group = eval_group(config_group)
45+
if not M.buffers[group] then M.buffers[group] = {} end
46+
for i, buffer in ipairs(M.buffers[group]) do
47+
if buffer == buffer_name then
48+
M.buffers[group]["active_index"] = i
49+
return group, i
50+
end
51+
end
52+
53+
table.insert(M.buffers[group], buffer_name)
54+
local count = #M.buffers[group]
55+
M.buffers[group]["active_index"] = count
56+
57+
return group, count
58+
end
59+
60+
-- Walk matcher configuration
61+
local matcher = M.buffer_matcher or {}
62+
if matcher and type(matcher) == "function" then
63+
matcher = matcher()
64+
end
65+
if #matcher == 0 then add(M.buffer_default_group) end
66+
for _, config in ipairs(M.buffer_matcher) do
67+
if type(config.match) == "function" and config.match() then
68+
return add(config.group)
69+
end
70+
71+
-- Match path's filename
72+
if type(config.match) == "string" and config.match == buffer_name:match("([^/]+)$") then
73+
return add(config.group)
74+
end
75+
76+
if type(config.match) == "boolean" and config.match then
77+
return add(config.group)
78+
end
79+
end
80+
81+
return add(M.buffer_default_group)
82+
end
83+
84+
local get_group_from_buffer = function(buffer_name)
85+
for group, buffers in pairs(M.buffers) do
86+
for i, buffer in ipairs(buffers) do
87+
if buffer == buffer_name then return group, i end
88+
end
89+
end
90+
return nil
91+
end
92+
93+
local buffer_action_in_active_group = function(action, direction)
94+
local buffer_name = get_buffer_name()
95+
if not buffer_name then return end
96+
97+
local group, index = get_group_from_buffer(buffer_name)
98+
if not group then group, index = M.add_buffer() end
99+
100+
local buffers = M.buffers[group]
101+
if #buffers < 2 then return end
102+
103+
-- Determine the other index
104+
local other_index = index + direction
105+
if index == 1 and direction == -1 then
106+
other_index = #buffers
107+
elseif index == #buffers and direction == 1 then
108+
other_index = 1
109+
end
110+
111+
if action == "move" then
112+
for _, buffer in ipairs(vim.api.nvim_list_bufs()) do
113+
-- Remove inactive buffers
114+
if not vim.api.nvim_buf_is_loaded(buffer) then
115+
for i, group_buffer in ipairs(buffers) do
116+
if buffer == group_buffer then
117+
table.remove(buffers, i)
118+
if i > 1 and i <= other_index then
119+
other_index = other_index - 1
120+
end
121+
end
122+
end
123+
124+
goto continue
125+
end
126+
127+
-- Make buffer active
128+
if vim.api.nvim_buf_get_name(buffer) == buffers[other_index] then
129+
vim.api.nvim_set_current_buf(buffer)
130+
buffers.active_index = other_index
131+
break
132+
end
133+
134+
::continue::
135+
end
136+
elseif action == "swap" then
137+
local tmp = buffers[other_index]
138+
buffers[other_index] = buffers[index]
139+
buffers[index] = tmp
140+
end
141+
142+
M.buffers[group] = buffers
143+
end
144+
145+
M.buffer_move_left = function()
146+
buffer_action_in_active_group("move", -1)
147+
end
148+
149+
M.buffer_move_right = function()
150+
buffer_action_in_active_group("move", 1)
151+
end
152+
153+
M.buffer_swap_left = function()
154+
buffer_action_in_active_group("swap", -1)
155+
end
156+
157+
M.buffer_swap_right = function()
158+
buffer_action_in_active_group("swap", 1)
159+
end
160+
161+
--------------------------------------------
162+
-- Group move
163+
164+
local buffer_group_move = function(direction)
165+
local buffer_name = get_buffer_name()
166+
if not buffer_name then return end
167+
168+
-- TODO: How to get groups deterministically?
169+
170+
-- Get active group from the current buffer
171+
172+
-- Check groups bounds
173+
174+
-- Change active group
175+
end
176+
177+
M.buffer_group_move_up = function()
178+
buffer_group_move(-1)
179+
end
180+
181+
M.buffer_group_move_down = function()
182+
buffer_group_move(1)
183+
end
184+
185+
-- TODO: functions that can
186+
-- v Navigate buffer left
187+
-- v Navigate buffer right
188+
-- - Navigate group up (use active_index when swapping)
189+
-- - Navigate group down
190+
-- v Move buffer left
191+
-- v Move buffer right
192+
-- - Remove buffer from currently active group (decrease active_index)
193+
194+
return M
195+
196+
197+
-- (cond
198+
-- ((string-equal "*" (substring (buffer-name) 0 1)) "Emacs")
199+
-- ((or (memq major-mode '(magit-process-mode
200+
-- magit-status-mode
201+
-- magit-diff-mode
202+
-- magit-log-mode
203+
-- magit-file-mode
204+
-- magit-blob-mode
205+
-- magit-blame-mode))
206+
-- (string= (buffer-name) "COMMIT_EDITMSG")) "Magit")
207+
-- ((project-current) (dot/project-project-name))
208+
-- ((memq major-mode '(org-mode
209+
-- emacs-lisp-mode)) "Org Mode")
210+
-- ((derived-mode-p 'dired-mode) "Dired")
211+
-- ((derived-mode-p 'prog-mode
212+
-- 'text-mode) "Editing")
213+
-- (t "Other")))))

.config/nvim/lua/core/functions.lua

+7-4
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,14 @@ M.find_project_root = function()
3232

3333
local directory = current_directory
3434
while directory ~= "/" do
35-
local git_directory = directory .. "/.git"
36-
local project_file = directory .. "/.project"
35+
local git_path = vim.loop.fs_stat(directory .. "/.git")
36+
if git_path then
37+
return directory:gsub("/$", "") -- remove trailing slash
38+
end
3739

38-
if vim.fn.isdirectory(git_directory) == 1 or vim.fn.filereadable(project_file) == 1 then
39-
return directory
40+
local project_file = vim.loop.fs_stat(directory .. "/.project")
41+
if project_file and project_file.type == "file" then
42+
return directory:gsub("/$", "") -- remove trailing slash
4043
end
4144

4245
directory = vim.fn.fnamemodify(directory, ":h")

.config/nvim/lua/development.lua

+38
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,16 @@ return {
6666
{ -- https://github.com/neovim/nvim-lspconfig
6767
"neovim/nvim-lspconfig",
6868
dependencies = {
69+
-- Improve the built-in LSP UI
70+
"nvimdev/lspsaga.nvim",
6971
-- Additional lua configuration, makes Nvim stuff amazing!
7072
"folke/neodev.nvim",
7173
-- C# "Goto Definition" with decompilation support
7274
"Hoffs/omnisharp-extended-lsp.nvim",
7375
},
7476
config = function()
7577
-- Setup neovim Lua configuration
78+
require("lspsaga").setup() -- ?? does this do anything with doc hover
7679
require("neodev").setup()
7780

7881
-- Vim process
@@ -103,6 +106,39 @@ return {
103106
["textDocument/definition"] = require('omnisharp_extended').handler,
104107
},
105108
},
109+
ts_ls = {
110+
init_options = {
111+
plugins = {
112+
{
113+
name = '@vue/typescript-plugin',
114+
location = '/home/rick/.cache/.bun/install/global/node_modules/@vue/language-server',
115+
languages = { 'vue' },
116+
},
117+
},
118+
},
119+
filetypes = { 'javascript', 'javascriptreact', 'javascript.jsx', 'typescript', 'typescriptreact', 'typescript.tsx', 'vue', },
120+
-- filetypes = { 'typescript', 'javascript', 'javascriptreact', 'typescriptreact', 'vue' },
121+
-- requires: bun install -g typescript-language-server
122+
-- TODO: Update which-key config, maybe other packages
123+
-- Sources:
124+
-- https://github.com/vuejs/language-tools?tab=readme-ov-file#hybrid-mode-configuration-requires-vuelanguage-server-version-200
125+
-- https://github.com/neovim/nvim-lspconfig/blob/master/lua/lspconfig/configs/ts_ls.lua#L4
126+
},
127+
volar = {
128+
-- init_options = {
129+
-- vue = {
130+
-- hybridMode = false,
131+
-- },
132+
-- },
133+
},
134+
-- volar = {
135+
-- -- init_options = {
136+
-- -- typescript = {
137+
-- -- serverPath = '/home/rick/.cache/.bun/install/global/node_modules/typescript/lib//tsserverlibrary.js'
138+
-- -- }
139+
-- -- },
140+
-- -- filetypes = {'typescript', 'javascript', 'javascriptreact', 'typescriptreact', 'vue', 'json'}
141+
-- },
106142
}
107143

108144
-- nvim-cmp supports additional completion capabilities, so broadcast that to servers
@@ -114,6 +150,8 @@ return {
114150
capabilities = capabilities,
115151
on_attach = require("keybinds").lspconfig_on_attach,
116152
})
153+
-- P(server)
154+
-- P(opts)
117155
require("lspconfig")[server].setup(opts)
118156
end
119157
end,

.config/nvim/lua/keybind-functions.lua

+7-2
Original file line numberDiff line numberDiff line change
@@ -297,8 +297,13 @@ M.vc_select_repo = function()
297297
end
298298

299299
M.vc_status = function()
300-
-- Open the repository of the current file
301-
require("neogit").open({ cwd = "%:p:h" })
300+
if F.find_project_root() then
301+
-- Open the repository of the current file
302+
require("neogit").open({ cwd = "%:p:h" })
303+
else
304+
-- Pick a project to open
305+
M.vc_select_repo()
306+
end
302307
end
303308

304309
return M

.config/nvim/lua/keybinds.lua

+3
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ M.lspconfig_on_attach = function(_, bufnr)
160160
nnoremap("<leader>lf", F.lsp_format_buffer, "Format buffer")
161161
nnoremap("<leader>lr", vim.lsp.buf.rename, "Rename")
162162

163+
nnoremap("<leader>ld", "<cmd>Lspsaga hover_doc<CR>", "Show documentation")
164+
-- vim.keymap.set("n", "<leader>ld", "<cmd>Lspsaga hover_doc<CR>", { desc = "Show documentation" })
165+
163166
F.wk("<leader>lg", "goto", bufnr)
164167
nnoremap("<leader>lga", builtin.lsp_dynamic_workspace_symbols, "Workspace symbols")
165168
nnoremap("<leader>lgd", vim.lsp.buf.declaration, "Declaration")

0 commit comments

Comments
 (0)