diff --git a/README.md b/README.md index e53b5e7..249b0a2 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,7 @@ pylsp = { format = { "I" }, -- Rules that are marked as fixable by ruff that should be fixed when running textDocument/formatting severities = { ["D212"] = "I" }, -- Optional table of rules where a custom severity is desired unsafeFixes = false, -- Whether or not to offer unsafe fixes as code actions. Ignored with the "Fix All" action + unfixable = { "F401" }, -- Rules that are excluded when checking the code actions (including the "Fix All" action) -- Rules that are ignored when a pyproject.toml or ruff.toml is present: lineLength = 88, -- Line length to pass to ruff checking and formatting @@ -93,6 +94,7 @@ pylsp = { "D212": "I" }, "unsafeFixes": false, + "unfixable": [ "F401" ], "lineLength": 88, "exclude": ["__about__.py"], "select": ["F"], @@ -143,7 +145,7 @@ The `Fix all` code action *only* consideres safe fixes. The log level can be set via the `cmd` option of `pylsp`: ```lua -lspconfig.pylsp.setup { +vim.lsp.config("pylsp", { cmd = {"pylsp", "-vvv", "--log-file", "/tmp/lsp.log"}, settings = { pylsp = { @@ -154,5 +156,5 @@ lspconfig.pylsp.setup { } } } -} +}) ``` diff --git a/pylsp_ruff/plugin.py b/pylsp_ruff/plugin.py index e58c68f..2c3f3d9 100644 --- a/pylsp_ruff/plugin.py +++ b/pylsp_ruff/plugin.py @@ -628,6 +628,9 @@ def build_check_arguments( if settings.unsafe_fixes: args.append("--unsafe-fixes") + if settings.unfixable: + args.append(f"--unfixable={','.join(settings.unfixable)}") + if settings.exclude: args.append(f"--exclude={','.join(settings.exclude)}") @@ -730,8 +733,8 @@ def load_settings(workspace: Workspace, document_path: str) -> PluginSettings: """ config = workspace._config - _plugin_settings = config.plugin_settings("ruff", document_path=document_path) - plugin_settings = converter.structure(_plugin_settings, PluginSettings) + plugin_settings = config.plugin_settings("ruff", document_path=document_path) + plugin_settings = converter.structure(plugin_settings, PluginSettings) pyproject_file = find_parents( workspace.root_path, document_path, ["pyproject.toml"] @@ -764,6 +767,7 @@ def load_settings(workspace: Workspace, document_path: str) -> PluginSettings: extend_select=plugin_settings.extend_select, format=plugin_settings.format, severities=plugin_settings.severities, + unfixable=plugin_settings.unfixable, ) return plugin_settings diff --git a/pylsp_ruff/settings.py b/pylsp_ruff/settings.py index 27af16f..c274dac 100644 --- a/pylsp_ruff/settings.py +++ b/pylsp_ruff/settings.py @@ -27,6 +27,8 @@ class PluginSettings: preview: bool = False unsafe_fixes: bool = False + unfixable: Optional[List[str]] = None + severities: Optional[Dict[str, str]] = None target_version: Optional[str] = None diff --git a/tests/test_code_actions.py b/tests/test_code_actions.py index 809198e..9d97d58 100644 --- a/tests/test_code_actions.py +++ b/tests/test_code_actions.py @@ -50,6 +50,14 @@ def f(): "Ruff: Fix All (safe fixes)", ] +codeactions_unfixable = [ + "Ruff (F401): Remove unused import: `os`", + "Ruff (F401): Disable for this line", + # "Ruff (F841): Remove assignment to unused variable `a` (unsafe)", + "Ruff (F841): Disable for this line", + "Ruff: Fix All (safe fixes)", +] + codeactions_import = [ "Ruff: Organize imports", "Ruff: Fix All (safe fixes)", @@ -85,6 +93,24 @@ def test_ruff_code_actions(workspace): assert sorted(codeactions) == sorted(action_titles) +def test_ruff_code_actions_unfixable(workspace): + _, doc = temp_document(codeaction_str, workspace) + + workspace._config.update( + {"plugins": {"ruff": {"select": ["F"], "unfixable": ["F841"]}}} + ) + diags = ruff_lint.pylsp_lint(workspace, doc) + range_ = cattrs.unstructure( + Range(start=Position(line=0, character=0), end=Position(line=0, character=0)) + ) + actions = ruff_lint.pylsp_code_actions( + workspace._config, workspace, doc, range=range_, context={"diagnostics": diags} + ) + actions = converter.structure(actions, List[CodeAction]) + action_titles = list(map(lambda action: action.title, actions)) + assert sorted(codeactions_unfixable) == sorted(action_titles) + + def test_import_action(workspace): workspace._config.update( {