From b4cd8ff19706220fed59a34ef3cb4515ab4b5792 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Wed, 5 Mar 2025 04:12:40 +0300 Subject: [PATCH] add lua-language-server types; fix comment logic --- lua/syntax-gaslighting.lua | 161 ++++++++++++++++++++++--------------- 1 file changed, 97 insertions(+), 64 deletions(-) diff --git a/lua/syntax-gaslighting.lua b/lua/syntax-gaslighting.lua index 78e03c0..0b431a6 100644 --- a/lua/syntax-gaslighting.lua +++ b/lua/syntax-gaslighting.lua @@ -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("^