From a60690aa5e338c555e2ad53c722326f55b5c200a Mon Sep 17 00:00:00 2001 From: pseudometa <73286100+chrisgrieser@users.noreply.github.com> Date: Thu, 21 Sep 2023 23:37:21 +0200 Subject: [PATCH] feat!: rule lookup directly at documentation sites --- README.md | 47 +++++++++++++++++++++++++++++-------------- lua/rulebook/init.lua | 41 +++++++++++++++++++++++-------------- 2 files changed, 58 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index d81c35e..39f4656 100644 --- a/README.md +++ b/README.md @@ -3,15 +3,18 @@ -Add inline-comments to locally disable diagnostic rules. +Add inline-comments to rules. Lookup rule documentation online. -Most LSPs provide code actions for to do that – this plugin adds commands for linters and LSPs that don't. (As such, this plugin is partially a replacement for [null-ls](https://github.com/jose-elias-alvarez/null-ls.nvim/)'s code action feature.) +Some LSPs provide code actions for to do that – this plugin adds commands for linters and LSPs that don't. - [Features](#features) -- [Supported Linters for adding ignore-comments](#supported-linters-for-adding-ignore-comments) +- [Supported Sources](#supported-sources) + - [For adding ignore comments](#for-adding-ignore-comments) + - [For looking up rule documentation](#for-looking-up-rule-documentation) - [Installation](#installation) - [Configuration](#configuration) +- [Limitations](#limitations) - [Credits](#credits) @@ -21,9 +24,13 @@ Most LSPs provide code actions for to do that – this plugin adds commands for - Perform a web search for a diagnostic rule. - Requires diagnostics provided by a source that supports neovim's builtin diagnostics system (`vim.diagnostic`). nvim's builtin LSP client and [nvim-lint](https://github.com/mfussenegger/nvim-lint) are such sources. -## Supported Linters for adding ignore-comments - - +## Supported Sources +You easily add a custom source via the [plugin configuration](#configuration). However, please consider making a PR to add support for a linter if it is missing. + +[Ignore Rule Data for the supported linters](./lua/rulebook/ignoreRuleData.lua) + +### For adding ignore comments + - selene - shellcheck - vale @@ -32,11 +39,11 @@ Most LSPs provide code actions for to do that – this plugin adds commands for - LTeX - typescript - pylint - -You easily add a custom via the [plugin configuration](#configuration). However, please consider making a PR to add support for a linter if it is missing. - -[Ignore Rule Data for the supported linters](./lua/rulebook/ignoreRuleData.lua) +### For looking up rule documentation +- selene +- shellcheck +- pylint ## Installation @@ -69,7 +76,8 @@ defaultConfig = { comment = "-- selene: allow(%s)", location = "prevLine", }, - -- full list of builtin linters found in README + -- ... (full list of supported sources can be found in the README) + yourCustomSource = { -- %s will be replaced with rule-id -- if location is "encloseLine", needs to be a list of two strings @@ -80,9 +88,18 @@ defaultConfig = { } }, - -- searchUrl for rule lookup. Default is the DuckDuckGo - -- "Ducky Search" (automatically opening first result) - searchUrl = "https://duckduckgo.com/?q=%s+%%21ducky&kl=en-us", + -- %s will be replaced with rule-id + ruleDocumentations = { + selene = "https://kampfkarren.github.io/selene/lints/%s.html" + -- ... (full list of supported sources can be found in the README) + + yourCustomSource = "https://my-docs/%s.hthml" + + -- Search URL when no documentation definition is available for a + -- diagnostic source. "%s" will be replaced with the diagnostic source & code. + -- Default is the DDG "Ducky Search" (automatically opening first result). + fallback = "https://duckduckgo.com/?q=%s+%21ducky&kl=en-us", + } } ``` @@ -90,7 +107,7 @@ defaultConfig = { > The plugin uses `vim.ui.select()`, so the appearance of the rule selection can be customized by using a ui-plugin like [dressing.nvim](https://github.com/stevearc/dressing.nvim). ## Limitations -- The diagnostics have to contain the necessary data, [that is a diagnostic code and diagnostic source](https://neovim.io/doc/user/diagnostic.html#diagnostic-structure). Most LSPs and most linters configured for `nvim-lint` do that, but some diagnostic sources do not (for example `efm-langserver` with certain linters). Please open an issue at the diagnostics provider to fix. +- The diagnostics have to contain the necessary data, [that is a diagnostic code and diagnostic source](https://neovim.io/doc/user/diagnostic.html#diagnostic-structure). Most LSPs and most linters configured for `nvim-lint` do that, but some diagnostic sources do not (for example `efm-langserver` with incorrectly defined errorformat). Please open an issue at the diagnostics provider to fix. - This plugin does *not* hook into `vim.lsp.buf.code_action`, but provides its own independent selector. - As opposed to [null-ls](https://github.com/jose-elias-alvarez/null-ls.nvim)'s code action feature, this plugin does not support arbitrary code actions, but only actions based on a diagnostic. diff --git a/lua/rulebook/init.lua b/lua/rulebook/init.lua index 6ac3f5c..35ba2e4 100644 --- a/lua/rulebook/init.lua +++ b/lua/rulebook/init.lua @@ -5,15 +5,18 @@ local fn = vim.fn -- CONFIG ---@class pluginConfig for this plugin ----@field ignoreRuleComments table ----@field searchUrl string +---@field ignoreComments table +---@field ruleDocs table ---@type pluginConfig local defaultConfig = { - ignoreRuleComments = require("rule-breaker.ignoreRuleData"), - searchUrl = "https://duckduckgo.com/?q=%s+%%21ducky&kl=en-us", + ignoreComments = require("rulebook.rule-data").ignoreComments, + ruleDocs = require("rulebook.rule-data").ruleDocs, } -local config = defaultConfig -- if user does not call setup, use default +defaultConfig.ruleDocs.fallback = "https://duckduckgo.com/?q=%s+%%21ducky&kl=en-us" + +-- if user does not call setup, use default +local config = defaultConfig ---@param userConfig table function M.setup(userConfig) config = vim.tbl_deep_extend("force", defaultConfig, userConfig) end @@ -25,10 +28,11 @@ function M.setup(userConfig) config = vim.tbl_deep_extend("force", defaultConfig ---@param level? "info"|"trace"|"debug"|"warn"|"error" local function notify(msg, level) if not level then level = "info" end - local pluginName = "nvim-rule-breaker" + local pluginName = "nvim-rulebook" vim.notify(msg, vim.log.levels[level:upper()], { title = pluginName }) end +---checks whether rule has id and source, as prescribed in nvim diagnostic structure ---@param diag diagnostic ---@return boolean whether rule is valid local function validDiagObj(diag) @@ -48,11 +52,16 @@ end ---@param diag diagnostic local function searchForTheRule(diag) if not validDiagObj(diag) then return end - local query = (diag.code .. " " .. diag.source) - local escapedQuery = query:gsub(" ", "%%20") - fn.setreg("+", query) - local url = config.searchUrl:format(escapedQuery) + -- determine url to open + local docsUrl = config.ruleDocs[diag.source] + local urlToOpen + if docsUrl then + urlToOpen = docsUrl:format(diag.code) + else + local escapedQuery = (diag.code .. " " .. diag.source):gsub(" ", "%%20") + urlToOpen = config.ruleDocs.fallback:format(escapedQuery) + end -- open with the OS-specific shell command local opener @@ -63,25 +72,27 @@ local function searchForTheRule(diag) elseif fn.has("win64") == 1 or fn.has("win32") == 1 then opener = "start" end - local openCommand = string.format("%s '%s' >/dev/null 2>&1", opener, url) + local openCommand = string.format("%s '%s' >/dev/null 2>&1", opener, urlToOpen) fn.system(openCommand) end ---@param diag diagnostic local function addIgnoreComment(diag) if not validDiagObj(diag) then return end - local ignoreRuleData = config.ignoreRuleComments + -- INFO no need to check that source has rule-data, since filtered beforehand + + local ignoreData = config.ignoreComments -- add rule id and indentation into comment local currentIndent = vim.api.nvim_get_current_line():match("^%s*") - local ignoreComment = ignoreRuleData[diag.source].comment + local ignoreComment = ignoreData[diag.source].comment if type(ignoreComment) == "string" then ignoreComment = { ignoreComment } end for i = 1, #ignoreComment, 1 do ignoreComment[i] = currentIndent .. ignoreComment[i]:format(diag.code) end -- insert the comment - local ignoreLocation = ignoreRuleData[diag.source].location + local ignoreLocation = ignoreData[diag.source].location if ignoreLocation == "prevLine" then local prevLineNum = vim.api.nvim_win_get_cursor(0)[1] - 1 vim.api.nvim_buf_set_lines(0, prevLineNum, prevLineNum, false, ignoreComment) @@ -107,7 +118,7 @@ local function selectRuleInCurrentLine(operation) -- filter diagnostics for which there are no ignore comments defined if operation == addIgnoreComment then curLineDiags = vim.tbl_filter( - function(diag) return config.ignoreRuleComments[diag.source] ~= nil end, + function(diag) return config.ignoreComments[diag.source] ~= nil end, curLineDiags ) end