Skip to content

Linting

The :lint module displays diagnostics (errors, warnings, hints) as inline decorations and in an optional panel.

Basic setup

Create a linter extension with a function that returns diagnostics:

private val myLinter: LintSource = { session ->
    val diagnostics = mutableListOf<Diagnostic>()
    val doc = session.state.doc
    for (i in 1..doc.lines) {
        val line = doc.line(LineNumber(i))
        val text = line.text
        // Long line warning
        if (text.length > 80) {
            diagnostics.add(
                Diagnostic(
                    from = line.from + 80,
                    to = line.to,
                    severity = Severity.WARNING,
                    message = "Line exceeds 80 characters (${text.length})",
                    source = "line-length"
                )
            )
        }
        // TODO/FIXME markers
        for (match in todoPattern.findAll(text)) {
            diagnostics.add(
                Diagnostic(
                    from = line.from + match.range.first,
                    to = line.from + match.range.last + 1,
                    severity = Severity.INFO,
                    message = "${match.value} comment found",
                    source = "todo-finder"
                )
            )
        }
    }
    println("[LintDemo] linter returned ${diagnostics.size} diagnostics")
    diagnostics
}

Diagnostic properties

Each Diagnostic has:

Property Description
from Start position
to End position
severity Severity.HINT, INFO, WARNING, or ERROR
message The diagnostic message
source Optional source identifier (e.g. "eslint")
actions Optional list of fix actions
markClass Optional CSS class override for the mark decoration

Severity levels

enum class Severity { HINT, INFO, WARNING, ERROR }

Each severity level gets a different underline style in the editor.

Lint configuration

LintConfig controls how the linter runs:

linter(myLintSource, LintConfig(
    delay = 750,        // milliseconds before re-running after changes
    autoPanel = false   // automatically open the diagnostics panel
))

Lint gutter

Show severity icons in the gutter:

lintGutter()

Diagnostic actions

Actions offer quick fixes that users can apply:

Diagnostic(
    from = pos,
    to = pos + word.length,
    severity = Severity.ERROR,
    message = "'$word' is misspelled",
    actions = listOf(
        Action(name = "Fix") { view ->
            view.dispatch(TransactionSpec(
                changes = ChangeSpec.Single(
                    pos, pos + word.length,
                    insert = InsertContent.StringContent(corrected)
                )
            ))
        }
    )
)

Programmatic diagnostics

You can also push diagnostics without a linter function:

forceLinting(view)

Commands

Command Default binding Action
openLintPanel Open the diagnostics panel
closeLintPanel Close the diagnostics panel
nextDiagnostic F8 Jump to next diagnostic

Based on the CodeMirror Lint example.