Lexical.Plugin

Extend lexical's functionality

overview

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

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

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.

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:

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.

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

Installation

Install this dependency as an optional dep in your project

def deps do
  [
    {:lexical_plugin, "~> 0.1.0", optional: true}
  ]
end

Documentation can be found at https://hexdocs.pm/lexical_plugin.