# Lexical.Plugin
Extend lexical's functionality
## Overview
Plugins are used to extend lexical's functionality and provide opt-in diagnostics, completion, and code intelligence features without having to build inside of Lexical itself.
## Plugin Types
The goal of the plugin project is to have different types of plugins that affect lexical in different ways. Presently, only diagnostic plugins are supported. A diagnostic examines a mix project or a document and emits `Lexical.Plugin.V1.Diagnostic.Result` structs to direct the user's attention to any issues it finds.
Diagnostic plugins can be used to integrate code linters like `credo` or to enforce project-specific rules and coding practices.
### Creating a diagnostic plugin
Create a new mix project with `mix new my_plugin`, and edit the `mix.exs` file to include the `:lexical_plugin` app.
```elixir
def deps do
[
{:lexical_plugin, "~> 0.1.0"}
]
end
```
You will also need to add an application `env` key in your `mix.exs` to tell lexical that this is a plugin application. When an application is marked like this, its modules are searched for any that implement plugin behaviours. Add the application key like this:
```elixir
def application do
[
extra_applications: [:logger],
env: [lexical_plugin: true]
]
```
Now we implement the plugin module. In our module, we're going to emit an error on the first line of every file we encounter with a message.
```elixir
defmodule NoisyPlugin do
alias Lexical.Document
alias Lexical.Plugin.V1.Diagnostic
alias Lexical.Project
use Diagnostic, name: :noisy_example_plugin
def diagnose(%Document{} = doc) do
results =
if Document.size(doc) >= 1 do
[build_result(doc.path)]
else
[]
end
{:ok, results}
end
def diagnose(%Project{} = project) do
root_path = Project.root_path(project)
glob =
if umbrella?(root_path) do
"#{root_path}/apps/**/*.ex"
else
"#{root_path}/lib/**/*.ex"
end
results =
glob
|> Path.wildcard()
|> Enum.map(&build_result/1)
{:ok, results}
end
defp build_result(document_path) do
Diagnostic.Result.new(
document_path,
1,
"Do you want to start like this?",
:information,
"Noisy Plugin"
)
end
defp umbrella?(root_path) do
root_path
|> Path.join("apps")
|> File.dir?()
end
end
```
...and that's it. Now, you can install that plugin in your project by adding it to the project's `mix.exs`, and when lexical starts, it will detect the plugin and every file in your project will have a little noisy error at the top.
## Installation
Install this dependency as an optional dep in your project
```elixir
def deps do
[
{:lexical_plugin, "~> 0.1.0", optional: true}
]
end
```
Documentation can be found at <https://hexdocs.pm/lexical_plugin>.