feat(ex): add :log command

This commit is contained in:
Olivia Kinnear
2026-03-28 22:07:04 -05:00
parent 6bea0cdbdc
commit 8715877417
14 changed files with 266 additions and 19 deletions

View File

@@ -1,5 +1,6 @@
local api = vim.api
local lsp = vim.lsp
local fs = vim.fs
local util = require('vim._core.util')
local M = {}
@@ -11,7 +12,7 @@ end
--- @return string[]
local function get_client_names()
return vim
.iter(lsp.get_clients())
.iter(vim.lsp.get_clients())
:map(function(client)
return client.name
end)
@@ -24,7 +25,7 @@ end
local function filtered_config_names(filter)
return function()
return vim
.iter(lsp.get_configs(filter))
.iter(vim.lsp.get_configs(filter))
:map(function(config)
return config.name
end)
@@ -43,8 +44,8 @@ local complete_args = {
--- @param enable? boolean
local function checked_enable(names, enable)
for _, name in ipairs(names) do
if name:find('*') == nil and lsp.config[name] ~= nil then
lsp.enable(name, enable)
if name:find('*') == nil and vim.lsp.config[name] ~= nil then
vim.lsp.enable(name, enable)
else
echo_err(("No client config named '%s'"):format(name))
end
@@ -56,7 +57,7 @@ local function ex_lsp_enable(config_names)
-- Default to enabling all clients matching the filetype of the current buffer.
if #config_names == 0 then
local filetype = vim.bo.filetype
for _, config in ipairs(lsp.get_configs()) do
for _, config in ipairs(vim.lsp.get_configs()) do
local filetypes = config.filetypes
if filetypes == nil or vim.list_contains(filetypes, filetype) then
table.insert(config_names, config.name)
@@ -80,12 +81,12 @@ local function ex_lsp_disable(config_names)
-- Default to disabling all clients attached to the current buffer.
if #config_names == 0 then
config_names = vim
.iter(lsp.get_clients { bufnr = api.nvim_get_current_buf() })
.iter(vim.lsp.get_clients { bufnr = api.nvim_get_current_buf() })
:map(function(client)
return client.name
end)
:filter(function(name)
return lsp.config[name] ~= nil
return vim.lsp.config[name] ~= nil
end)
:totable()
if #config_names == 0 then
@@ -102,7 +103,7 @@ end
local function get_clients_from_names(client_names)
-- Default to all active clients attached to the current buffer.
if #client_names == 0 then
local clients = lsp.get_clients { bufnr = api.nvim_get_current_buf() }
local clients = vim.lsp.get_clients { bufnr = api.nvim_get_current_buf() }
if #clients == 0 then
echo_err('No clients attached to current buffer')
end
@@ -111,7 +112,7 @@ local function get_clients_from_names(client_names)
return vim
.iter(client_names)
:map(function(name)
local clients = lsp.get_clients { name = name }
local clients = vim.lsp.get_clients { name = name }
if #clients == 0 then
echo_err(("No active clients named '%s'"):format(name))
end
@@ -186,4 +187,45 @@ function M.lsp_complete(line)
end
end
--- @type string
--- @diagnostic disable-next-line: assign-type-mismatch
local log_dir = vim.fn.stdpath('log')
--- Implements command: `:log {file}`.
--- @param filename string
--- @param mods string
M.ex_log = function(filename, mods)
if filename == '' then
util.wrapped_edit(log_dir, mods)
else
local path --- @type string
-- Special case for NVIM_LOG_FILE
local nvim_log_file = vim.env.NVIM_LOG_FILE --- @type string
if filename == 'nvim' and nvim_log_file and nvim_log_file ~= '' then
path = nvim_log_file
else
path = fs.joinpath(log_dir, filename .. '.log')
end
if not vim.uv.fs_stat(path) then
echo_err(("No such log file: '%s'"):format(path))
return
end
util.wrapped_edit(path, mods)
vim.cmd.normal { 'G', bang = true }
end
end
--- Completion logic for `:log` command
--- @return string[] list of completions
function M.log_complete()
local names = { 'nvim' } --- @type string[]
for file, type in vim.fs.dir(log_dir, { depth = math.huge }) do
local name, matches = file:gsub('%.log$', '')
if matches ~= 0 and type == 'file' and name ~= 'nvim' then
names[#names + 1] = name
end
end
return names
end
return M

View File

@@ -22,6 +22,17 @@ function M.space_below()
add_blank()
end
--- Gets a buffer by name
--- @param name string
--- @return integer?
function M.get_buf_by_name(name)
for _, buf in ipairs(vim.api.nvim_list_bufs()) do
if vim.api.nvim_buf_get_name(buf) == name then
return buf
end
end
end
--- Edit a file in a specific window
--- @param winnr number
--- @param file string
@@ -49,6 +60,23 @@ M.edit_in = function(winnr, file)
end)
end
--- :edit, but it respects commands like :hor, :vert, :tab, etc.
--- @param file string
--- @param mods_str string
function M.wrapped_edit(file, mods_str)
local cmdline = table.concat({ mods_str, 'edit' }, ' ')
local mods = vim.api.nvim_parse_cmd(cmdline, {}).mods
--- @diagnostic disable-next-line: need-check-nil
if mods.tab > 0 or mods.split ~= '' or mods.horizontal or mods.vertical then
local buf = M.get_buf_by_name(file)
if buf == nil then
buf = vim.api.nvim_create_buf(true, false)
end
vim.cmd.sbuffer { buf, mods = mods }
end
vim.cmd.edit { file }
end
--- Read a chunk of data from a file
--- @param file string
--- @param size number

View File

@@ -10,11 +10,9 @@
---
--- Then try to run the language server, and open the log with:
--- ```vim
--- :lua vim.cmd('tabnew ' .. vim.lsp.log.get_filename())
--- :log lsp
--- ```
---
--- (Or use `:LspLog` if you have nvim-lspconfig installed.)
---
--- Note:
--- - Remember to DISABLE verbose logging ("debug" or "trace" level), else you may encounter
--- performance issues.