Skip to content

Public API to get individual fixes #5353

@golergka

Description

@golergka

Search before asking

  • I searched the issues and found no similar issues.

Description

I want to have a public API to get a list of errors with fixes for them, which could be displayed in an IDE.

I've been writing code that would use internal, undocumented APIs to achieve this, but I've ran into some problems.

I can get a list of errors with fixes like this:

from sqlfluff.core.linter import Linter

# ...some many lines later...

linter = Linter(config=config)
result = linter.lint_string_wrapped(args.content)
violations = result.paths[0].files[0].violations
for error in violations:
    if isinstance(error, SQLLintError):
        fixes: List[SQLFluffLintFix] = error.fixes
        # TODO Convert fixes
    else:
        logger.trace("Not SQLLintError")

And I was trying to come up with a function that would convert a LintFix instance to a serialisable representation, which could then be used in a code editor:

from sqlfluff.core.rules.base import LintFix as SQLFluffLintFix


# These data classes map to Monaco or other potential editor's types

class Range:
    start_line_number: int
    start_column: int
    end_line_number: int
    end_column: int


class LintFixEdit:
    range: Range
    text: str


class LintFix:
    title: str
    edits: List[LintFixEdit]


def sqlfluff_to_editor_lint_fix(
    sqlfluff_lint_fix: SQLFluffLintFix,
) -> Optional[LintFix]:
    popsql_edits: List[LintFixEdit] = []

    # PROBLEM
    # Position marker doesn't always exist
    anchor_pos = sqlfluff_lint_fix.anchor.pos_marker
    if not anchor_pos:
        raise ValueError(
            f"Anchor position not found for fix: {sqlfluff_lint_fix}"
        )

    range_start_line = anchor_pos.line_no
    range_start_column = anchor_pos.line_pos

    edit_text = ""

    if sqlfluff_lint_fix.edit_type == "delete":
        # Nothing to do, text stays empty and range defines the segment to delete
        pass
    elif sqlfluff_lint_fix.edit_type in [
        "create_before",
        "create_after",
        "replace",
    ]:
        if not sqlfluff_lint_fix.edit:
            raise ValueError(
                f"Edit segments are missing for a non-delete operation: {sqlfluff_lint_fix}"
            )

        for edit_segment in sqlfluff_lint_fix.edit:
            edit_text += edit_segment.raw

            # PROBLEM
            # How to get a range end position?

The core of the problem with this approach is that BaseSegment class is not actually a position in source code, but some kind of very representation. This makes sense for a parser, but I didn't understand how to convert BaseSegment to a pair of start and end line and column numbers.

Use case

I want to display sqlfluff fixes as "quick fixes" in a code editor, and be able to instantly apply those edits when user selects one (without running sqlfluff again).

Screenshot 2023-10-25 at 12 47 27

(In my particular case, I will use Monaco editor).

Dialect

Not specific to any dialect

Are you willing to work on and submit a PR to address the issue?

  • Yes I am willing to submit a PR!

Code of Conduct

Metadata

Metadata

Labels

enhancementNew feature or request

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions