Packages

The package you need to build plugins for the lexical language server

Current section

Files

Jump to
lexical_plugin lib lexical plugin v1 diagnostic.ex
Raw

lib/lexical/plugin/v1/diagnostic.ex

defmodule Lexical.Plugin.V1.Diagnostic do
@moduledoc """
A use-able diagnostic plugin module
A diagnostic result examines a `diagnosable` data structure and emits
a list of `Lexical.Plugin.V1.Diagnostic.Result` structs.
Diagnostic plugins are called in two places. When a file is saved, they're called with the
`Lexical.Project` struct and are expected to perform diagnostics across the whole project.
On receipt of a change to a `Lexical.Document`, they're called with the changed document and
are expected to analyze that document and emit any diagnostics they find.
Both calls to `diagnose` operate on tight deadlines, though when `diagnose` is called with a `Lexical.Project`,
the deadline is much longer than it is when `diagnose` is called with a `Lexical.Document`. This is because
analyzing a project should take a lot longer than analyzing a single document. Currently, Lexical sets
a deadline of around a second on project-level diagnostics and a tens-of-milliseconds deadline on document
plugins.
## Errors and Timeouts
Plugins are very sensitive to errors and are disabled by lexical if they cause too many. At present,
a disabled plugin can only be re-enabled by restarting lexical, so ensure that your plugin doesn't crash,
and if you don't have errors, return `{:ok, []}` rather than some error response.
## Plugin lifecycle
When a plugin is started, Lexical calls the `init/0` function, which can perform setup actions, like starting
the application associated with the plugin. Implementing this function is optional.
From then on, the plugin will be resident and run in tasks whenever files are changed or saved.
## A simple do-nothing plugin
```
defmodule DoesNothing do
use Lexical.Plugin.V1.Diagnostic
def diagnose(%Lexical.Document{} = doc) do
{:ok, []}
end
def diagnose(%Lexical.Project{}) do
{:ok, []}
end
end
```
Check out the README for a plugin that does something more.
"""
alias Lexical.Document
alias Lexical.Plugin.V1.Diagnostic
alias Lexical.Project
@type state :: any()
@type results :: [Diagnostic.Result.t()]
@type diagnosable :: Project.t() | Document.t()
@type diagnostics_reply :: {:ok, results} | {:error, any()}
@callback diagnose(diagnosable) :: diagnostics_reply()
defmacro __using__(opts) do
name = Keyword.get(opts, :name)
quote location: :keep do
require Logger
Module.register_attribute(__MODULE__, :lexical_plugin, persist: true)
@lexical_plugin true
@behaviour unquote(__MODULE__)
def __lexical_plugin__ do
__MODULE__
end
def __plugin_type__ do
:diagnostic
end
def name do
unquote(name)
end
def init do
:ok
end
def diagnose(_) do
{:ok, []}
end
defoverridable init: 0, diagnose: 1
end
end
end