Skip to content

Commit

Permalink
Add support for disabling the linter (astral-sh#361)
Browse files Browse the repository at this point in the history
## Summary

This PR enables users to specify `"ruff.lint.enable": false` to use the
LSP (or extension) solely for formatting.

"Organize Imports" is still supported even when the linter is disabled.

See: astral-sh/ruff-vscode#329.

## Test Plan

- Ran the VS Code extension.
- Verified that diagnostics appeared for unused imports.
- Set `"ruff.lint.enable": false`.
- Verified that the diagnostics disappeared.
- Ran "Organize Imports".
- Verified that the imports were sorted.
- Ran "Fix All".
- Verified that the imports (which were unused) were not removed.
  • Loading branch information
charliermarsh authored Jan 25, 2024
1 parent ed12cbf commit 523bbfc
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 42 deletions.
2 changes: 1 addition & 1 deletion justfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ install:
pip install --no-deps -r requirements-dev.txt

fmt:
ruff check --fix ./ruff_lsp ./tests
ruff format ./ruff_lsp ./tests
ruff check --fix ./ruff_lsp ./tests

check:
ruff check ./ruff_lsp ./tests
Expand Down
126 changes: 85 additions & 41 deletions ruff_lsp/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
UserSettings,
WorkspaceSettings,
lint_args,
lint_enable,
lint_run,
)
from ruff_lsp.utils import RunResult
Expand Down Expand Up @@ -440,7 +441,11 @@ async def did_open(params: DidOpenTextDocumentParams) -> None:
document = Document.from_text_document(
LSP_SERVER.workspace.get_text_document(params.text_document.uri)
)
diagnostics = await _lint_document_impl(document)
settings = _get_settings_by_document(document.path)
if not lint_enable(settings):
return

diagnostics = await _lint_document_impl(document, settings)
LSP_SERVER.publish_diagnostics(document.uri, diagnostics)


