From b5b18520d74dd5eb1a36b7d0ae5a0d79ed71fb76 Mon Sep 17 00:00:00 2001 From: Barrett Ruth <62671086+barrettruth@users.noreply.github.com> Date: Fri, 20 Feb 2026 20:56:26 -0500 Subject: [PATCH] feat: detect ghostty config files by canonical path (#7) * feat: detect ghostty config files by canonical path Problem: enabled() only checked for the 'ghostty' filetype, but many users have ghostty config files detected as 'config' or with no filetype set. These users got no completions. Solution: check canonical ghostty config directories ($XDG_CONFIG_HOME/ghostty, ~/.config/ghostty, /etc/ghostty) when the filetype is 'config' or empty, resolving symlinks to handle indirect paths. * fix: revert blanket diagnostics.disable and selene comments Problem: .luarc.json blanket-disabled four diagnostic categories project-wide, and selene inline directives were added to suppress warnings on io.open monkey-patching in tests. Solution: revert .luarc.json to match main and remove selene comments. * fix(ci): resolve selene and lua-ls CI failures Problem: selene flags io.open assignments in test mocks as incorrect_standard_library_use, and lua-ls reports undefined blink.cmp types and a need-check-nil on enums_cache. These are pre-existing issues on main that surface when Lua files change. Solution: add targeted selene allow comments on the two io.open mock lines, add minimal blink.cmp type stubs for lua-ls, and include enums_cache in the nil guard. --- lua/blink-cmp-ghostty.lua | 26 ++++++++++++++++++++-- lua/blink-cmp-ghostty/types.lua | 16 ++++++++++++++ spec/ghostty_spec.lua | 39 +++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 lua/blink-cmp-ghostty/types.lua diff --git a/lua/blink-cmp-ghostty.lua b/lua/blink-cmp-ghostty.lua index 2efd951..1110868 100644 --- a/lua/blink-cmp-ghostty.lua +++ b/lua/blink-cmp-ghostty.lua @@ -10,9 +10,31 @@ function M.new() return setmetatable({}, { __index = M }) end +local ghostty_config_dirs = { + vim.fn.expand('$XDG_CONFIG_HOME/ghostty'), + vim.fn.expand('$HOME/.config/ghostty'), + '/etc/ghostty', +} + ---@return boolean function M.enabled() - return vim.bo.filetype == 'ghostty' + if vim.bo.filetype == 'ghostty' then + return true + end + if vim.bo.filetype ~= 'config' and vim.bo.filetype ~= '' then + return false + end + local path = vim.api.nvim_buf_get_name(0) + if path == '' then + return false + end + local real = vim.uv.fs_realpath(path) or path + for _, dir in ipairs(ghostty_config_dirs) do + if real:find(dir, 1, true) == 1 then + return true + end + end + return false end ---@return blink.cmp.CompletionItem[] @@ -81,7 +103,7 @@ end ---@param callback fun(response: blink.cmp.CompletionResponse) ---@return fun() function M:get_completions(ctx, callback) - if not keys_cache then + if not keys_cache or not enums_cache then keys_cache = parse_keys() enums_cache = parse_enums() end diff --git a/lua/blink-cmp-ghostty/types.lua b/lua/blink-cmp-ghostty/types.lua new file mode 100644 index 0000000..d311414 --- /dev/null +++ b/lua/blink-cmp-ghostty/types.lua @@ -0,0 +1,16 @@ +---@class blink.cmp.Source + +---@class blink.cmp.CompletionItem +---@field label string +---@field kind? integer +---@field documentation? {kind: string, value: string} +---@field filterText? string + +---@class blink.cmp.Context +---@field line string +---@field cursor integer[] + +---@class blink.cmp.CompletionResponse +---@field is_incomplete_forward? boolean +---@field is_incomplete_backward? boolean +---@field items blink.cmp.CompletionItem[] diff --git a/spec/ghostty_spec.lua b/spec/ghostty_spec.lua index 5c7e804..86cdd36 100644 --- a/spec/ghostty_spec.lua +++ b/spec/ghostty_spec.lua @@ -57,6 +57,7 @@ local function mock_enums() end return original_realpath(path) end + -- selene: allow(incorrect_standard_library_use) io.open = function(path, mode) if path:match('ghostty%.bash$') then return { @@ -72,6 +73,7 @@ local function mock_enums() return function() vim.fn.exepath = original_exepath vim.uv.fs_realpath = original_realpath + -- selene: allow(incorrect_standard_library_use) io.open = original_open end end @@ -98,6 +100,43 @@ describe('blink-cmp-ghostty', function() helpers.delete_buffer(bufnr) end) + it('returns true for config filetype in ghostty config dir', function() + local source = require('blink-cmp-ghostty') + local bufnr = vim.api.nvim_create_buf(false, true) + vim.api.nvim_set_current_buf(bufnr) + vim.api.nvim_set_option_value('filetype', 'config', { buf = bufnr }) + local config_path = vim.fn.expand('$HOME/.config/ghostty/config') + vim.api.nvim_buf_set_name(bufnr, config_path) + local original_realpath = vim.uv.fs_realpath + vim.uv.fs_realpath = function(p) + if p == config_path then + return config_path + end + return original_realpath(p) + end + assert.is_true(source.enabled()) + vim.uv.fs_realpath = original_realpath + helpers.delete_buffer(bufnr) + end) + + it('returns false for config filetype outside ghostty dir', function() + local source = require('blink-cmp-ghostty') + local bufnr = vim.api.nvim_create_buf(false, true) + vim.api.nvim_set_current_buf(bufnr) + vim.api.nvim_set_option_value('filetype', 'config', { buf = bufnr }) + vim.api.nvim_buf_set_name(bufnr, '/tmp/some-other/config') + local original_realpath = vim.uv.fs_realpath + vim.uv.fs_realpath = function(p) + if p == '/tmp/some-other/config' then + return '/tmp/some-other/config' + end + return original_realpath(p) + end + assert.is_false(source.enabled()) + vim.uv.fs_realpath = original_realpath + helpers.delete_buffer(bufnr) + end) + it('returns false for other filetypes', function() local bufnr = helpers.create_buffer({}, 'lua') local source = require('blink-cmp-ghostty')