Skip to content

Commit

Permalink
feat: add documentation for plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
Nerixyz committed Dec 4, 2024
1 parent 71abda8 commit f916dbc
Show file tree
Hide file tree
Showing 22 changed files with 1,194 additions and 0 deletions.
Binary file added docs/images/plugins/enable-hello-world.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/plugins/settings-enable.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
130 changes: 130 additions & 0 deletions docs/plugins/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# Plugins Overview

Since version 2.5.2, you're able to extend Chatterino with Lua plugins. They allow you to extend the functionality of Chatterino in various ways, such as adding new commands or custom tab-completions.

<!-- prettier-ignore -->
!!! note
Version 2.5.2 is not yet released. You can try out the plugin system by downloading the latest [nightly build](../Help.md#what-is-nightly-and-how-to-use-install-it).

## Getting Started

Plugins are disabled by default. To enable them, open the settings, go to `Plugins` and check the `Enable plugins` checkbox.
If you don't see such a checkbox, you're likely using an older version of Chatterino.

<details><summary>Screenshot</summary>

<img alt="Chatterino settings" src="../images/plugins/settings-enable.png">

</details>

In the settings, there's also a button to open the plugin folder (_the `Plugins` directory_). Alternatively, you can navigate to the `Plugins` folder inside the [Chatterino folder](../Settings.md#where-is-my-chatterino-folder-located) manually.

Each plugin gets its own folder in the `Plugins` directory. Inside the folder, you can place the plugin metadata (`info.json`), the Lua script (`init.lua`) with its dependencies, and data files/resources (`data/`).

Your `Plugins` folder might look like this:

```text
Plugins/
├── MyPlugin/
│ ├── data/
│ │ └── my-data-file.txt
│ ├── info.json
│ └── init.lua
└── AnotherPlugin/
├── info.json
└── init.lua
```

### Plugin Metadata

Each plugin must have an `info.json` file. It contains metadata about the plugin, such as the name, author, version, permissions, and description. The following is an example of an `info.json` file:

<!-- prettier-ignore -->
```json title="info.json"
{
"$schema": /* (1)! */"https://raw.githubusercontent.com/Chatterino/chatterino2/master/docs/plugin-info.schema.json",
"name": "My Plugin",
"description": "This is a description of my plugin.",
"authors": ["Your Name"],
"version": "1.0.0",
"license": "MIT"
}
```

1. The schema is not required, but it's recommended to include it. Many editors will use it to provide autocompletion and validation.

Take a look at [the reference](./reference.md) for all available fields.

## Your First Plugin

To create your first plugin, create a new folder inside the `Plugins` directory. Inside the folder, create an `info.json` file (such as the one above) and an `init.lua` file. The `init.lua` file is the entry point of your plugin.

<!-- prettier-ignore-start -->
=== ":octicons-file-code-16: `init.lua`"
```lua
c2.register_command("/hello-plugin", function(ctx)
ctx.channel:add_system_message("Hello from my plugin!") -- (1)!
end)
```

1. In Lua, `#!lua v:method()` is equivalent to `#!lua v.method(v)`. The `add_system_message` method is called on the `ctx.channel` object with the message as an argument.
=== ":material-code-json: `info.json`"
```json
{
"$schema": "https://raw.githubusercontent.com/Chatterino/chatterino2/master/docs/plugin-info.schema.json",
"name": "My Plugin",
"description": "This is a description of my plugin.",
"authors": ["Your Name"],
"version": "1.0.0",
"license": "MIT"
}
```
=== ":material-file-tree: Directory Structure"
```text
Plugins/
└── my-plugin/
├── info.json
└── init.lua
```
<!-- prettier-ignore-end -->

In the plugin settings, you can now enable your plugin by clicking on `Enable`:

<figure markdown="span">
<img alt="Enable plugin" src="../images/plugins/enable-hello-world.png">
</figure>

Now you can use the `/hello-plugin` command in any channel to see the message.

## Your Second Plugin

We can get more advanced by adding arguments to the command. The arguments are stored in the `#!lua ctx.words` table. The first element is the command itself, and the rest are the arguments. The input `/foo bar baz` would result in `#!lua ctx.words` being `#!lua {"/foo", "bar", "baz"}` for example. To recreate the input, you can use `#!lua table.concat(ctx.words, " ", 2)`. The second argument is the starting index, which is 2 in this case, because we want to skip the command itself. Table indices in Lua start at 1.

In the following example, we're going to convert the input to a "serif" version of the input. The serif version is a Unicode representation of the input where each letter is replaced with a math letter. For example, `Chatterino` becomes `𝐂𝐡𝐚𝐭𝐭𝐞𝐫𝐢𝐧𝐨`.

```lua title="init.lua"
local UPPER_A = 0x41 -- 'A'
local LOWER_A = 0x61 -- 'a'
local MATH_UPPER_A = 0x1D400 -- 𝐀
local MATH_LOWER_A = 0x1D41A -- 𝐚

---@param s string
local function to_serif(s)
local codepoint = s:byte(1)
if codepoint >= LOWER_A then
return utf8.char(MATH_LOWER_A + (codepoint - LOWER_A))
end
return utf8.char(MATH_UPPER_A + (codepoint - UPPER_A))
end

c2.register_command("/serif", function(ctx)
local arguments = table.concat(ctx.words, " ", 2)
local serif = arguments:gsub("%a", to_serif)

ctx.channel:send_message(serif, false)
end)
```

Try running `/serif Chatterino` in any channel to see the serif version of the input.

For a more involved example, check out the [Weather example](./weather-example.md).
91 changes: 91 additions & 0 deletions docs/plugins/reference.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Reference

This page provides a reference for Chatterino Lua plugins. It doesn't list the entire API, as the feature is still in development, but it describes the basic structure of a plugin and how to interact with the Chatterino API.

## Directory Structure

Chatterino plugins are located in the `Plugins` directory in the [Chatterino configuration directory](../Settings.md#where-is-my-chatterino-folder-located).
Each plugin uses its own directory with at least an `init.lua` and `info.json` file.
The `info.json` file contains metadata about the plugin, such as the name and version.
The `init.lua` file is the entry point of the plugin and is executed when the plugin is loaded.

```text
Chatterino/
├── Logs/
├── Cache/
├── Misc/
└── Plugins/
├── MyPlugin/
│ ├── data/
│ │ └── my-data-file.txt
│ ├── info.json
│ └── init.lua
└── AnotherPlugin/
├── info.json
└── init.lua
```

## Plugin Metadata

Each plugin must have an `info.json` file. It contains metadata about the plugin, such as the name, author, version, permissions, and description. The following keys are available:

<div class="no-wrap-tbl" markdown>

| Key | Required | Type | Description |
| ------------- | ------------------ | -------------- | ------------------------------------------------------------------------------------------ |
| `$schema` | :x: | `string` | The URL to the JSON schema for the `info.json` file. |
| `name` | :white_check_mark: | `string` | The name of the plugin. |
| `description` | :white_check_mark: | `string` | A description of the plugin. |
| `authors` | :white_check_mark: | `string[]` | An array of authors of the plugin. |
| `version` | :white_check_mark: | `string` | The version of the plugin. Must be SemVer compliant. See [https://semver.org/](semver.org) |
| `license` | :white_check_mark: | `string` | SPDX identifier for license of this plugin. See [https://spdx.org/licenses/](spdx.org) |
| `permissions` | :x: | `Permission[]` | An array of permissions required by the plugin. See [permissions](#permissions). |
| `homepage` | :x: | `string` | The URL to the plugin's homepage (a GitHub repository for example). |
| `tags` | :x: | `string[]` | An array of tags for the plugin. |

</div>

**Example:**

```json title="info.json"
{
"$schema": "https://raw.githubusercontent.com/Chatterino/chatterino2/master/docs/plugin-info.schema.json",
"name": "My Plugin",
"description": "This is a description of my plugin.",
"authors": ["Your Name"],
"version": "1.0.0",
"license": "MIT",
"permissions": [{ "type": "FilesystemRead" }, { "type": "Network" }],
"homepage": "https://github.com/your-username/your-repo",
"tags": ["fun", "utility"]
}
```

### Permissions

A permission is an object with a `"type"` key describing the type of permission. The following types are available:

- `FilesystemRead`: Permission to read files from its `data` directory.
- `FilesystemWrite`: Permission to write files to its `data` directory.
- `Network`: Permission to make network requests.

## Lua API

The Lua API is still in development. From the standard Lua 5.4 API, the following functions are available:

- `io` (except `stdin`, `stdout`, and `stderr`)
- `math`
- `string`
- `table`
- `utf8`

See the [Lua 5.4 manual](https://www.lua.org/manual/5.4/) for more information.

Since the API is still in development, the reference can be found [in the Chatterino repository](https://github.com/Chatterino/chatterino2/blob/master/docs/wip-plugins.md).

### Type Definitions

Chatterino provides type definitions for the [LuaLS](https://luals.github.io/) language server (available as an extension for many popular editors).
The type definitions can be found in the [`docs` directory](https://github.com/Chatterino/chatterino2/blob/master/docs/plugin-meta.lua) of the Chatterino repository.
Currently, you need to copy the file to your plugin directory to get autocompletion and type checking.
In the future, there will be an addon for the language server.
3 changes: 3 additions & 0 deletions docs/plugins/snippets/.lua-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
column_limit: 80
keep_simple_control_block_one_line: false
keep_simple_function_one_line: false
Loading

0 comments on commit f916dbc

Please sign in to comment.