Expand All @@ -456,22 +461,30 @@ def did_close(params: DidCloseTextDocumentParams) -> None:
async def did_save(params: DidSaveTextDocumentParams) -> None:
"""LSP handler for textDocument/didSave request."""
text_document = LSP_SERVER.workspace.get_text_document(params.text_document.uri)
if lint_run(_get_settings_by_document(text_document.path)) in (
settings = _get_settings_by_document(text_document.path)
if not lint_enable(settings):
return

if lint_run(settings) in (
Run.OnType,
Run.OnSave,
):
document = Document.from_text_document(text_document)
diagnostics = await _lint_document_impl(document)
diagnostics = await _lint_document_impl(document, settings)
LSP_SERVER.publish_diagnostics(document.uri, diagnostics)


@LSP_SERVER.feature(TEXT_DOCUMENT_DID_CHANGE)
async def did_change(params: DidChangeTextDocumentParams) -> None:
"""LSP handler for textDocument/didChange request."""
text_document = LSP_SERVER.workspace.get_text_document(params.text_document.uri)
if lint_run(_get_settings_by_document(text_document.path)) == Run.OnType:
settings = _get_settings_by_document(text_document.path)
if not lint_enable(settings):
return

if lint_run(settings) == Run.OnType:
document = Document.from_text_document(text_document)
diagnostics = await _lint_document_impl(document)
diagnostics = await _lint_document_impl(document, settings)
LSP_SERVER.publish_diagnostics(document.uri, diagnostics)


Expand All @@ -486,7 +499,11 @@ async def did_open_notebook(params: DidOpenNotebookDocumentParams) -> None:
return

document = Document.from_notebook_document(notebook_document)
diagnostics = await _lint_document_impl(document)
settings = _get_settings_by_document(document.path)
if not lint_enable(settings):
return

diagnostics = await _lint_document_impl(document, settings)

# Publish diagnostics for each cell.
for cell_idx, diagnostics in _group_diagnostics_by_cell(diagnostics).items():
Expand Down Expand Up @@ -551,27 +568,34 @@ async def _did_change_or_save_notebook(
return

document = Document.from_notebook_document(notebook_document)
if lint_run(_get_settings_by_document(document.path)) not in run_types:
settings = _get_settings_by_document(document.path)
if not lint_enable(settings):
return

cell_diagnostics = _group_diagnostics_by_cell(await _lint_document_impl(document))

# Publish diagnostics for every code cell, replacing the previous diagnostics.
# This is required here because a cell containing diagnostics in the first run
# might not contain any diagnostics in the second run. In that case, we need to
# clear the diagnostics for that cell which is done by publishing empty diagnostics.
for cell_idx, cell in enumerate(notebook_document.cells):
if cell.kind is not NotebookCellKind.Code:
continue
LSP_SERVER.publish_diagnostics(
cell.document,
# The cell indices are 1-based in Ruff.
cell_diagnostics.get(cell_idx + 1, []),
if lint_run(settings) in run_types:
cell_diagnostics = _group_diagnostics_by_cell(
await _lint_document_impl(document, settings)
)

# Publish diagnostics for every code cell, replacing the previous diagnostics.
# This is required here because a cell containing diagnostics in the first run
# might not contain any diagnostics in the second run. In that case, we need to
# clear the diagnostics for that cell which is done by publishing empty
# diagnostics.
for cell_idx, cell in enumerate(notebook_document.cells):
if cell.kind is not NotebookCellKind.Code:
continue
LSP_SERVER.publish_diagnostics(
cell.document,
# The cell indices are 1-based in Ruff.
cell_diagnostics.get(cell_idx + 1, []),
)


async def _lint_document_impl(document: Document) -> list[Diagnostic]:
result = await _run_check_on_document(document)
async def _lint_document_impl(
document: Document, settings: WorkspaceSettings
) -> list[Diagnostic]:
result = await _run_check_on_document(document, settings)
if result is None:
return []

Expand Down Expand Up @@ -883,6 +907,7 @@ def document_from_kind(uri: str, kind: str) -> Document:
):
workspace_edit = await _fix_document_impl(
document_from_kind(params.text_document.uri, kind),
settings,
only=["I001", "I002"],
)
if workspace_edit:
Expand All @@ -898,8 +923,8 @@ def document_from_kind(uri: str, kind: str) -> Document:
else:
return []

if settings["fixAll"]:
# Generate the "Ruff: Fix All" edit.
# If the linter is enabled, generate the "Ruff: Fix All" edit.
if lint_enable(settings) and settings["fixAll"]:
for kind in (
CodeActionKind.SourceFixAll,
SOURCE_FIX_ALL_RUFF,
Expand All @@ -912,7 +937,8 @@ def document_from_kind(uri: str, kind: str) -> Document:
and kind in params.context.only
):
workspace_edit = await _fix_document_impl(
document_from_kind(params.text_document.uri, kind)
document_from_kind(params.text_document.uri, kind),
settings,
)
if workspace_edit:
return [
Expand All @@ -935,8 +961,10 @@ def document_from_kind(uri: str, kind: str) -> Document:

actions: list[CodeAction] = []

# Add "Ruff: Autofix" for every fixable diagnostic.
if settings.get("codeAction", {}).get("fixViolation", {}).get("enable", True):
# If the linter is enabled, add "Ruff: Autofix" for every fixable diagnostic.
if lint_enable(settings) and settings.get("codeAction", {}).get(
"fixViolation", {}
).get("enable", True):
if not params.context.only or CodeActionKind.QuickFix in params.context.only:
# This is a text document representing either a Python file or a
# Notebook cell.
Expand Down Expand Up @@ -967,8 +995,10 @@ def document_from_kind(uri: str, kind: str) -> Document:
),
)

# Add "Disable for this line" for every diagnostic.
if settings.get("codeAction", {}).get("disableRuleComment", {}).get("enable", True):
# If the linter is enabled, add "Disable for this line" for every diagnostic.
if lint_enable(settings) and settings.get("codeAction", {}).get(
"disableRuleComment", {}
).get("enable", True):
if not params.context.only or CodeActionKind.QuickFix in params.context.only:
# This is a text document representing either a Python file or a
# Notebook cell.
Expand Down Expand Up @@ -1047,6 +1077,7 @@ def document_from_kind(uri: str, kind: str) -> Document:
else:
workspace_edit = await _fix_document_impl(
Document.from_cell_or_text_uri(params.text_document.uri),
settings,
only=["I001", "I002"],
)
if workspace_edit:
Expand All @@ -1060,8 +1091,8 @@ def document_from_kind(uri: str, kind: str) -> Document:
),
)

