mirror of
https://github.com/NotAShelf/syntax-gaslighting.nvim.git
synced 2026-04-15 15:33:47 +00:00
add lua-language-server types; fix comment logic
This commit is contained in:
parent
2cf9d00db9
commit
b4cd8ff197
1 changed files with 93 additions and 60 deletions
|
|
@ -1,20 +1,25 @@
|
|||
---@class GaslightingConfig
|
||||
---@field gaslighting_chance number -- Percentage chance that a line will receive a gaslighting message
|
||||
---@field min_line_length number -- Minimum length of a trimmed line for gaslighting to apply
|
||||
---@field highlight string -- Highlight group name used for virtual text messages
|
||||
---@field debounce_delay number -- Delay in milliseconds before updating decorations
|
||||
---@field auto_update boolean -- Automatically update decorations on buffer changes
|
||||
---@field merge_messages boolean -- Merge user-defined messages with default ones
|
||||
---@field filetypes_to_ignore string[] -- List of filetypes to ignore from gaslighting
|
||||
---@field messages string[] -- Array of gaslighting messages
|
||||
|
||||
local M = {}
|
||||
|
||||
-- Default configuration options
|
||||
--- Default configuration options
|
||||
---@type GaslightingConfig
|
||||
local default_config = {
|
||||
gaslighting_chance = 5, -- 5% chance per line
|
||||
min_line_length = 10, -- Minimum trimmed line length to apply gaslighting
|
||||
highlight = "GaslightingUnderline", -- Highlight group name (linked to Comment by default)
|
||||
debounce_delay = 500, -- Debounce delay in ms
|
||||
auto_update = true, -- Whether to auto-update on buffer events
|
||||
merge_messages = false, -- If true, merge user messages with default ones
|
||||
filetypes_to_ignore = { -- List of filetypes to ignore (default: "netrw")
|
||||
"netrw",
|
||||
"NvimTree",
|
||||
"neo-tree",
|
||||
"Telescope",
|
||||
"qf"
|
||||
},
|
||||
gaslighting_chance = 5,
|
||||
min_line_length = 10,
|
||||
highlight = "GaslightingUnderline",
|
||||
debounce_delay = 500,
|
||||
auto_update = true,
|
||||
merge_messages = false,
|
||||
filetypes_to_ignore = { "netrw", "NvimTree", "neo-tree", "Telescope", "qf" },
|
||||
messages = {
|
||||
"Are you sure this will pass the code quality checks? 🤔",
|
||||
"Is this line really covered by unit tests? 🧐",
|
||||
|
|
@ -31,14 +36,22 @@ local default_config = {
|
|||
},
|
||||
}
|
||||
|
||||
local config = {}
|
||||
---@type GaslightingConfig
|
||||
local config = vim.deepcopy(default_config)
|
||||
|
||||
local api = vim.api
|
||||
local timer = nil
|
||||
local ns = api.nvim_create_namespace("syntax_gaslighting")
|
||||
M.is_enabled = true
|
||||
|
||||
-- If user_config.merge_messages is true and user_config.messages is provided,
|
||||
-- the plugin will merge default messages with user messages.
|
||||
--- Convert filetype list to a set for fast lookup
|
||||
local ignored_filetypes_set = {}
|
||||
for _, ft in ipairs(default_config.filetypes_to_ignore) do
|
||||
ignored_filetypes_set[ft] = true
|
||||
end
|
||||
|
||||
--- Merge user configuration with defaults
|
||||
---@param user_config table
|
||||
function M.setup(user_config)
|
||||
user_config = user_config or {}
|
||||
config = vim.tbl_deep_extend("force", {}, default_config, user_config)
|
||||
|
|
@ -61,7 +74,7 @@ function M.setup(user_config)
|
|||
})
|
||||
end
|
||||
|
||||
-- Command to toggle the gaslighting functionality.
|
||||
-- Toggle the gaslighting functionality.
|
||||
api.nvim_create_user_command("SyntaxGaslightingToggle", function()
|
||||
M.is_enabled = not M.is_enabled
|
||||
if M.is_enabled then
|
||||
|
|
@ -74,7 +87,7 @@ function M.setup(user_config)
|
|||
end
|
||||
end, {})
|
||||
|
||||
-- Command to change the gaslighting chance percentage.
|
||||
-- Change the gaslighting chance percentage.
|
||||
api.nvim_create_user_command("SyntaxGaslightingEditChance", function()
|
||||
local input = vim.fn.input("Enter the percentage chance of gaslighting (1-100): ", config.gaslighting_chance)
|
||||
local num = tonumber(input)
|
||||
|
|
@ -86,31 +99,31 @@ function M.setup(user_config)
|
|||
print("Invalid input. Please enter a number between 1 and 100.")
|
||||
end
|
||||
end, {})
|
||||
end
|
||||
|
||||
-- A simple deterministic hash function (not cryptographically secure)
|
||||
local function createHash(str)
|
||||
local hash1, hash2 = 0, 0
|
||||
for i = 1, #str do
|
||||
local byte = str:byte(i)
|
||||
hash1 = (hash1 * 31 + byte) % 0xFFFFFFFF
|
||||
hash2 = (hash2 * 37 + byte) % 0xFFFFFFFF
|
||||
end
|
||||
return string.format("%08x%08x", hash1, hash2)
|
||||
end
|
||||
|
||||
-- Check if the current buffer's filetype is in the ignore list
|
||||
local function shouldIgnoreFileType()
|
||||
local filetype = vim.bo.filetype
|
||||
for _, ft in ipairs(config.filetypes_to_ignore) do
|
||||
if filetype == ft then
|
||||
return true
|
||||
api.nvim_create_user_command("SyntaxGaslightingMessages", function()
|
||||
print("Current gaslighting messages:")
|
||||
for _, msg in ipairs(config.messages) do
|
||||
print("- " .. msg)
|
||||
end
|
||||
end
|
||||
return false
|
||||
end, {})
|
||||
end
|
||||
|
||||
-- Determine if a gaslighting message should be applied to a line and return it if so.
|
||||
-- A simple, deterministic hash function using sha256
|
||||
---@param str string
|
||||
---@return string
|
||||
local function createHash(str)
|
||||
return vim.fn.sha256(str)
|
||||
end
|
||||
|
||||
--- Check if the current filetype should be ignored
|
||||
---@return boolean
|
||||
local function shouldIgnoreFileType()
|
||||
return ignored_filetypes_set[vim.bo.filetype] or false
|
||||
end
|
||||
|
||||
--- Determine if a gaslighting message should be applied to a line
|
||||
---@param line string
|
||||
---@return string|nil
|
||||
local function getGaslightingMessageForLineContent(line)
|
||||
local hash = createHash(line)
|
||||
local selectionNum = tonumber(hash:sub(1, 8), 16)
|
||||
|
|
@ -122,48 +135,68 @@ local function getGaslightingMessageForLineContent(line)
|
|||
return nil
|
||||
end
|
||||
|
||||
-- Update the gaslighting decorations in the current buffer.
|
||||
function M.update_decorations()
|
||||
if not M.is_enabled or shouldIgnoreFileType() then
|
||||
return
|
||||
-- Check if the line is a comment based on the filetype
|
||||
-- TODO: this should be replaced with Treesitter native method of checking for comments
|
||||
-- in the future. I don't care to set up Treesitter for testing, so this is what we have.
|
||||
local function isComment(line)
|
||||
local filetype = vim.bo.filetype
|
||||
local trimmed_line = vim.trim(line)
|
||||
|
||||
-- Lua: '--' for comments
|
||||
if filetype == "lua" then
|
||||
return vim.fn.match(trimmed_line, "^--") ~= -1
|
||||
end
|
||||
|
||||
-- Python: '#' for comments
|
||||
if filetype == "python" then
|
||||
return vim.fn.match(trimmed_line, "^#") ~= -1
|
||||
end
|
||||
|
||||
-- C/C++/JavaScript: '//' for comments
|
||||
if filetype == "c" or filetype == "cpp" or filetype == "javascript" or filetype == "java" then
|
||||
return vim.fn.match(trimmed_line, "^//") ~= -1
|
||||
end
|
||||
|
||||
-- If no specific filetype matches, return false (i.e., not a comment)
|
||||
return false
|
||||
end
|
||||
|
||||
--- Update the gaslighting decorations in the current buffer
|
||||
function M.update_decorations()
|
||||
if not M.is_enabled or shouldIgnoreFileType() then return end
|
||||
|
||||
local bufnr = api.nvim_get_current_buf()
|
||||
-- Clear previous extmarks in our namespace.
|
||||
api.nvim_buf_clear_namespace(bufnr, ns, 0, -1)
|
||||
api.nvim_buf_clear_namespace(bufnr, ns, 0, -1) -- Clear previous decorations
|
||||
local lines = api.nvim_buf_get_lines(bufnr, 0, -1, false)
|
||||
|
||||
for i, line in ipairs(lines) do
|
||||
local trimmed = vim.trim(line)
|
||||
if #trimmed >= config.min_line_length then
|
||||
-- Skip dummy comment lines (detection based on starting patterns)
|
||||
-- TODO: use Treesitter for this
|
||||
if not (trimmed:find("^//") or trimmed:find("^#") or trimmed:find("^/%*") or trimmed:find("^%*") or trimmed:find("^<!--")) then
|
||||
local message = getGaslightingMessageForLineContent(trimmed)
|
||||
if message then
|
||||
local first_non_whitespace = line:find("%S")
|
||||
if first_non_whitespace then
|
||||
api.nvim_buf_set_extmark(bufnr, ns, i - 1, first_non_whitespace - 1, {
|
||||
virt_text = { { message, config.highlight } },
|
||||
virt_text_pos = "eol",
|
||||
hl_mode = "combine",
|
||||
})
|
||||
end
|
||||
|
||||
-- Skip comment lines entirely
|
||||
if #trimmed >= config.min_line_length and not isComment(trimmed) then
|
||||
local message = getGaslightingMessageForLineContent(trimmed)
|
||||
if message then
|
||||
local first_non_whitespace = line:find("%S")
|
||||
if first_non_whitespace then
|
||||
api.nvim_buf_set_extmark(bufnr, ns, i - 1, first_non_whitespace - 1, {
|
||||
virt_text = { { message, config.highlight } },
|
||||
virt_text_pos = "eol",
|
||||
hl_mode = "combine",
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Debounce update: schedules an update after a delay.
|
||||
--- Debounced update function
|
||||
function M.schedule_update()
|
||||
if timer then
|
||||
timer:stop()
|
||||
timer:close()
|
||||
end
|
||||
timer = vim.loop.new_timer()
|
||||
timer:start(config.debounce_delay, 0, vim.schedule_wrap(function()
|
||||
M.update_decorations()
|
||||
end))
|
||||
timer:start(config.debounce_delay, 0, vim.schedule_wrap(M.update_decorations))
|
||||
end
|
||||
|
||||
return M
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue