From 480b1a3480a69002996645bc8e9a9da92262c012 Mon Sep 17 00:00:00 2001 From: Thomas485 Date: Sat, 6 Jul 2024 11:19:44 +0200 Subject: [PATCH] the code --- README.md | 32 ++++++++- lua/comment_navigator/init.lua | 126 +++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 lua/comment_navigator/init.lua diff --git a/README.md b/README.md index 0c84f20..950fcf5 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,32 @@ # comment-navigator -A simple nvim plugin to jump between comments. + +A simple nvim plugin to jump between (special) comments. + +## Preview + +![commentnavigator](https://github.com/Thomas485/comment-navigator/assets/1681511/bfeb5a64-145d-4df0-98c9-3196d646dc0c) + +## Setup +This is my current setup: +```lua +local comment_navigator = require('comment_navigator') + +local comment_filetypes = { + {"*.{odin,c,cc,cpp,cxx}", comment_navigator.regex.c}, + {"*.lua", comment_navigator.regex.lua}, + {"*.py", comment_navigator.regex.python} +} + +for _, cf in ipairs(comment_filetypes) do + local cn = comment_navigator.setup({ + regex = cf[2] + }) + vim.api.nvim_create_autocmd("BufEnter", { + pattern = cf[1], + callback = function() + vim.keymap.set('n', 'c', cn.open, { noremap = true, silent = true }) + end + }) +end +``` + diff --git a/lua/comment_navigator/init.lua b/lua/comment_navigator/init.lua new file mode 100644 index 0000000..f327683 --- /dev/null +++ b/lua/comment_navigator/init.lua @@ -0,0 +1,126 @@ +local plenary = require("plenary") + +local M = {} + +local function filter_comments(settings, content) + local cursor_position = vim.api.nvim_win_get_cursor(0) + local new_cursor = {1,0} + + local numbers, values = {}, {} + local indentations = {} + + for i, v in ipairs(content) do + local indent, line = string.match(v, settings.regex) + if line then + if settings.keep_indent then + numbers[#numbers+1] = i + values[#values+1] = indent .. line + table.insert(indentations, #indent) + else + numbers[#numbers+1] = i + values[#values+1] = line + end + end + + -- set the cursor position to the comment under the cursor + -- or to the previous comment if not on a comment directly. + if new_cursor[1] == 1 then + if i == cursor_position[1] then + new_cursor = {math.max(#numbers,1), indentations[#indentations] or 0} + end + end + end + + -- strip down indentation + if settings.keep_indent then + local min_indentation = math.huge + for _, indent in ipairs(indentations) do + min_indentation = min_indentation < indent and min_indentation or indent + end + for i = 1, #values, 1 do + values[i] = string.sub(values[i], min_indentation+1) + end + end + return numbers, values, new_cursor +end + +function M.setup(options) + -- create a new module to support multiple file types + local module = {} + + -- default settings + module.settings = { + regex = M.regex.c, -- the regex used to extract the comments (c-style default) + line_numbers = true, -- show the line numbers in the list + width = 100, -- width of the window + height = 50, -- height of the window + borderchars = { "─", "│", "─", "│", "╭", "╮", "╯", "╰" }, -- the borders, nil means no border + keep_indent = true, -- preserve the indentation of the file (shows the values in a hierarchical manner) + } + + module.settings = vim.tbl_deep_extend("force", module.settings, options) + + -- main entry point, opens the popup window + function module.open() + local settings = module.settings + + local content_buffer = vim.api.nvim_buf_get_lines(0, 0, vim.api.nvim_buf_line_count(0), false) + local line_numbers, content, cursor_position = filter_comments(settings, content_buffer) + + -- FIXME: this is a hotfix + -- removes an empty line at the end of the buffer + if content[#content] == "" then + table.remove(content, #content) + end + + -- TODO: avoid module to be able to open multiple popups at the same time + module.state = line_numbers + + -- create the buffer for the popup window + local buffer = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(buffer, -2, -1, true, content) + vim.api.nvim_buf_set_option(buffer, 'readonly', true) + vim.api.nvim_buf_set_keymap(buffer, "n", "", "", { + callback = function() + module.go(buffer) + end + }) + vim.api.nvim_buf_set_keymap(buffer, "n", "", + "lua vim.api.nvim_buf_delete(" .. buffer .. ", {})", {}) + + local win, _ = plenary.popup.create(buffer, { + title = "comment-navigator", + minwidth = settings.width, + minheight = settings.height, + maxheight = settings.height, + maxwidth = settings.width, + borderchars = settings.borderchars, + }) + + if settings.line_numbers then + vim.api.nvim_win_set_option(win, "number", true) + end + + vim.api.nvim_win_set_cursor(win, cursor_position) + end + + -- navigates to the comment under the cursor + function module.go(buffer) + local idx = vim.api.nvim__buf_stats(buffer).current_lnum + vim.api.nvim_buf_delete(buffer, {}) + + local line = module.state[idx] + vim.api.nvim_win_set_cursor(0,{line,0}) + end + + return module +end + +M.regex = { + c = "(%s*)///%s*(.*)%s*", -- /// comment + lua = "(%s*)%-%-%-%s*(.*)%s*", -- --- comment + python = "(%s*)#:%s*(.*)%s*", -- #: comment (not ## because of autoformatters…) + erb = "(%s*)<%%%s?# *(.*) *%%>" -- <%# comment %> +} + +return M