if settings["fixAll"]:
# Add "Ruff: Fix All" as a supported action.
# If the linter is enabled, add "Ruff: Fix All" as a supported action.
if lint_enable(settings) and settings["fixAll"]:
if not params.context.only or (
CodeActionKind.SourceFixAll in params.context.only
):
Expand All @@ -1077,7 +1108,8 @@ def document_from_kind(uri: str, kind: str) -> Document:
)
else:
workspace_edit = await _fix_document_impl(
Document.from_cell_or_text_uri(params.text_document.uri)
Document.from_cell_or_text_uri(params.text_document.uri),
settings,
)
if workspace_edit:
actions.append(
Expand Down Expand Up @@ -1111,12 +1143,18 @@ async def resolve_code_action(params: CodeAction) -> CodeAction:
settings["organizeImports"]
and params.kind == CodeActionKind.SourceOrganizeImports
):
# Generate the "Ruff: Organize Imports" edit
params.edit = await _fix_document_impl(document, only=["I001", "I002"])
# Generate the "Organize Imports" edit
params.edit = await _fix_document_impl(
document, settings, only=["I001", "I002"]
)

elif settings["fixAll"] and params.kind == CodeActionKind.SourceFixAll:
# Generate the "Ruff: Fix All" edit.
params.edit = await _fix_document_impl(document)
elif (
lint_enable(settings)
and settings["fixAll"]
and params.kind == CodeActionKind.SourceFixAll
):
# Generate the "Fix All" edit.
params.edit = await _fix_document_impl(document, settings)

return params

Expand All @@ -1125,7 +1163,11 @@ async def resolve_code_action(params: CodeAction) -> CodeAction:
async def apply_autofix(arguments: tuple[TextDocument]):
uri = arguments[0]["uri"]
document = Document.from_uri(uri)
workspace_edit = await _fix_document_impl(document)
settings = _get_settings_by_document(document.path)
if not lint_enable(settings):
return

workspace_edit = await _fix_document_impl(document, settings)
if workspace_edit is None:
return
LSP_SERVER.apply_edit(workspace_edit, "Ruff: Fix all auto-fixable problems")
Expand All @@ -1135,7 +1177,8 @@ async def apply_autofix(arguments: tuple[TextDocument]):
async def apply_organize_imports(arguments: tuple[TextDocument]):
uri = arguments[0]["uri"]
document = Document.from_uri(uri)
workspace_edit = await _fix_document_impl(document, only=["I001", "I002"])
settings = _get_settings_by_document(document.path)
workspace_edit = await _fix_document_impl(document, settings, only=["I001", "I002"])
if workspace_edit is None:
return
LSP_SERVER.apply_edit(workspace_edit, "Ruff: Format imports")
Expand Down Expand Up @@ -1196,11 +1239,13 @@ async def format_document(params: DocumentFormattingParams) -> list[TextEdit] |

async def _fix_document_impl(
document: Document,
settings: WorkspaceSettings,
*,
only: Sequence[str] | None = None,
) -> WorkspaceEdit | None:
result = await _run_check_on_document(
document,
settings,
extra_args=["--fix"],
only=only,
)
Expand Down Expand Up @@ -1707,6 +1752,7 @@ def _executable_version(executable: str) -> Version:

async def _run_check_on_document(
document: Document,
settings: WorkspaceSettings,
*,
extra_args: Sequence[str] = [],
only: Sequence[str] | None = None,
Expand All @@ -1716,8 +1762,6 @@ async def _run_check_on_document(
log_warning(f"Skipping standard library file: {document.path}")
return None

settings = _get_settings_by_document(document.path)

executable = _find_ruff_binary(settings, VERSION_REQUIREMENT_LINTER)
argv: list[str] = CHECK_ARGS + list(extra_args)

Expand Down
11 changes: 11 additions & 0 deletions ruff_lsp/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ class CodeAction(TypedDict, total=False):


class Lint(TypedDict, total=False):
enable: bool
"""Whether to enable linting."""

args: list[str]
"""Additional command-line arguments to pass to `ruff check`."""

Expand Down Expand Up @@ -110,3 +113,11 @@ def lint_run(settings: UserSettings) -> Run:
return Run(settings["run"])
else:
return Run.OnType


def lint_enable(settings: UserSettings) -> bool:
"""Get the `lint.enable` setting from the user settings."""
if "lint" in settings and "enable" in settings["lint"]:
return settings["lint"]["enable"]
else:
return True

0 comments on commit 523bbfc

Please sign in to comment.