diff --git a/lua/config/autocmds.lua b/lua/config/autocmds.lua index 7012d8d..5afadc7 100644 --- a/lua/config/autocmds.lua +++ b/lua/config/autocmds.lua @@ -152,3 +152,20 @@ vim.api.nvim_create_autocmd('FileType', { vim.opt_local.formatoptions:remove({ 'o' }) end, }) + +-- Run async commands with output to split +vim.api.nvim_create_user_command('RunAsync', function(async_opts) + -- Save current buffer first + vim.cmd('w') + + -- Construct the full command + local cmd = table.concat(async_opts.fargs, ' ') + + -- Open a horizontal split with the terminal running the command + vim.cmd('belowright split | terminal ' .. cmd) + + -- Optional: return focus to original window + vim.cmd('wincmd p') +end, { + nargs = '+', -- Require at least one argument +}) diff --git a/lua/config/early.lua b/lua/config/early.lua index 8a7db3e..fe88901 100644 --- a/lua/config/early.lua +++ b/lua/config/early.lua @@ -2,6 +2,12 @@ -- │ Early interventions │ -- ╰─────────────────────────────────────────────────────────╯ +-- Execute project-specific configuration if it exists +local project_config = vim.fn.getcwd() .. '/.nvim.lua' +if vim.fn.filereadable(project_config) == 1 then + dofile(project_config) +end + -- Address vim.hl bug impacting `:Inspect` command ---@see https://github.com/neovim/neovim/issues/31675 vim.hl = vim.highlight diff --git a/lua/config/lazy.lua b/lua/config/lazy.lua index 4227a57..7578dfa 100644 --- a/lua/config/lazy.lua +++ b/lua/config/lazy.lua @@ -22,6 +22,7 @@ vim.opt.rtp:prepend(vim.env.LAZY or lazypath) local plugin_specs = { { -- LazyVim 'LazyVim/LazyVim', + -- dev = true, priority = 900, opts = require('data.types').lazyvim.opts, }, @@ -35,19 +36,9 @@ local plugin_specs = { { import = 'plugins' }, -- General Plugins } --- Automatically import all subdirectories of `lua/plugins` -local plugin_dirs = vim.fn.glob('~/.config/nvim/lua/plugins/*', true, true) -for _, dir in ipairs(plugin_dirs) do - if vim.fn.isdirectory(dir) == 1 then - table.insert( -- Add directory to the plugin import table - plugin_specs, - { import = 'plugins.' .. vim.fn.fnamemodify(dir, ':t') } - ) - end -end +-- ━━━━━━━━━━━━━━━━━━━━━━━━━ Lazy Configuration ━━━━━━━━━━━━━━━━━━━━━━ --- Initialize Lazy plugin manager -require('lazy').setup({ +local lazy_spec = { spec = plugin_specs, rocks = { hererocks = vim.g.use_luarocks, @@ -100,4 +91,22 @@ require('lazy').setup({ border = 'rounded', title = ' Plugin Manager ', }, -}) +} + +-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━ Import Plugins ━━━━━━━━━━━━━━━━━━━━━━━━ + +-- Automatically import all subdirectories of `lua/plugins` +local plugin_dirs = vim.fn.glob('~/.config/nvim/lua/plugins/*', true, true) +for _, dir in ipairs(plugin_dirs) do + if vim.fn.isdirectory(dir) == 1 then + table.insert( -- Add directory to the plugin import table + plugin_specs, + { import = 'plugins.' .. vim.fn.fnamemodify(dir, ':t') } + ) + end +end + +-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Setup Lazy ━━━━━━━━━━━━━━━━━━━━━━━━━━ + +-- Initialize Lazy plugin manager +require('lazy').setup(lazy_spec) diff --git a/lua/config/neovide.lua b/lua/config/neovide.lua index 75456f3..14810c2 100644 --- a/lua/config/neovide.lua +++ b/lua/config/neovide.lua @@ -8,7 +8,7 @@ vim.opt.guifont = 'Iosevka Rootiest V2:#e-subpixelantialias:h12' -- refresh rate and translucency vim.g.neovide_refresh_rate = 120 -vim.g.neovide_transparency = 0.85 +vim.g.neovide_opacity = 0.85 vim.g.neovide_window_blurred = true vim.g.neovide_floating_blur_amount_x = 2.0 vim.g.neovide_floating_blur_amount_y = 2.0 diff --git a/lua/config/options.lua b/lua/config/options.lua index 4662ac7..d5a2dd8 100644 --- a/lua/config/options.lua +++ b/lua/config/options.lua @@ -192,7 +192,7 @@ vim.g.statusline = "lualine" ---@type string Options: [status -- Click git components on statusline to open LazyGit vim.g.statusline_clickable_git = true ---@type boolean Options: -- Show wakatime stats on statusline -vim.g.stats_wakatime = true ---@type boolean Options: +vim.g.stats_wakatime = false ---@type boolean Options: -- Show music stats on statusline vim.g.stats_music = true ---@type boolean Options: -- Ignored player sources for music stats diff --git a/lua/config/overrides.lua b/lua/config/overrides.lua index 113e04a..acff662 100644 --- a/lua/config/overrides.lua +++ b/lua/config/overrides.lua @@ -107,6 +107,13 @@ vim.keymap.set( { noremap = true, desc = 'Replay last register' } ) +-- Duplicate and comment lines +vim.keymap.set('n', 'ycc', function() + vim.cmd('normal! ' .. vim.v.count1 .. 'yy') + vim.cmd('normal ' .. vim.v.count1 .. 'gcc') + vim.cmd("normal! ']$p") +end, { desc = 'Duplicate and comment lines' }) + --------------------------------------------------------------------------- -- ╓─────────────────────────────────────────────────────────╖ -- ║ Scroll half a screen with and ║ @@ -149,3 +156,27 @@ vim.keymap.set('n', '', function() scroll('up') end, { silent = true }) --------------------------------------------------------------------------- + +-- Dump floating window info to file +vim.keymap.set( + 'n', + 'fd', + require('data.func').dump_floating_window_info, + { desc = 'Dump floating window info to file' } +) + +--------------------------------------------------------------------------- +-- Obsidian Project Configuration: +local function run_obsidian_config() + -- Reduce conceallevel for Obsidian UI + vim.o.conceallevel = 2 + vim.cmd('Neominimap off') +end + +vim.api.nvim_create_augroup('obsidian_config', { clear = true }) +vim.api.nvim_create_autocmd({ 'BufNewFile', 'BufRead', 'BufEnter' }, { + group = 'obsidian_config', + pattern = vim.fn.expand('~') .. '/vaults/Rootiest Notes/**', + callback = run_obsidian_config, +}) +--------------------------------------------------------------------------- diff --git a/lua/data/func.lua b/lua/data/func.lua index d77e27a..de87123 100644 --- a/lua/data/func.lua +++ b/lua/data/func.lua @@ -2571,5 +2571,84 @@ function M.swap_buffers() end end +--- Get relative window width +---@param fraction number fraction of the main window width +---@return number width the relative width in columns +function M.get_relative_win_width(fraction) + -- Validate param types + vim.validate({ + fraction = { fraction, 'number', true }, + }) + -- Catch out-of-range parameters + if fraction < 0 then + return 0 + elseif fraction > 1 then + return 1 + end + -- Get window width + local win_width = vim.api.nvim_win_get_width(0) + -- Round relative width to nearest whole number + return math.floor(win_width * fraction + 0.5) +end + +--- Testing truncated width +---@param fraction number fraction of the main window width +function M.trunc_test(fraction) + local trunc_width = (M.get_relative_win_width(fraction)) + Snacks.picker.files({ formatters = { file = { truncate = trunc_width } } }) +end + +--- Function to get identifying information for all current floating windows +---@return table info A table of floating windows and their info +function M.get_floating_window_info() + local info = {} + for _, win in ipairs(vim.api.nvim_list_wins()) do + local config = vim.api.nvim_win_get_config(win) + if config.relative ~= '' then + local buf = vim.api.nvim_win_get_buf(win) + table.insert(info, { + win_id = win, + bufname = vim.api.nvim_buf_get_name(buf), + filetype = vim.api.nvim_get_option_value('filetype', { buf = buf }), + width = vim.api.nvim_win_get_width(win), + height = vim.api.nvim_win_get_height(win), + }) + end + end + return info +end + +--- Function to get identifying information for all current +--- floating windows and dump that info to a temporary file +---@param path string? The path to the file (optional) +function M.dump_floating_window_info(path) + local float_info = M.get_floating_window_info() + local output = {} + + for _, win in ipairs(float_info) do + table.insert( + output, + string.format( + 'Win ID: %d\n Buffer: %s\n Filetype: %s\n Width: %d\n Height: %d\n---', + win.win_id, + win.bufname ~= '' and win.bufname or '[No Name]', + win.filetype, + win.width, + win.height + ) + ) + end + + if not path then + path = vim.fn.stdpath('cache') .. '/float_dump.txt' + end + + local f = assert(io.open(path, 'w')) + f:write(table.concat(output, '\n')) + f:close() + + print('Floating window info written to ' .. path) +end + -- Export the module return M diff --git a/lua/data/keys.lua b/lua/data/keys.lua index e2a512b..8f8c2bd 100644 --- a/lua/data/keys.lua +++ b/lua/data/keys.lua @@ -1243,6 +1243,12 @@ M.misc = { desc = 'Yank buffer', mode = 'n', }, + { -- Pick keymaps + lhs = 'fk', + rhs = 'Pick keymaps', + desc = 'Pick keymaps', + mode = 'n', + }, } M.nekifoch = { diff --git a/lua/data/types.lua b/lua/data/types.lua index 3d55027..cfcc7a5 100644 --- a/lua/data/types.lua +++ b/lua/data/types.lua @@ -1750,6 +1750,13 @@ M.catppuccin = { light = 'latte', dark = 'mocha', }, + -- color_overrides = { -- OLED black background + -- mocha = { + -- base = '#000000', + -- mantle = '#000000', + -- crust = '#000000', + -- }, + -- }, transparent_background = false, integrations = { native_lsp = { @@ -1780,6 +1787,7 @@ M.catppuccin = { }, grug_far = true, mason = true, + markview = true, mini = { enabled = true, indentscope_color = 'mauve', @@ -1857,9 +1865,27 @@ M.noice = { M.grug_far = { opts = { + showCompactInputs = true, + showInputsTopPadding = false, + showInputsBottomPadding = false, + helpLine = { + enabled = false, + }, + enabledEngines = { 'ripgrep', 'astgrep' }, engines = { astgrep = { path = 'ast-grep', + placeholders = { + enabled = false, + }, + }, + ripgrep = { + placeholders = { + enabled = false, + }, + }, + ['astgrep-rules'] = { + path = 'ast-grep', }, }, engine = 'ripgrep', @@ -1869,15 +1895,14 @@ M.grug_far = { --- Smear Cursor M.smearcursor = function() local bg = require('data.func').get_bg_color('Normal') or '#1d1d2d' - local fg = require('data.func').get_fg_color('Normal') or '#d3cdc3' + local fg = require('data.func').get_fg_color('Normal') or '#f7e0dc' return { -- Cursor color. Defaults to Normal gui foreground color cursor_color = fg, - -- cursor_color = 'none', -- Background color. Defaults to Normal gui background color - --normal_bg = bg, + normal_bg = bg, -- Smear cursor when switching buffers smear_between_buffers = true, diff --git a/lua/lvplugs/lvplugs.lua b/lua/lvplugs/lvplugs.lua index cd2fabc..1974af4 100644 --- a/lua/lvplugs/lvplugs.lua +++ b/lua/lvplugs/lvplugs.lua @@ -14,6 +14,10 @@ return { import = 'lazyvim.plugins.extras.ai.copilot', cond = require('data.cond').copilot, }, + { -- Copilot Chat + import = 'lazyvim.plugins.extras.ai.copilot-chat', + cond = require('data.cond').copilot, + }, { -- Tabnine import = 'lazyvim.plugins.extras.ai.tabnine', cond = require('data.cond').tabnine, diff --git a/lua/plugins/cmp.lua b/lua/plugins/cmp.lua index cccb3a7..cd52332 100644 --- a/lua/plugins/cmp.lua +++ b/lua/plugins/cmp.lua @@ -30,11 +30,16 @@ if vim.g.useblinkcmp then vim.g.lazyvim_blink_main = true end - return { - { + return { -- Blink.cmp + { -- Overide the lazy-load event to include CmdlineEnter + 'saghen/blink.cmp', + event = { 'InsertEnter', 'CmdlineEnter' }, + }, + { -- Load blink.cmp configuration 'saghen/blink.cmp', dependencies = { 'mikavilpas/blink-ripgrep.nvim', + 'archie-judd/blink-cmp-words', }, opts = { enabled = function() @@ -65,6 +70,15 @@ if vim.g.useblinkcmp then snippets = { preset = 'luasnip', }, + fuzzy = { + implementation = 'prefer_rust', + use_frecency = true, + sorts = { + 'exact', + 'score', + 'sort_text', + }, + }, keymap = { preset = 'enter', [''] = { 'select_and_accept' }, @@ -113,7 +127,11 @@ if vim.g.useblinkcmp then module = 'blink-ripgrep', name = 'Ripgrep', opts = { - search_casing = '--smart-case', + backend = { + ripgrep = { + search_casing = '--smart-case', + }, + }, }, transform_items = function(_, items) for _, item in ipairs(items) do @@ -125,13 +143,53 @@ if vim.g.useblinkcmp then return items end, }, + -- Use the thesaurus source + thesaurus = { + name = 'blink-cmp-words', + module = 'blink-cmp-words.thesaurus', + -- All available options + opts = { + -- A score offset applied to returned items. + -- By default the highest score is 0 (item 1 has a score of -1, item 2 of -2 etc..). + score_offset = 0, + + -- Default pointers define the lexical relations listed under each definition, + -- see Pointer Symbols below. + -- Default is as below ("antonyms", "similar to" and "also see"). + pointer_symbols = { '!', '&', '^' }, + }, + }, + -- Use the dictionary source + dictionary = { + name = 'blink-cmp-words', + module = 'blink-cmp-words.dictionary', + -- All available options + opts = { + -- The number of characters required to trigger completion. + -- Set this higher if completion is slow, 3 is default. + dictionary_search_threshold = 3, + + -- See above + score_offset = 0, + + -- See above + pointer_symbols = { '!', '&', '^' }, + }, + }, }, default = { 'lsp', 'path', + 'lazydev', 'snippets', 'buffer', 'ripgrep', + 'thesaurus', + }, + -- Setup completion by filetype + per_filetype = { + text = { 'dictionary' }, + markdown = { 'thesaurus' }, }, }, }, diff --git a/lua/plugins/coding.lua b/lua/plugins/coding.lua index bfc9fca..297fbde 100644 --- a/lua/plugins/coding.lua +++ b/lua/plugins/coding.lua @@ -65,4 +65,19 @@ return { cond = require('data.cond').tiny_inline_diagnostic, config = require('data.types').tiny_inline_diagnostic.config, }, + { + 'neovim/nvim-lspconfig', + init = function() end, + opts = { + servers = { + yamlls = { + settings = { + yaml = { + customTags = vim.g.custom_yaml_tags, + }, + }, + }, + }, + }, + }, } diff --git a/lua/plugins/editor.lua b/lua/plugins/editor.lua index 64db0d0..2238276 100644 --- a/lua/plugins/editor.lua +++ b/lua/plugins/editor.lua @@ -9,6 +9,12 @@ return { 'ehpi/vim-illuminate', opts = require('data.types').illuminate.opts, }, + { -- Nvim-notify + 'rcarriga/nvim-notify', + opts = { + fps = 144, -- your monitor refresh rate + }, + }, { -- Grug-Far 'MagicDuck/grug-far.nvim', opts = require('data.types').grug_far.opts, diff --git a/lua/plugins/languages.lua b/lua/plugins/languages.lua index 37b0a6d..d1d2d55 100644 --- a/lua/plugins/languages.lua +++ b/lua/plugins/languages.lua @@ -44,4 +44,8 @@ return { vim.fn['mkdp#util#install']() end, }, + { -- CookLang + 'luizribeiro/vim-cooklang', + lazy = false, + }, } diff --git a/lua/plugins/nvim_updater.lua b/lua/plugins/nvim_updater.lua index b9b57eb..1697879 100644 --- a/lua/plugins/nvim_updater.lua +++ b/lua/plugins/nvim_updater.lua @@ -2,27 +2,29 @@ -- │ Nvim-Updater │ -- ╰─────────────────────────────────────────────────────────╯ -return { -- Neovim Updater - 'rootiest/nvim-updater.nvim', - version = '*', -- Pin to GitHub releases - lazy = false, - opts = { - build_type = 'RelWithDebInfo', - branch = 'master', - verbose = false, - check_for_updates = true, - update_interval = (60 * 60) * 6, -- 6 hours - notify_updates = false, - default_keymaps = false, - }, - keys = function() - -- Load Neovim Updater Debugging Functions - require('config.nvim_updater') -- Debugging Functions +-- return { -- Neovim Updater +-- 'rootiest/nvim-updater.nvim', +-- version = '*', -- Pin to GitHub releases +-- lazy = false, +-- opts = { +-- build_type = 'Release', +-- branch = 'master', +-- verbose = false, +-- check_for_updates = true, +-- update_interval = (60 * 60) * 6, -- 6 hours +-- notify_updates = false, +-- default_keymaps = false, +-- }, +-- keys = function() +-- -- Load Neovim Updater Debugging Functions +-- require('config.nvim_updater') -- Debugging Functions +-- +-- -- Add Neovim Updater menu +-- require('data.func').add_keymap(require('data.keys').group.nvimup) +-- -- Add Neovim Updater keys +-- return require('data.keys').nvimup +-- end, +-- dev = vim.g.rootiest_dev or false, +-- } - -- Add Neovim Updater menu - require('data.func').add_keymap(require('data.keys').group.nvimup) - -- Add Neovim Updater keys - return require('data.keys').nvimup - end, - dev = vim.g.rootiest_dev or false, -} +return {} diff --git a/lua/plugins/obsidian.lua b/lua/plugins/obsidian.lua index f3ba9de..229c864 100644 --- a/lua/plugins/obsidian.lua +++ b/lua/plugins/obsidian.lua @@ -1,34 +1,59 @@ return { - 'epwalsh/obsidian.nvim', - version = '*', -- recommended, use latest release instead of latest commit - lazy = true, - event = { - 'BufReadPre ' .. vim.fn.expand('~' .. '/vaults/rootiest/*.md'), - 'BufNewFile ' .. vim.fn.expand('~' .. '/vaults/rootiest/*.md'), + { + 'obsidian-nvim/obsidian.nvim', + version = '*', -- recommended, use latest release instead of latest commit + lazy = true, + event = { + 'BufReadPre ' .. vim.fn.expand('~' .. '/vaults/Rootiest Notes/*.md'), + 'BufNewFile ' .. vim.fn.expand('~' .. '/vaults/Rootiest Notes/*.md'), + }, + cmd = 'Obsidian', + dependencies = { + -- Required. + 'nvim-lua/plenary.nvim', + }, + opts = { + completion = { + nvim_cmp = false, + blink = true, + min_chars = 2, + }, + picker = { + name = 'snacks.pick', + }, + workspaces = { + { + name = 'Rootiest Notes', + path = '~/vaults/Rootiest Notes', + }, + }, + templates = { + folder = 'templates', + date_format = '%Y-%m-%d-%a', + time_format = '%H:%M', + substitutions = { + yesterday = function() + return os.date('%Y-%m-%d', os.time() - 86400) + end, + }, + }, + -- ui = { + -- enable = false, + -- }, + }, }, - dependencies = { - -- Required. - 'nvim-lua/plenary.nvim', - }, - opts = { - workspaces = { - { - name = 'rootiest', - path = '~/vaults/rootiest', + { + 'arakkkkk/kanban.nvim', + ft = 'markdown', + opts = { + markdown = { + description_folder = './tasks/', -- Path to save the file corresponding to the task. + list_head = '## ', }, }, - templates = { - folder = 'templates', - date_format = '%Y-%m-%d-%a', - time_format = '%H:%M', - substitutions = { - yesterday = function() - return os.date('%Y-%m-%d', os.time() - 86400) - end, - }, - }, - ui = { - enable = false, - }, + }, + { + 'marcocofano/excalidraw.nvim', + lazy = false, }, } diff --git a/lua/plugins/snacks.lua b/lua/plugins/snacks.lua index d80c1f4..603fccb 100644 --- a/lua/plugins/snacks.lua +++ b/lua/plugins/snacks.lua @@ -106,9 +106,16 @@ local profiler = { }, } +---@class PickerList +---@field row2idx fun(self: PickerList, row: integer): integer +---@field _move fun(self: PickerList, index: integer, a: boolean, b: boolean): nil + +---@class SnacksPicker +---@field list PickerList + --- flash_on_picker ---Use the flash.nvim plugin in Snacks picker ----@param picker table: The picker instance to interact with. +---@param picker SnacksPicker The picker instance to interact with. local flash_on_picker = function(picker) require('flash').jump({ pattern = '^', @@ -162,11 +169,36 @@ local picker = { jump = { close = true }, auto_close = true, layout = { preset = 'sidebar' }, + -- ignored = true, -- Show .ignore/.gitignore files + -- hidden = true, -- Show hidden files }, }, layouts = { -- default = vscode_layout, vscode = vscode_layout, + ivy = { + layout = { + box = 'vertical', + backdrop = false, + row = -1, + width = 0.8, + height = 0.4, + border = 'top', + title = ' {title} {live} {flags}', + title_pos = 'left', + { win = 'input', height = 1, border = 'bottom' }, + { + box = 'horizontal', + { win = 'list', width = 0.4, border = 'none' }, + { + win = 'preview', + title = '{preview}', + width = 0.6, + border = 'left', + }, + }, + }, + }, left = { preset = 'sidebar', layout = { position = 'left' } }, right = { preset = 'sidebar', layout = { position = 'right' } }, top = { preset = 'ivy', layout = { position = 'top' } }, diff --git a/lua/plugins/statusline/lualine.lua b/lua/plugins/statusline/lualine.lua index ee50114..eaecbcb 100644 --- a/lua/plugins/statusline/lualine.lua +++ b/lua/plugins/statusline/lualine.lua @@ -285,40 +285,40 @@ return { -- Lualine end, padding = { left = 0, right = 1 }, }, - { -- Music - function() - return music_stats.get_icon_with_text() - end, - cond = function() - return require('data.func').is_window_wide_enough(100) - end, - padding = { left = 0, right = 1 }, - }, - { -- Neovim Updater Status - function() - return require('nvim_updater').get_statusline().icon_text - end, - color = function() - local fg = require('data.func').get_fg_color( - require('nvim_updater').get_statusline().color - ) - local bg = require('data.func').get_bg_color('lualine_x') - return { fg = fg, bg = bg } - end, - on_click = function() - require('nvim_updater').show_new_commits({ - isupdate = true, - short = false, - }) - end, - padding = { left = 1, right = 1 }, - cond = function() - if not pcall(require, 'nvim_updater') then - return false - end - return not string.find(vim.bo.filetype, 'neovim_updater_term') - end, - }, + -- { -- Music + -- function() + -- return music_stats.get_icon_with_text() + -- end, + -- cond = function() + -- return require('data.func').is_window_wide_enough(100) + -- end, + -- padding = { left = 0, right = 1 }, + -- }, + -- { -- Neovim Updater Status + -- function() + -- return require('nvim_updater').get_statusline().icon_text + -- end, + -- color = function() + -- local fg = require('data.func').get_fg_color( + -- require('nvim_updater').get_statusline().color + -- ) + -- local bg = require('data.func').get_bg_color('lualine_x') + -- return { fg = fg, bg = bg } + -- end, + -- on_click = function() + -- require('nvim_updater').show_new_commits({ + -- isupdate = true, + -- short = false, + -- }) + -- end, + -- padding = { left = 1, right = 1 }, + -- cond = function() + -- if not pcall(require, 'nvim_updater') then + -- return false + -- end + -- return not string.find(vim.bo.filetype, 'neovim_updater_term') + -- end, + -- }, }, lualine_y = { { -- NeoCodeium Status diff --git a/lua/utils/lsp-ops.lua b/lua/utils/lsp-ops.lua new file mode 100644 index 0000000..e6f2e9b --- /dev/null +++ b/lua/utils/lsp-ops.lua @@ -0,0 +1,33 @@ +-- ╭─────────────────────────────────────────────────────────╮ +-- │ LSP Operations │ +-- ╰─────────────────────────────────────────────────────────╯ + +local M = {} + +--- Function to get attached LSP server names +---@return string|nil list A list of attached lsp servers +function M.get_attached_lsp_clients() + local clients = + vim.lsp.get_clients({ bufnr = vim.api.nvim_get_current_buf() }) + if #clients == 0 then + return nil + else + local names = {} + for _, client in ipairs(clients) do + table.insert(names, client.name) + end + return 'LSP~ ' .. table.concat(names, ', ') + end +end + +--- Function to print the list of attached LSP servers +function M.print_attached_lsp_clients() + local clients = M.get_attached_lsp_clients() + if clients == nil then + print('No LSP clients attached') + else + print(clients) + end +end + +return M diff --git a/lua/utils/picker_trunc.lua b/lua/utils/picker_trunc.lua new file mode 100644 index 0000000..4d88834 --- /dev/null +++ b/lua/utils/picker_trunc.lua @@ -0,0 +1,105 @@ +local M = {} + +--- Recursively find the width for a window by name +---@param layout table +---@param target_win string +---@return number|nil +local function find_win_width(layout, target_win) + for _, item in ipairs(layout) do + if type(item) == 'table' then + if item.win == target_win and item.width then + return item.width + elseif vim.islist(item) or item.box then + local result = find_win_width(item, target_win) + if result then + return result + end + end + end + end + return nil +end + +--- Get relative window width +---@param fraction number fraction of the main window width +---@param layout_name string the snacks layout to use +---@param target_win string the window name to extract width for +---@return number width the relative width in columns +function M.get_relative_win_width(fraction, layout_name, target_win) + vim.validate({ + fraction = { fraction, 'number', true }, + layout_name = { layout_name, 'string', true }, + target_win = { target_win, 'string', true }, + }) + + if fraction < 0 then + return 0 + elseif fraction > 1 then + return 1 + end + + local win_width = vim.api.nvim_win_get_width(0) + local top_level_fraction = 1 + local nested_win_fraction = 1 + + local ok, snacks = pcall(require, 'snacks') + if ok then + local layouts = snacks.config + and snacks.config.picker + and snacks.config.picker.layouts + + local chosen_layout = layouts + and layouts[layout_name] + and layouts[layout_name].layout + + if chosen_layout then + -- Check for layout-wide width + if type(chosen_layout) == 'table' and chosen_layout.width then + top_level_fraction = chosen_layout.width + end + + -- Check inside nested win="target_win" + nested_win_fraction = find_win_width(chosen_layout, target_win) or 1 + end + end + + local combined_fraction = fraction * top_level_fraction * nested_win_fraction + return math.floor(win_width * combined_fraction + 0.5) +end + +--- Truncate the picker file text +---@param fraction number|nil +---@param layout_name string|nil +---@param target_win string|nil +---@param picker_type string|nil +function M.trunc_text(fraction, layout_name, target_win, picker_type) + fraction = fraction or 1.0 + layout_name = layout_name or 'default' + target_win = target_win or 'list' + picker_type = picker_type or 'files' + + local trunc_width = + M.get_relative_win_width(fraction, layout_name, target_win) + + local ok, snacks = pcall(require, 'snacks') + if not ok then + vim.notify('snacks.nvim not loaded', vim.log.levels.ERROR) + return + end + + local picker = snacks.picker and snacks.picker[picker_type] + if type(picker) ~= 'function' then + vim.notify( + 'Invalid Snacks.picker type: ' .. tostring(picker_type), + vim.log.levels.ERROR + ) + return + end + + picker({ + layout = { preset = layout_name }, + formatters = { file = { truncate = trunc_width } }, + }) +end + +return M