1
0
Fork 0
mirror of https://github.com/jiriks74/presence.nvim synced 2025-04-08 13:23:00 +02:00

Merge branch 'main' into lazy-plugin-manager

This commit is contained in:
jan Mikowa 2024-04-06 15:58:44 +02:00 committed by GitHub
commit 8b18beb367
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 2264 additions and 1938 deletions

View file

@ -1,47 +1,98 @@
name: Issue report name: Issue report
description: Report any errors, bugs, or unexpected behaviors related to presence.nvim description: Report any errors, bugs, or unexpected behaviors related to presence.nvim
title: "[Bug]: "
labels: [bug] labels: [bug]
assignees:
- jiriks74
body: body:
- type: markdown - type: markdown
attributes: attributes:
value: | value: |
Before reporting, please search [existing issues](https://github.com/andweeb/presence.nvim/issues) and make sure that presence.nvim is updated to the latest version. Before reporting, please search [existing issues](https://github.com/andweeb/presence.nvim/issues) and make sure that presence.nvim is updated to the latest version.
- type: checkboxes
attributes:
label: Are you on the latest version?
options:
- label: I have updated to the latest version.
required: true
- type: checkboxes
attributes:
label: Have you tried it with default config?
options:
- label: I have tried the default config.
required: true
- type: textarea - type: textarea
attributes: attributes:
label: "Description" label: "Description"
description: "A short summary of the error, bug, or unexpected behavior you're facing." description: "A short summary of the error, bug, or unexpected behavior you're facing."
validations: validations:
required: true required: true
- type: textarea - type: textarea
attributes: attributes:
label: "Neovim version" label: "Neovim version"
description: "Output of `nvim --version`" description: "Output of `nvim --version`"
render: markdown render: markdown
placeholder: | placeholder: |
NVIM v0.6.0-dev+209-g0603eba6e NVIM: v0.6.0-dev+209-g0603eba6e
Build type: Release Build type: Release
LuaJIT 2.1.0-beta3 LuaJIT: 2.1.0-beta3
value: |
NVIM:
Build type:
LuaJIT:
validations: validations:
required: true required: true
- type: input - type: input
attributes: attributes:
label: "OS information" label: "OS information"
placeholder: "macOS 12.0.1" placeholder: "macOS 12.0.1"
validations: validations:
required: true required: true
- type: textarea - type: textarea
attributes: attributes:
label: "Steps to reproduce" label: "Steps to reproduce"
description: "Steps to reproduce the issue with your config(s) if applicable" description: "Steps to reproduce the issue with your config(s) if applicable."
placeholder: | placeholder: |
1. Setup presence.nvim with `require("presence"):setup({...})` 1. Setup presence.nvim with `require("presence"):setup({...})`
2. Run Neovim with `nvim test.txt` 2. Run Neovim with `nvim test.txt`
3. ... 3. ...
validations: validations:
required: true required: true
- type: textarea - type: textarea
attributes: attributes:
label: "Logs" label: "Logs"
description: "The full list of `:messages` from one or more `nvim` instances" description: "The full list of `:messages` from one or more `nvim` instances.\nPlease insert the logs into code blocks."
placeholder: |
<details>
```
[presence.nvim] Using runtime path: /run/user/1000
[presence.nvim] Using Discord IPC socket path: /run/user/1000/discord-ipc-0
[presence.nvim] Checking Discord IPC socket at /run/user/1000/discord-ipc-0...
```
</details>
value: |
<details>
```
```
</details>
validations: validations:
required: true required: true
- type: textarea
attributes:
label: "Aditional info"
description: "If you'd like to add anything else put it here."
validations:
required: false

View file

@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View file

@ -0,0 +1,34 @@
name: Feature request
description: Report any errors, bugs, or unexpected behaviors related to presence.nvim
title: "[FEAT]: "
labels: [enhancement]
assignees:
- jiriks74
body:
- type: textarea
attributes:
label: Is your feature request related to a problem?
description: A clear and concise description of what the problem is. Ex. I'm always frustrated when...
validations:
required: true
- type: textarea
attributes:
label: Describe the solution you'd like
description: A clear and concise description of what you want to happen.
validations:
required: false
- type: textarea
attributes:
label: Describe alternatives you've considered
description: A clear and concise description of any alternative solutions or features you've considered.
validations:
required: false
- type: textarea
attributes:
label: Additional context
description: Add any other context or screenshots about the feature request here.
validations:
required: false

View file

@ -1,14 +0,0 @@
name: CI
on:
push:
pull_request:
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: nebularg/actions-luacheck@v1
with:
files: 'lua'

10
.github/workflows/luacheck.yml vendored Normal file
View file

@ -0,0 +1,10 @@
name: Luacheck
on: [push, pull_request]
jobs:
Luacheck:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Luacheck linter
uses: lunarmodules/luacheck@v1

15
.github/workflows/stylua.yml vendored Normal file
View file

@ -0,0 +1,15 @@
name: StyLua
on: [push, pull_request]
jobs:
StyLuacheck:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: StyLua check
uses: JohnnyMorganz/stylua-action@v3
with:
token: ${{ secrets.GH_TOKEN }}
version: v0.18.2 # NOTE: we recommend pinning to a specific version in case of formatting changes
# CLI arguments
args: --check .

123
README.md
View file

@ -1,41 +1,63 @@
<img src="https://gist.githubusercontent.com/andweeb/df3216345530234289b87cf5080c2c60/raw/8de399cfed82c137f793e9f580027b5246bc4379/presence.nvim.png" alt="presence.nvim">&#x200B; # ![presence.nvim](https://gist.githubusercontent.com/andweeb/df3216345530234289b87cf5080c2c60/raw/8de399cfed82c137f793e9f580027b5246bc4379/presence.nvim.png)
**[Features](#features)** | **[Installation](#installation)** | **[Configuration](#configuration)** | **[Troubleshooting](#troubleshooting)** | **[Development](#development)** | **[Contributing](#contributing)** This repository uses
[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-%23FE5196?logo=conventionalcommits&logoColor=white)](https://conventionalcommits.org)
**[Features](#features)** | **[Installation](#installation)** |
**[Configuration](#configuration)** | **[Troubleshooting](#troubleshooting)** |
**[Development](#development)** | **[Contributing](#contributing)**
> Discord [Rich Presence](https://discord.com/rich-presence) plugin for [Neovim](https://neovim.io) > Discord [Rich Presence](https://discord.com/rich-presence) plugin for [Neovim](https://neovim.io)
<img src="https://gist.githubusercontent.com/andweeb/df3216345530234289b87cf5080c2c60/raw/ad916fec8de921d0021801a0af877a5349621e7e/presence-demo-a.gif" width="100%" alt="demo.gif"> ![Presence demo](https://gist.githubusercontent.com/andweeb/df3216345530234289b87cf5080c2c60/raw/ad916fec8de921d0021801a0af877a5349621e7e/presence-demo-a.gif)
## Features ## Features
* Light and unobtrusive
* No Python/Node providers (or CoC) required - Light and unobtrusive
* Cross-platform support: macOS, nixOS, Linux[\*](#notes), Windows[\*](https://github.com/andweeb/presence.nvim/projects/1#card-60537963), WSL[\*](https://github.com/andweeb/presence.nvim/wiki/Rich-Presence-in-WSL) - No Python/Node providers (or CoC) required
* Startup time is fast(er than other Rich Presence plugins, by [kind of a lot](https://github.com/andweeb/presence.nvim/wiki/Plugin-Comparisons)) - Cross-platform support: macOS, nixOS, Linux[\*](#notes),
* Written in Lua and [highly configurable](#configuration) in Lua (but also configurable in VimL if you want) Windows, WSL
* Manages Rich Presence across multiple Neovim instances in various environments (tmux panes/windows, ssh sessions, terminal tabs/windows, etc.) - Startup time is fast(er than other Rich Presence plugins, by
[kind of a lot](https://github.com/andweeb/presence.nvim/wiki/Plugin-Comparisons))
- Written in Lua and [highly configurable](#configuration) in Lua
(but also configurable in VimL if you want)
- Manages Rich Presence across multiple Neovim instances in various environments
(tmux panes/windows, ssh sessions, terminal tabs/windows, etc.)
- Now with Flatpak support!
## Installation ## Installation
Use your favorite plugin manager Use your favorite plugin manager
* [vim-plug](https://github.com/junegunn/vim-plug): `Plug 'andweeb/presence.nvim'`
* [packer.nvim](https://github.com/wbthomason/packer.nvim): `use 'andweeb/presence.nvim'` - [vim-plug](https://github.com/junegunn/vim-plug): `Plug 'jiriks74/presence.nvim'`
- [packer.nvim](https://github.com/wbthomason/packer.nvim): `use 'jiriks74/presence.nvim'`
- [lazy.nvim](https://github.com/folke/lazy.nvim):
```lua ```lua
{ {
'andweeb/presence.nvim', "jiriks74/presence.nvim",
event = 'UIEnter', event = "UIEnter",
} },
``` ```
#### Notes ### Notes
* Requires [Neovim 0.5](https://github.com/neovim/neovim/releases/tag/v0.5.0) or higher
* Rich Presence should work automatically after installation (unless you're using WSL, in which case [see here](https://github.com/andweeb/presence.nvim/wiki/Rich-Presence-in-WSL)) - Requires [Neovim 0.5](https://github.com/neovim/neovim/releases/tag/v0.5.0)
* If you're using an unofficial Discord package on Linux ([flatpak](https://flathub.org/apps/details/com.discordapp.Discord), [snap](https://snapcraft.io/discord), etc.), you may need to follow some instructions to expose the Discord socket on your system (e.g. [flatpak instructions](https://github.com/flathub/com.discordapp.Discord/wiki/Rich-Precense-(discord-rpc))) or higher
- Rich Presence should work automatically after installation
(unless you're using WSL, in which case
[see here](https://github.com/andweeb/presence.nvim/wiki/Rich-Presence-in-WSL))
## Configuration ## Configuration
Configuration is not necessary for Rich Presence to work. But for those that want to override the default configs, the following options are available to configure in either Lua or VimL.
Configuration is not necesary unless you want to override the default config.
If you want to change the default config here are your options in Lua and VimL:
### Lua ### Lua
Require the plugin and call `setup` with a config table with one or more of the following keys:
Require the plugin and call `setup` with a config table with one or more of the
following keys:
```lua ```lua
-- The setup config table shows all available config options with their default values: -- The setup config table shows all available config options with their default values:
@ -44,7 +66,7 @@ require("presence").setup({
auto_update = true, -- Update activity based on autocmd events (if `false`, map or manually execute `:lua package.loaded.presence:update()`) auto_update = true, -- Update activity based on autocmd events (if `false`, map or manually execute `:lua package.loaded.presence:update()`)
neovim_image_text = "The One True Text Editor", -- Text displayed when hovered over the Neovim image neovim_image_text = "The One True Text Editor", -- Text displayed when hovered over the Neovim image
main_image = "neovim", -- Main image display (either "neovim" or "file") main_image = "neovim", -- Main image display (either "neovim" or "file")
client_id = "793271441293967371", -- Use your own Discord application client id (not recommended) client_id = "1172122807501594644", -- Use your own Discord application client id (not recommended)
log_level = nil, -- Log messages at or above this level (one of the following: "debug", "info", "warn", "error") log_level = nil, -- Log messages at or above this level (one of the following: "debug", "info", "warn", "error")
debounce_timeout = 10, -- Number of seconds to debounce events (or calls to `:lua package.loaded.presence:update(<filename>, true)`) debounce_timeout = 10, -- Number of seconds to debounce events (or calls to `:lua package.loaded.presence:update(<filename>, true)`)
enable_line_number = false, -- Displays the current line number instead of the current project enable_line_number = false, -- Displays the current line number instead of the current project
@ -65,13 +87,15 @@ require("presence").setup({
``` ```
### VimL ### VimL
Or if global variables are more your thing, you can use any of the following instead: Or if global variables are more your thing, you can use any of the following instead:
```viml ```viml
" General options " General options
let g:presence_auto_update = 1 let g:presence_auto_update = 1
let g:presence_neovim_image_text = "The One True Text Editor" let g:presence_neovim_image_text = "The One True Text Editor"
let g:presence_main_image = "neovim" let g:presence_main_image = "neovim"
let g:presence_client_id = "793271441293967371" let g:presence_client_id = "1172122807501594644"
let g:presence_log_level let g:presence_log_level
let g:presence_debounce_timeout = 10 let g:presence_debounce_timeout = 10
let g:presence_enable_line_number = 0 let g:presence_enable_line_number = 0
@ -91,23 +115,48 @@ let g:presence_line_number_text = "Line %s out of %s"
``` ```
## Troubleshooting ## Troubleshooting
* Ensure that Discord is running
* Ensure that your Neovim version is 0.5 or higher - Ensure that Discord is running
* Ensure Game Activity is enabled in your Discord settings - Ensure that your Neovim version is 0.5 or higher
* Enable logging and inspect the logs after opening a buffer - Ensure Game Activity is enabled in your Discord settings
* Set the [`log_level`](#lua) setup option or [`g:presence_log_level`](#viml) to `"debug"` - Enable logging and inspect the logs after opening a buffer
* Load a file and inspect the logs with `:messages` - Set the [`log_level`](#lua) setup option or [`g:presence_log_level`](#viml)
* If there is a `Failed to determine Discord IPC socket` error, your particular OS may not yet be supported to `"debug"`
* If you don't see an existing [issue](https://github.com/andweeb/presence.nvim/issues) or [card](https://github.com/andweeb/presence.nvim/projects/1#column-14183588) for your OS, create a prefixed [issue](https://github.com/andweeb/presence.nvim/issues/new) (e.g. `[Void Linux]`) - Load a file and inspect the logs with `:messages`
* Still not working and need help? Create a new [issue](https://github.com/andweeb/presence.nvim/issues)! - If there is a `Failed to determine Discord IPC socket` error, your particular
OS may not yet be supported
- If you don't see an existing
[issue](https://github.com/jiriks74/presence.nvim/issues)
or [card](https://github.com/jiriks74/presence.nvim/projects/1#column-14183588)
for your OS, create a prefixed
[issue](https://github.com/jiriks74/presence.nvim/issues/new)
(e.g. `[Void Linux]`)
- Still not working and need help? Create a new
[issue](https://github.com/jiriks74/presence.nvim/issues)!
## Development ## Development
* Clone the repo: `git clone https://github.com/andweeb/presence.nvim.git`
* Enable [logging](#configuration) and ensure that `presence.nvim` is **_not_** in the list of vim plugins in your config - Clone the repo: `git clone https://github.com/jiriks74/presence.nvim.git`
* Run `nvim` with your local changes: `nvim --cmd 'set rtp+=path/to/your/local/presence.nvim' file.txt` - Enable [logging](#configuration) and ensure that `presence.nvim` is **_not_**
* Ensure that there are no [luacheck](https://github.com/mpeterv/luacheck/) errors: `luacheck lua` in the list of vim plugins in your config
- Run `nvim` with your local changes: `nvim --cmd
'set rtp+=path/to/your/local/presence.nvim' file.txt`
- Ensure that there are no [luacheck](https://github.com/mpeterv/luacheck/)
errors: `luacheck lua`
## Contributing ## Contributing
Pull requests are very welcome, feel free to open an issue to work on any of the open [todo items](https://github.com/andweeb/presence.nvim/projects/1?add_cards_query=is%3Aopen) or message [droob#1322](https://discordapp.com/users/241953146232897550) on Discord!
Asset additions and changes are also welcome! Supported file types can be found in [`file_assets.lua`](lua/presence/file_assets.lua) and their referenced asset files can be found [in this folder](https://www.dropbox.com/sh/j8913f0gav3toeh/AADxjn0NuTprGFtv3Il1Pqz-a?dl=0). **Please use [Conventional Commits](https://www.conventionalcommits.org/)
if you want to contribute.
It makes everyones jobs easier.**
**This project uses [StyLua](https://github.com/JohnnyMorganz/StyLua).
Please format your code using StyLua for better readability**
Pull requests are very welcome, feel free to open an issue to work on
or message [me (@jiriks74)](https://discordapp.com/users/517810049360461837) on my
[Discord server](https://discord.gg/cCq3qcB4jB)!
Asset additions and changes are also welcome! Supported file types can be found in
[`file_assets.lua`](lua/presence/file_assets.lua) and their referenced asset files
can be found [in this folder](https://www.dropbox.com/sh/j8913f0gav3toeh/AADxjn0NuTprGFtv3Il1Pqz-a?dl=0).

View file

@ -9,120 +9,140 @@ local double_encode_count = 0
-- cache bitops -- cache bitops
local band, rshift = luabit.band, luabit.brshift local band, rshift = luabit.band, luabit.brshift
if not rshift then -- luajit differ from luabit if not rshift then -- luajit differ from luabit
rshift = luabit.rshift rshift = luabit.rshift
end end
local function byte_mod(x,v) local function byte_mod(x, v)
if x < 0 then if x < 0 then
x = x + 256 x = x + 256
end end
return (x%v) return (x % v)
end end
-- buffer -- buffer
local strbuf = "" -- for unpacking local strbuf = "" -- for unpacking
local strary = {} -- for packing local strary = {} -- for packing
local function strary_append_int16(n,h) local function strary_append_int16(n, h)
if n < 0 then if n < 0 then
n = n + 65536 n = n + 65536
end end
table.insert( strary, tostr(h, math.floor(n / 256), n % 256 ) ) table.insert(strary, tostr(h, math.floor(n / 256), n % 256))
end end
local function strary_append_int32(n,h) local function strary_append_int32(n, h)
if n < 0 then if n < 0 then
n = n + 4294967296 n = n + 4294967296
end end
table.insert(strary, tostr(h, table.insert(
math.floor(n / 16777216), strary,
math.floor(n / 65536) % 256, tostr(h, math.floor(n / 16777216), math.floor(n / 65536) % 256, math.floor(n / 256) % 256, n % 256)
math.floor(n / 256) % 256, )
n % 256 ))
end end
local doubleto8bytes local doubleto8bytes
local strary_append_double = function(n) local strary_append_double = function(n)
-- assume double -- assume double
double_encode_count = double_encode_count + 1 double_encode_count = double_encode_count + 1
local b = doubleto8bytes(n) local b = doubleto8bytes(n)
table.insert( strary, tostr(0xcb)) table.insert(strary, tostr(0xcb))
table.insert( strary, string.reverse(b) ) -- reverse: make big endian double precision table.insert(strary, string.reverse(b)) -- reverse: make big endian double precision
end end
--- IEEE 754 --- IEEE 754
-- out little endian -- out little endian
doubleto8bytes = function(x) doubleto8bytes = function(x)
local function grab_byte(v) local function grab_byte(v)
return math.floor(v / 256), tostr(math.fmod(math.floor(v), 256)) return math.floor(v / 256), tostr(math.fmod(math.floor(v), 256))
end end
local sign = 0 local sign = 0
if x < 0 then sign = 1; x = -x end if x < 0 then
local mantissa, exponent = math.frexp(x) sign = 1
if x == 0 then -- zero x = -x
mantissa, exponent = 0, 0 end
elseif x == 1/0 then local mantissa, exponent = math.frexp(x)
mantissa, exponent = 0, 2047 if x == 0 then -- zero
else mantissa, exponent = 0, 0
mantissa = (mantissa * 2 - 1) * math.ldexp(0.5, 53) elseif x == 1 / 0 then
exponent = exponent + 1022 mantissa, exponent = 0, 2047
end else
mantissa = (mantissa * 2 - 1) * math.ldexp(0.5, 53)
exponent = exponent + 1022
end
local v, byte = "" -- convert to bytes local v, byte = "" -- convert to bytes
x = mantissa x = mantissa
for _ = 1,6 do for _ = 1, 6 do
_, byte = grab_byte(x); v = v..byte -- 47:0 _, byte = grab_byte(x)
end v = v .. byte -- 47:0
x, byte = grab_byte(exponent * 16 + x); v = v..byte -- 55:48 end
x, byte = grab_byte(sign * 128 + x); v = v..byte -- 63:56 x, byte = grab_byte(exponent * 16 + x)
return v, x v = v .. byte -- 55:48
x, byte = grab_byte(sign * 128 + x)
v = v .. byte -- 63:56
return v, x
end end
local function bitstofrac(ary) local function bitstofrac(ary)
local x = 0 local x = 0
local cur = 0.5 local cur = 0.5
for _, v in ipairs(ary) do for _, v in ipairs(ary) do
x = x + cur * v x = x + cur * v
cur = cur / 2 cur = cur / 2
end end
return x return x
end end
local function bytestobits(ary) local function bytestobits(ary)
local out={} local out = {}
for _, v in ipairs(ary) do for _, v in ipairs(ary) do
for j = 0, 7, 1 do for j = 0, 7, 1 do
table.insert(out, band( rshift(v,7-j), 1 ) ) table.insert(out, band(rshift(v, 7 - j), 1))
end end
end end
return out return out
end end
-- get little endian -- get little endian
local function bytestodouble(v) local function bytestodouble(v)
-- sign:1bit -- sign:1bit
-- exp: 11bit (2048, bias=1023) -- exp: 11bit (2048, bias=1023)
local sign = math.floor(v:byte(8) / 128) local sign = math.floor(v:byte(8) / 128)
local exp = band( v:byte(8), 127 ) * 16 + rshift( v:byte(7), 4 ) - 1023 -- bias local exp = band(v:byte(8), 127) * 16 + rshift(v:byte(7), 4) - 1023 -- bias
-- frac: 52 bit -- frac: 52 bit
local fracbytes = { local fracbytes = {
band( v:byte(7), 15 ), v:byte(6), v:byte(5), v:byte(4), v:byte(3), v:byte(2), v:byte(1) -- big endian band(v:byte(7), 15),
} v:byte(6),
local bits = bytestobits(fracbytes) v:byte(5),
v:byte(4),
v:byte(3),
v:byte(2),
v:byte(1), -- big endian
}
local bits = bytestobits(fracbytes)
for _ = 1, 4 do table.remove(bits,1) end for _ = 1, 4 do
table.remove(bits, 1)
end
if sign == 1 then sign = -1 else sign = 1 end if sign == 1 then
sign = -1
else
sign = 1
end
local frac = bitstofrac(bits) local frac = bitstofrac(bits)
if exp == -1023 and frac==0 then return 0 end if exp == -1023 and frac == 0 then
if exp == 1024 and frac==0 then return 1/0 *sign end return 0
end
if exp == 1024 and frac == 0 then
return 1 / 0 * sign
end
local real = math.ldexp(1+frac,exp) local real = math.ldexp(1 + frac, exp)
return real * sign return real * sign
end end
--- packers --- packers
@ -130,265 +150,285 @@ end
local packers = {} local packers = {}
packers.dynamic = function(data) packers.dynamic = function(data)
local t = type(data) local t = type(data)
return packers[t](data) return packers[t](data)
end end
packers["nil"] = function() packers["nil"] = function()
table.insert( strary, tostr(0xc0)) table.insert(strary, tostr(0xc0))
end end
packers.boolean = function(data) packers.boolean = function(data)
if data then -- pack true if data then -- pack true
table.insert( strary, tostr(0xc3)) table.insert(strary, tostr(0xc3))
else -- pack false else -- pack false
table.insert( strary, tostr(0xc2)) table.insert(strary, tostr(0xc2))
end end
end end
packers.number = function(n) packers.number = function(n)
if math.floor(n) == n then -- integer if math.floor(n) == n then -- integer
if n >= 0 then -- positive integer if n >= 0 then -- positive integer
if n < 128 then -- positive fixnum if n < 128 then -- positive fixnum
table.insert( strary, tostr(n)) table.insert(strary, tostr(n))
elseif n < 256 then -- uint8 elseif n < 256 then -- uint8
table.insert(strary, tostr(0xcc,n)) table.insert(strary, tostr(0xcc, n))
elseif n < 65536 then -- uint16 elseif n < 65536 then -- uint16
strary_append_int16(n,0xcd) strary_append_int16(n, 0xcd)
elseif n < 4294967296 then -- uint32 elseif n < 4294967296 then -- uint32
strary_append_int32(n,0xce) strary_append_int32(n, 0xce)
else -- lua cannot handle uint64, so double else -- lua cannot handle uint64, so double
strary_append_double(n) strary_append_double(n)
end end
else -- negative integer else -- negative integer
if n >= -32 then -- negative fixnum if n >= -32 then -- negative fixnum
table.insert( strary, tostr( 0xe0 + ((n+256)%32)) ) table.insert(strary, tostr(0xe0 + ((n + 256) % 32)))
elseif n >= -128 then -- int8 elseif n >= -128 then -- int8
table.insert( strary, tostr(0xd0,byte_mod(n,0x100))) table.insert(strary, tostr(0xd0, byte_mod(n, 0x100)))
elseif n >= -32768 then -- int16 elseif n >= -32768 then -- int16
strary_append_int16(n,0xd1) strary_append_int16(n, 0xd1)
elseif n >= -2147483648 then -- int32 elseif n >= -2147483648 then -- int32
strary_append_int32(n,0xd2) strary_append_int32(n, 0xd2)
else -- lua cannot handle int64, so double else -- lua cannot handle int64, so double
strary_append_double(n) strary_append_double(n)
end end
end end
else -- floating point else -- floating point
strary_append_double(n) strary_append_double(n)
end end
end end
packers.string = function(data) packers.string = function(data)
local n = #data local n = #data
if n < 32 then if n < 32 then
table.insert( strary, tostr( 0xa0+n ) ) table.insert(strary, tostr(0xa0 + n))
elseif n < 65536 then elseif n < 65536 then
strary_append_int16(n,0xda) strary_append_int16(n, 0xda)
elseif n < 4294967296 then elseif n < 4294967296 then
strary_append_int32(n,0xdb) strary_append_int32(n, 0xdb)
else else
error("overflow") error("overflow")
end end
table.insert( strary, data) table.insert(strary, data)
end end
packers["function"] = function() packers["function"] = function()
error("unimplemented:function") error("unimplemented:function")
end end
packers.userdata = function() packers.userdata = function()
error("unimplemented:userdata") error("unimplemented:userdata")
end end
packers.thread = function() packers.thread = function()
error("unimplemented:thread") error("unimplemented:thread")
end end
packers.table = function(data) packers.table = function(data)
local is_map,ndata,nmax = false,0,0 local is_map, ndata, nmax = false, 0, 0
for k,_ in pairs(data) do for k, _ in pairs(data) do
if type(k) == "number" then if type(k) == "number" then
if k > nmax then nmax = k end if k > nmax then
else is_map = true end nmax = k
ndata = ndata+1 end
end else
if is_map then -- pack as map is_map = true
if ndata < 16 then end
table.insert( strary, tostr(0x80+ndata)) ndata = ndata + 1
elseif ndata < 65536 then end
strary_append_int16(ndata,0xde) if is_map then -- pack as map
elseif ndata < 4294967296 then if ndata < 16 then
strary_append_int32(ndata,0xdf) table.insert(strary, tostr(0x80 + ndata))
else elseif ndata < 65536 then
error("overflow") strary_append_int16(ndata, 0xde)
end elseif ndata < 4294967296 then
for k,v in pairs(data) do strary_append_int32(ndata, 0xdf)
packers[type(k)](k) else
packers[type(v)](v) error("overflow")
end end
else -- pack as array for k, v in pairs(data) do
if nmax < 16 then packers[type(k)](k)
table.insert( strary, tostr( 0x90+nmax ) ) packers[type(v)](v)
elseif nmax < 65536 then end
strary_append_int16(nmax,0xdc) else -- pack as array
elseif nmax < 4294967296 then if nmax < 16 then
strary_append_int32(nmax,0xdd) table.insert(strary, tostr(0x90 + nmax))
else elseif nmax < 65536 then
error("overflow") strary_append_int16(nmax, 0xdc)
end elseif nmax < 4294967296 then
for i=1,nmax do packers[type(data[i])](data[i]) end strary_append_int32(nmax, 0xdd)
end else
error("overflow")
end
for i = 1, nmax do
packers[type(data[i])](data[i])
end
end
end end
-- types decoding -- types decoding
local types_map = { local types_map = {
[0xc0] = "nil", [0xc0] = "nil",
[0xc2] = "false", [0xc2] = "false",
[0xc3] = "true", [0xc3] = "true",
[0xca] = "float", [0xca] = "float",
[0xcb] = "double", [0xcb] = "double",
[0xcc] = "uint8", [0xcc] = "uint8",
[0xcd] = "uint16", [0xcd] = "uint16",
[0xce] = "uint32", [0xce] = "uint32",
[0xcf] = "uint64", [0xcf] = "uint64",
[0xd0] = "int8", [0xd0] = "int8",
[0xd1] = "int16", [0xd1] = "int16",
[0xd2] = "int32", [0xd2] = "int32",
[0xd3] = "int64", [0xd3] = "int64",
[0xda] = "raw16", [0xda] = "raw16",
[0xdb] = "raw32", [0xdb] = "raw32",
[0xdc] = "array16", [0xdc] = "array16",
[0xdd] = "array32", [0xdd] = "array32",
[0xde] = "map16", [0xde] = "map16",
[0xdf] = "map32", [0xdf] = "map32",
} }
local type_for = function(n) local type_for = function(n)
if types_map[n] then
if types_map[n] then return types_map[n] return types_map[n]
elseif n < 0xc0 then elseif n < 0xc0 then
if n < 0x80 then return "fixnum_posi" if n < 0x80 then
elseif n < 0x90 then return "fixmap" return "fixnum_posi"
elseif n < 0xa0 then return "fixarray" elseif n < 0x90 then
else return "fixraw" end return "fixmap"
elseif n > 0xdf then return "fixnum_neg" elseif n < 0xa0 then
else return "undefined" end return "fixarray"
else
return "fixraw"
end
elseif n > 0xdf then
return "fixnum_neg"
else
return "undefined"
end
end end
local types_len_map = { local types_len_map = {
uint16 = 2, uint32 = 4, uint64 = 8, uint16 = 2,
int16 = 2, int32 = 4, int64 = 8, uint32 = 4,
float = 4, double = 8, uint64 = 8,
int16 = 2,
int32 = 4,
int64 = 8,
float = 4,
double = 8,
} }
--- unpackers --- unpackers
local unpackers = {} local unpackers = {}
local unpack_number = function(offset,ntype,nlen) local unpack_number = function(offset, ntype, nlen)
local b1,b2,b3,b4,b5,b6,b7,b8 local b1, b2, b3, b4, b5, b6, b7, b8
if nlen>=2 then if nlen >= 2 then
b1,b2 = string.byte( strbuf, offset+1, offset+2 ) b1, b2 = string.byte(strbuf, offset + 1, offset + 2)
end end
if nlen>=4 then if nlen >= 4 then
b3,b4 = string.byte( strbuf, offset+3, offset+4 ) b3, b4 = string.byte(strbuf, offset + 3, offset + 4)
end end
if nlen>=8 then if nlen >= 8 then
b5,b6,b7,b8 = string.byte( strbuf, offset+5, offset+8 ) b5, b6, b7, b8 = string.byte(strbuf, offset + 5, offset + 8)
end end
if ntype == "uint16_t" then if ntype == "uint16_t" then
return b1 * 256 + b2 return b1 * 256 + b2
elseif ntype == "uint32_t" then elseif ntype == "uint32_t" then
return b1*65536*256 + b2*65536 + b3 * 256 + b4 return b1 * 65536 * 256 + b2 * 65536 + b3 * 256 + b4
elseif ntype == "int16_t" then elseif ntype == "int16_t" then
local n = b1 * 256 + b2 local n = b1 * 256 + b2
local nn = (65536 - n)*-1 local nn = (65536 - n) * -1
if nn == -65536 then nn = 0 end if nn == -65536 then
return nn nn = 0
elseif ntype == "int32_t" then end
local n = b1*65536*256 + b2*65536 + b3 * 256 + b4 return nn
local nn = ( 4294967296 - n ) * -1 elseif ntype == "int32_t" then
if nn == -4294967296 then nn = 0 end local n = b1 * 65536 * 256 + b2 * 65536 + b3 * 256 + b4
return nn local nn = (4294967296 - n) * -1
elseif ntype == "double_t" then if nn == -4294967296 then
local s = tostr(b8,b7,b6,b5,b4,b3,b2,b1) nn = 0
double_decode_count = double_decode_count + 1 end
local n = bytestodouble( s ) return nn
return n elseif ntype == "double_t" then
else local s = tostr(b8, b7, b6, b5, b4, b3, b2, b1)
error("unpack_number: not impl:" .. ntype ) double_decode_count = double_decode_count + 1
end local n = bytestodouble(s)
return n
else
error("unpack_number: not impl:" .. ntype)
end
end end
local function unpacker_number(offset) local function unpacker_number(offset)
local obj_type = type_for( string.byte( strbuf, offset+1, offset+1 ) ) local obj_type = type_for(string.byte(strbuf, offset + 1, offset + 1))
local nlen = types_len_map[obj_type] local nlen = types_len_map[obj_type]
local ntype local ntype
if (obj_type == "float") then if obj_type == "float" then
error("float is not implemented") error("float is not implemented")
else else
ntype = obj_type .. "_t" ntype = obj_type .. "_t"
end end
return offset+nlen+1,unpack_number(offset+1,ntype,nlen) return offset + nlen + 1, unpack_number(offset + 1, ntype, nlen)
end end
local function unpack_map(offset,n) local function unpack_map(offset, n)
local r = {} local r = {}
local k,v local k, v
for _ = 1, n do for _ = 1, n do
offset,k = unpackers.dynamic(offset) offset, k = unpackers.dynamic(offset)
assert(offset) assert(offset)
offset,v = unpackers.dynamic(offset) offset, v = unpackers.dynamic(offset)
assert(offset) assert(offset)
r[k] = v r[k] = v
end end
return offset,r return offset, r
end end
local function unpack_array(offset,n) local function unpack_array(offset, n)
local r = {} local r = {}
for i=1,n do for i = 1, n do
offset,r[i] = unpackers.dynamic(offset) offset, r[i] = unpackers.dynamic(offset)
assert(offset) assert(offset)
end end
return offset,r return offset, r
end end
function unpackers.dynamic(offset) function unpackers.dynamic(offset)
if offset >= #strbuf then error("need more data") end if offset >= #strbuf then
local obj_type = type_for( string.byte( strbuf, offset+1, offset+1 ) ) error("need more data")
return unpackers[obj_type](offset) end
local obj_type = type_for(string.byte(strbuf, offset + 1, offset + 1))
return unpackers[obj_type](offset)
end end
function unpackers.undefined() function unpackers.undefined()
error("unimplemented:undefined") error("unimplemented:undefined")
end end
unpackers["nil"] = function(offset) unpackers["nil"] = function(offset)
return offset+1,nil return offset + 1, nil
end end
unpackers["false"] = function(offset) unpackers["false"] = function(offset)
return offset+1,false return offset + 1, false
end end
unpackers["true"] = function(offset) unpackers["true"] = function(offset)
return offset+1,true return offset + 1, true
end end
unpackers.fixnum_posi = function(offset) unpackers.fixnum_posi = function(offset)
return offset+1, string.byte(strbuf, offset+1, offset+1) return offset + 1, string.byte(strbuf, offset + 1, offset + 1)
end end
unpackers.uint8 = function(offset) unpackers.uint8 = function(offset)
return offset+2, string.byte(strbuf, offset+2, offset+2) return offset + 2, string.byte(strbuf, offset + 2, offset + 2)
end end
unpackers.uint16 = unpacker_number unpackers.uint16 = unpacker_number
@ -396,18 +436,18 @@ unpackers.uint32 = unpacker_number
unpackers.uint64 = unpacker_number unpackers.uint64 = unpacker_number
unpackers.fixnum_neg = function(offset) unpackers.fixnum_neg = function(offset)
-- alternative to cast below: -- alternative to cast below:
local n = string.byte( strbuf, offset+1, offset+1) local n = string.byte(strbuf, offset + 1, offset + 1)
local nn = ( 256 - n ) * -1 local nn = (256 - n) * -1
return offset+1, nn return offset + 1, nn
end end
unpackers.int8 = function(offset) unpackers.int8 = function(offset)
local i = string.byte( strbuf, offset+2, offset+2 ) local i = string.byte(strbuf, offset + 2, offset + 2)
if i > 127 then if i > 127 then
i = (256 - i ) * -1 i = (256 - i) * -1
end end
return offset+2, i return offset + 2, i
end end
unpackers.int16 = unpacker_number unpackers.int16 = unpacker_number
@ -418,92 +458,96 @@ unpackers.float = unpacker_number
unpackers.double = unpacker_number unpackers.double = unpacker_number
unpackers.fixraw = function(offset) unpackers.fixraw = function(offset)
local n = byte_mod( string.byte( strbuf, offset+1, offset+1) ,0x1f+1) local n = byte_mod(string.byte(strbuf, offset + 1, offset + 1), 0x1f + 1)
-- print("unpackers.fixraw: offset:", offset, "#buf:", #buf, "n:",n ) -- print("unpackers.fixraw: offset:", offset, "#buf:", #buf, "n:",n )
local b local b
if ( #strbuf - 1 - offset ) < n then if (#strbuf - 1 - offset) < n then
error("require more data") error("require more data")
end end
if n > 0 then if n > 0 then
b = string.sub( strbuf, offset + 1 + 1, offset + 1 + 1 + n - 1 ) b = string.sub(strbuf, offset + 1 + 1, offset + 1 + 1 + n - 1)
else else
b = "" b = ""
end end
return offset+n+1, b return offset + n + 1, b
end end
unpackers.raw16 = function(offset) unpackers.raw16 = function(offset)
local n = unpack_number(offset+1,"uint16_t",2) local n = unpack_number(offset + 1, "uint16_t", 2)
if ( #strbuf - 1 - 2 - offset ) < n then if (#strbuf - 1 - 2 - offset) < n then
error("require more data") error("require more data")
end end
local b = string.sub( strbuf, offset+1+1+2, offset+1 + 1+2 + n - 1 ) local b = string.sub(strbuf, offset + 1 + 1 + 2, offset + 1 + 1 + 2 + n - 1)
return offset+n+3, b return offset + n + 3, b
end end
unpackers.raw32 = function(offset) unpackers.raw32 = function(offset)
local n = unpack_number(offset+1,"uint32_t",4) local n = unpack_number(offset + 1, "uint32_t", 4)
if ( #strbuf - 1 - 4 - offset ) < n then if (#strbuf - 1 - 4 - offset) < n then
error( "require more data (possibly bug)") error("require more data (possibly bug)")
end end
local b = string.sub( strbuf, offset+1+ 1+4, offset+1 + 1+4 +n -1 ) local b = string.sub(strbuf, offset + 1 + 1 + 4, offset + 1 + 1 + 4 + n - 1)
return offset+n+5,b return offset + n + 5, b
end end
unpackers.fixarray = function(offset) unpackers.fixarray = function(offset)
return unpack_array( offset+1,byte_mod( string.byte( strbuf, offset+1,offset+1),0x0f+1)) return unpack_array(offset + 1, byte_mod(string.byte(strbuf, offset + 1, offset + 1), 0x0f + 1))
end end
unpackers.array16 = function(offset) unpackers.array16 = function(offset)
return unpack_array(offset+3,unpack_number(offset+1,"uint16_t",2)) return unpack_array(offset + 3, unpack_number(offset + 1, "uint16_t", 2))
end end
unpackers.array32 = function(offset) unpackers.array32 = function(offset)
return unpack_array(offset+5,unpack_number(offset+1,"uint32_t",4)) return unpack_array(offset + 5, unpack_number(offset + 1, "uint32_t", 4))
end end
unpackers.fixmap = function(offset) unpackers.fixmap = function(offset)
return unpack_map(offset+1,byte_mod( string.byte( strbuf, offset+1,offset+1),0x0f+1)) return unpack_map(offset + 1, byte_mod(string.byte(strbuf, offset + 1, offset + 1), 0x0f + 1))
end end
unpackers.map16 = function(offset) unpackers.map16 = function(offset)
return unpack_map(offset+3,unpack_number(offset+1,"uint16_t",2)) return unpack_map(offset + 3, unpack_number(offset + 1, "uint16_t", 2))
end end
unpackers.map32 = function(offset) unpackers.map32 = function(offset)
return unpack_map(offset+5,unpack_number(offset+1,"uint32_t",4)) return unpack_map(offset + 5, unpack_number(offset + 1, "uint32_t", 4))
end end
-- Main functions -- Main functions
local ljp_pack = function(data) local ljp_pack = function(data)
strary={} strary = {}
packers.dynamic(data) packers.dynamic(data)
local s = table.concat(strary,"") local s = table.concat(strary, "")
return s return s
end end
local ljp_unpack = function(s,offset) local ljp_unpack = function(s, offset)
if offset == nil then offset = 0 end if offset == nil then
if type(s) ~= "string" then return false,"invalid argument" end offset = 0
local data end
strbuf = s if type(s) ~= "string" then
offset,data = unpackers.dynamic(offset) return false, "invalid argument"
return offset,data end
local data
strbuf = s
offset, data = unpackers.dynamic(offset)
return offset, data
end end
local function ljp_stat() local function ljp_stat()
return { return {
double_decode_count = double_decode_count, double_decode_count = double_decode_count,
double_encode_count = double_encode_count double_encode_count = double_encode_count,
} }
end end
local msgpack = { local msgpack = {
pack = ljp_pack, pack = ljp_pack,
unpack = ljp_unpack, unpack = ljp_unpack,
stat = ljp_stat stat = ljp_stat,
} }
return msgpack return msgpack

View file

@ -1,140 +1,265 @@
local n, v = "serpent", "0.302" -- (C) 2012-18 Paul Kulchenko; MIT License local n, v = "serpent", "0.302" -- (C) 2012-18 Paul Kulchenko; MIT License
local c, d = "Paul Kulchenko", "Lua serializer and pretty printer" local c, d = "Paul Kulchenko", "Lua serializer and pretty printer"
local snum = {[tostring(1/0)]='1/0 --[[math.huge]]',[tostring(-1/0)]='-1/0 --[[-math.huge]]',[tostring(0/0)]='0/0'} local snum = {
local badtype = {thread = true, userdata = true, cdata = true} [tostring(1 / 0)] = "1/0 --[[math.huge]]",
[tostring(-1 / 0)] = "-1/0 --[[-math.huge]]",
[tostring(0 / 0)] = "0/0",
}
local badtype = { thread = true, userdata = true, cdata = true }
local getmetatable = debug and debug.getmetatable or getmetatable local getmetatable = debug and debug.getmetatable or getmetatable
local pairs = function(t) return next, t end -- avoid using __pairs in Lua 5.2+ local pairs = function(t)
return next, t
end -- avoid using __pairs in Lua 5.2+
local keyword, globals, G = {}, {}, (_G or _ENV) local keyword, globals, G = {}, {}, (_G or _ENV)
for _,k in ipairs({'and', 'break', 'do', 'else', 'elseif', 'end', 'false', for _, k in ipairs({
'for', 'function', 'goto', 'if', 'in', 'local', 'nil', 'not', 'or', 'repeat', "and",
'return', 'then', 'true', 'until', 'while'}) do keyword[k] = true end "break",
for k,v in pairs(G) do globals[v] = k end -- build func to name mapping "do",
for _,g in ipairs({'coroutine', 'debug', 'io', 'math', 'string', 'table', 'os'}) do "else",
for k,v in pairs(type(G[g]) == 'table' and G[g] or {}) do globals[v] = g..'.'..k end end "elseif",
"end",
"false",
"for",
"function",
"goto",
"if",
"in",
"local",
"nil",
"not",
"or",
"repeat",
"return",
"then",
"true",
"until",
"while",
}) do
keyword[k] = true
end
for k, v in pairs(G) do
globals[v] = k
end -- build func to name mapping
for _, g in ipairs({ "coroutine", "debug", "io", "math", "string", "table", "os" }) do
for k, v in pairs(type(G[g]) == "table" and G[g] or {}) do
globals[v] = g .. "." .. k
end
end
local function s(t, opts) local function s(t, opts)
local name, indent, fatal, maxnum = opts.name, opts.indent, opts.fatal, opts.maxnum local name, indent, fatal, maxnum = opts.name, opts.indent, opts.fatal, opts.maxnum
local sparse, custom, huge = opts.sparse, opts.custom, not opts.nohuge local sparse, custom, huge = opts.sparse, opts.custom, not opts.nohuge
local space, maxl = (opts.compact and '' or ' '), (opts.maxlevel or math.huge) local space, maxl = (opts.compact and "" or " "), (opts.maxlevel or math.huge)
local maxlen, metatostring = tonumber(opts.maxlength), opts.metatostring local maxlen, metatostring = tonumber(opts.maxlength), opts.metatostring
local iname, comm = '_'..(name or ''), opts.comment and (tonumber(opts.comment) or math.huge) local iname, comm = "_" .. (name or ""), opts.comment and (tonumber(opts.comment) or math.huge)
local numformat = opts.numformat or "%.17g" local numformat = opts.numformat or "%.17g"
local seen, sref, syms, symn = {}, {'local '..iname..'={}'}, {}, 0 local seen, sref, syms, symn = {}, { "local " .. iname .. "={}" }, {}, 0
local function gensym(val) return '_'..(tostring(tostring(val)):gsub("[^%w]",""):gsub("(%d%w+)", local function gensym(val)
-- tostring(val) is needed because __tostring may return a non-string value return "_"
function(s) if not syms[s] then symn = symn+1; syms[s] = symn end return tostring(syms[s]) end)) end .. (
local function safestr(s) return type(s) == "number" and tostring(huge and snum[tostring(s)] or numformat:format(s)) tostring(tostring(val)):gsub("[^%w]", ""):gsub(
or type(s) ~= "string" and tostring(s) -- escape NEWLINE/010 and EOF/026 "(%d%w+)",
or ("%q"):format(s):gsub("\010","n"):gsub("\026","\\026") end -- tostring(val) is needed because __tostring may return a non-string value
local function comment(s,l) return comm and (l or 0) < comm and ' --[['..select(2, pcall(tostring, s))..']]' or '' end function(s)
local function globerr(s,l) return globals[s] and globals[s]..comment(s,l) or not fatal if not syms[s] then
and safestr(select(2, pcall(tostring, s))) or error("Can't serialize "..tostring(s)) end symn = symn + 1
local function safename(path, name) -- generates foo.bar, foo[3], or foo['b a r'] syms[s] = symn
local n = name == nil and '' or name end
local plain = type(n) == "string" and n:match("^[%l%u_][%w_]*$") and not keyword[n] return tostring(syms[s])
local safe = plain and n or '['..safestr(n)..']' end
return (path or '')..(plain and path and '.' or '')..safe, safe end )
local alphanumsort = type(opts.sortkeys) == 'function' and opts.sortkeys or function(k, o, n) -- k=keys, o=originaltable, n=padding )
local maxn, to = tonumber(n) or 12, {number = 'a', string = 'b'} end
local function padnum(d) return ("%0"..tostring(maxn).."d"):format(tonumber(d)) end local function safestr(s)
table.sort(k, function(a,b) return type(s) == "number" and tostring(huge and snum[tostring(s)] or numformat:format(s))
-- sort numeric keys first: k[key] is not nil for numerical keys or type(s) ~= "string" and tostring(s) -- escape NEWLINE/010 and EOF/026
return (k[a] ~= nil and 0 or to[type(a)] or 'z')..(tostring(a):gsub("%d+",padnum)) or ("%q"):format(s):gsub("\010", "n"):gsub("\026", "\\026")
< (k[b] ~= nil and 0 or to[type(b)] or 'z')..(tostring(b):gsub("%d+",padnum)) end) end end
local function val2str(t, name, indent, insref, path, plainindex, level) local function comment(s, l)
local ttype, level, mt = type(t), (level or 0), getmetatable(t) return comm and (l or 0) < comm and " --[[" .. select(2, pcall(tostring, s)) .. "]]" or ""
local spath, sname = safename(path, name) end
local tag = plainindex and local function globerr(s, l)
((type(name) == "number") and '' or name..space..'='..space) or return globals[s] and globals[s] .. comment(s, l)
(name ~= nil and sname..space..'='..space or '') or not fatal and safestr(select(2, pcall(tostring, s)))
if seen[t] then -- already seen this element or error("Can't serialize " .. tostring(s))
sref[#sref+1] = spath..space..'='..space..seen[t] end
return tag..'nil'..comment('ref', level) end local function safename(path, name) -- generates foo.bar, foo[3], or foo['b a r']
-- protect from those cases where __tostring may fail local n = name == nil and "" or name
if type(mt) == 'table' and metatostring ~= false then local plain = type(n) == "string" and n:match("^[%l%u_][%w_]*$") and not keyword[n]
local to, tr = pcall(function() return mt.__tostring(t) end) local safe = plain and n or "[" .. safestr(n) .. "]"
local so, sr = pcall(function() return mt.__serialize(t) end) return (path or "") .. (plain and path and "." or "") .. safe, safe
if (to or so) then -- knows how to serialize itself end
seen[t] = insref or spath local alphanumsort = type(opts.sortkeys) == "function" and opts.sortkeys
t = so and sr or tr or function(k, o, n) -- k=keys, o=originaltable, n=padding
ttype = type(t) local maxn, to = tonumber(n) or 12, { number = "a", string = "b" }
end -- new value falls through to be serialized local function padnum(d)
end return ("%0" .. tostring(maxn) .. "d"):format(tonumber(d))
if ttype == "table" then end
if level >= maxl then return tag..'{}'..comment('maxlvl', level) end table.sort(k, function(a, b)
seen[t] = insref or spath -- sort numeric keys first: k[key] is not nil for numerical keys
if next(t) == nil then return tag..'{}'..comment(t, level) end -- table empty return (k[a] ~= nil and 0 or to[type(a)] or "z") .. (tostring(a):gsub("%d+", padnum))
if maxlen and maxlen < 0 then return tag..'{}'..comment('maxlen', level) end < (k[b] ~= nil and 0 or to[type(b)] or "z") .. (tostring(b):gsub("%d+", padnum))
local maxn, o, out = math.min(#t, maxnum or #t), {}, {} end)
for key = 1, maxn do o[key] = key end end
if not maxnum or #o < maxnum then local function val2str(t, name, indent, insref, path, plainindex, level)
local n = #o -- n = n + 1; o[n] is much faster than o[#o+1] on large tables local ttype, level, mt = type(t), (level or 0), getmetatable(t)
for key in pairs(t) do if o[key] ~= key then n = n + 1; o[n] = key end end end local spath, sname = safename(path, name)
if maxnum and #o > maxnum then o[maxnum+1] = nil end local tag = plainindex and ((type(name) == "number") and "" or name .. space .. "=" .. space)
if opts.sortkeys and #o > maxn then alphanumsort(o, t, opts.sortkeys) end or (name ~= nil and sname .. space .. "=" .. space or "")
local sparse = sparse and #o > maxn -- disable sparsness if only numeric keys (shorter output) if seen[t] then -- already seen this element
for n, key in ipairs(o) do sref[#sref + 1] = spath .. space .. "=" .. space .. seen[t]
local value, ktype, plainindex = t[key], type(key), n <= maxn and not sparse return tag .. "nil" .. comment("ref", level)
if opts.valignore and opts.valignore[value] -- skip ignored values; do nothing end
or opts.keyallow and not opts.keyallow[key] -- protect from those cases where __tostring may fail
or opts.keyignore and opts.keyignore[key] if type(mt) == "table" and metatostring ~= false then
or opts.valtypeignore and opts.valtypeignore[type(value)] -- skipping ignored value types local to, tr = pcall(function()
or sparse and value == nil then -- skipping nils; do nothing return mt.__tostring(t)
elseif ktype == 'table' or ktype == 'function' or badtype[ktype] then end)
if not seen[key] and not globals[key] then local so, sr = pcall(function()
sref[#sref+1] = 'placeholder' return mt.__serialize(t)
local sname = safename(iname, gensym(key)) -- iname is table for local variables end)
sref[#sref] = val2str(key,sname,indent,sname,iname,true) end if to or so then -- knows how to serialize itself
sref[#sref+1] = 'placeholder' seen[t] = insref or spath
local path = seen[t]..'['..tostring(seen[key] or globals[key] or gensym(key))..']' t = so and sr or tr
sref[#sref] = path..space..'='..space..tostring(seen[value] or val2str(value,nil,indent,path)) ttype = type(t)
else end -- new value falls through to be serialized
out[#out+1] = val2str(value,key,indent,nil,seen[t],plainindex,level+1) end
if maxlen then if ttype == "table" then
maxlen = maxlen - #out[#out] if level >= maxl then
if maxlen < 0 then break end return tag .. "{}" .. comment("maxlvl", level)
end end
end seen[t] = insref or spath
end if next(t) == nil then
local prefix = string.rep(indent or '', level) return tag .. "{}" .. comment(t, level)
local head = indent and '{\n'..prefix..indent or '{' end -- table empty
local body = table.concat(out, ','..(indent and '\n'..prefix..indent or space)) if maxlen and maxlen < 0 then
local tail = indent and "\n"..prefix..'}' or '}' return tag .. "{}" .. comment("maxlen", level)
return (custom and custom(tag,head,body,tail,level) or tag..head..body..tail)..comment(t, level) end
elseif badtype[ttype] then local maxn, o, out = math.min(#t, maxnum or #t), {}, {}
seen[t] = insref or spath for key = 1, maxn do
return tag..globerr(t, level) o[key] = key
elseif ttype == 'function' then end
seen[t] = insref or spath if not maxnum or #o < maxnum then
if opts.nocode then return tag.."function() --[[..skipped..]] end"..comment(t, level) end local n = #o -- n = n + 1; o[n] is much faster than o[#o+1] on large tables
local ok, res = pcall(string.dump, t) for key in pairs(t) do
local func = ok and "((loadstring or load)("..safestr(res)..",'@serialized'))"..comment(t, level) if o[key] ~= key then
return tag..(func or globerr(t, level)) n = n + 1
else return tag..safestr(t) end -- handle all other types o[n] = key
end end
local sepr = indent and "\n" or ";"..space end
local body = val2str(t, name, indent) -- this call also populates sref end
local tail = #sref>1 and table.concat(sref, sepr)..sepr or '' if maxnum and #o > maxnum then
local warn = opts.comment and #sref>1 and space.."--[[incomplete output with shared/self-references skipped]]" or '' o[maxnum + 1] = nil
return not name and body..warn or "do local "..body..sepr..tail.."return "..name..sepr.."end" end
if opts.sortkeys and #o > maxn then
alphanumsort(o, t, opts.sortkeys)
end
local sparse = sparse and #o > maxn -- disable sparsness if only numeric keys (shorter output)
for n, key in ipairs(o) do
local value, ktype, plainindex = t[key], type(key), n <= maxn and not sparse
if
opts.valignore and opts.valignore[value] -- skip ignored values; do nothing
or opts.keyallow and not opts.keyallow[key]
or opts.keyignore and opts.keyignore[key]
or opts.valtypeignore and opts.valtypeignore[type(value)] -- skipping ignored value types
or sparse and value == nil
then -- skipping nils; do nothing
elseif ktype == "table" or ktype == "function" or badtype[ktype] then
if not seen[key] and not globals[key] then
sref[#sref + 1] = "placeholder"
local sname = safename(iname, gensym(key)) -- iname is table for local variables
sref[#sref] = val2str(key, sname, indent, sname, iname, true)
end
sref[#sref + 1] = "placeholder"
local path = seen[t] .. "[" .. tostring(seen[key] or globals[key] or gensym(key)) .. "]"
sref[#sref] = path
.. space
.. "="
.. space
.. tostring(seen[value] or val2str(value, nil, indent, path))
else
out[#out + 1] = val2str(value, key, indent, nil, seen[t], plainindex, level + 1)
if maxlen then
maxlen = maxlen - #out[#out]
if maxlen < 0 then
break
end
end
end
end
local prefix = string.rep(indent or "", level)
local head = indent and "{\n" .. prefix .. indent or "{"
local body = table.concat(out, "," .. (indent and "\n" .. prefix .. indent or space))
local tail = indent and "\n" .. prefix .. "}" or "}"
return (custom and custom(tag, head, body, tail, level) or tag .. head .. body .. tail) .. comment(t, level)
elseif badtype[ttype] then
seen[t] = insref or spath
return tag .. globerr(t, level)
elseif ttype == "function" then
seen[t] = insref or spath
if opts.nocode then
return tag .. "function() --[[..skipped..]] end" .. comment(t, level)
end
local ok, res = pcall(string.dump, t)
local func = ok and "((loadstring or load)(" .. safestr(res) .. ",'@serialized'))" .. comment(t, level)
return tag .. (func or globerr(t, level))
else
return tag .. safestr(t)
end -- handle all other types
end
local sepr = indent and "\n" or ";" .. space
local body = val2str(t, name, indent) -- this call also populates sref
local tail = #sref > 1 and table.concat(sref, sepr) .. sepr or ""
local warn = opts.comment and #sref > 1 and space .. "--[[incomplete output with shared/self-references skipped]]"
or ""
return not name and body .. warn or "do local " .. body .. sepr .. tail .. "return " .. name .. sepr .. "end"
end end
local function deserialize(data, opts) local function deserialize(data, opts)
local env = (opts and opts.safe == false) and G local env = (opts and opts.safe == false) and G
or setmetatable({}, { or setmetatable({}, {
__index = function(t,k) return t end, __index = function(t, k)
__call = function(t,...) error("cannot call functions") end return t
}) end,
local f, res = (loadstring or load)('return '..data, nil, nil, env) __call = function(t, ...)
if not f then f, res = (loadstring or load)(data, nil, nil, env) end error("cannot call functions")
if not f then return f, res end end,
if setfenv then setfenv(f, env) end })
return pcall(f) local f, res = (loadstring or load)("return " .. data, nil, nil, env)
if not f then
f, res = (loadstring or load)(data, nil, nil, env)
end
if not f then
return f, res
end
if setfenv then
setfenv(f, env)
end
return pcall(f)
end end
local function merge(a, b) if b then for k,v in pairs(b) do a[k] = v end end; return a; end local function merge(a, b)
return { _NAME = n, _COPYRIGHT = c, _DESCRIPTION = d, _VERSION = v, serialize = s, if b then
load = deserialize, for k, v in pairs(b) do
dump = function(a, opts) return s(a, merge({name = '_', compact = true, sparse = true}, opts)) end, a[k] = v
line = function(a, opts) return s(a, merge({sortkeys = true, comment = true}, opts)) end, end
block = function(a, opts) return s(a, merge({indent = ' ', sortkeys = true, comment = true}, opts)) end } end
return a
end
return {
_NAME = n,
_COPYRIGHT = c,
_DESCRIPTION = d,
_VERSION = v,
serialize = s,
load = deserialize,
dump = function(a, opts)
return s(a, merge({ name = "_", compact = true, sparse = true }, opts))
end,
line = function(a, opts)
return s(a, merge({ sortkeys = true, comment = true }, opts))
end,
block = function(a, opts)
return s(a, merge({ indent = " ", sortkeys = true, comment = true }, opts))
end,
}

View file

@ -1,179 +1,178 @@
local struct = {} local struct = {}
function struct.pack(format, ...) function struct.pack(format, ...)
local stream = {} local stream = {}
local vars = {...} local vars = { ... }
local endianness = true local endianness = true
for i = 1, format:len() do for i = 1, format:len() do
local opt = format:sub(i, i) local opt = format:sub(i, i)
if opt == '<' then if opt == "<" then
endianness = true endianness = true
elseif opt == '>' then elseif opt == ">" then
endianness = false endianness = false
elseif opt:find('[bBhHiIlL]') then elseif opt:find("[bBhHiIlL]") then
local n = opt:find('[hH]') and 2 or opt:find('[iI]') and 4 or opt:find('[lL]') and 8 or 1 local n = opt:find("[hH]") and 2 or opt:find("[iI]") and 4 or opt:find("[lL]") and 8 or 1
local val = tonumber(table.remove(vars, 1)) local val = tonumber(table.remove(vars, 1))
local bytes = {} local bytes = {}
for _ = 1, n do for _ = 1, n do
table.insert(bytes, string.char(val % (2 ^ 8))) table.insert(bytes, string.char(val % (2 ^ 8)))
val = math.floor(val / (2 ^ 8)) val = math.floor(val / (2 ^ 8))
end end
if not endianness then if not endianness then
table.insert(stream, string.reverse(table.concat(bytes))) table.insert(stream, string.reverse(table.concat(bytes)))
else else
table.insert(stream, table.concat(bytes)) table.insert(stream, table.concat(bytes))
end end
elseif opt:find('[fd]') then elseif opt:find("[fd]") then
local val = tonumber(table.remove(vars, 1)) local val = tonumber(table.remove(vars, 1))
local sign = 0 local sign = 0
if val < 0 then if val < 0 then
sign = 1 sign = 1
val = -val val = -val
end end
local mantissa, exponent = math.frexp(val) local mantissa, exponent = math.frexp(val)
if val == 0 then if val == 0 then
mantissa = 0 mantissa = 0
exponent = 0 exponent = 0
else else
mantissa = (mantissa * 2 - 1) * math.ldexp(0.5, (opt == 'd') and 53 or 24) mantissa = (mantissa * 2 - 1) * math.ldexp(0.5, (opt == "d") and 53 or 24)
exponent = exponent + ((opt == 'd') and 1022 or 126) exponent = exponent + ((opt == "d") and 1022 or 126)
end end
local bytes = {} local bytes = {}
if opt == 'd' then if opt == "d" then
val = mantissa val = mantissa
for _ = 1, 6 do for _ = 1, 6 do
table.insert(bytes, string.char(math.floor(val) % (2 ^ 8))) table.insert(bytes, string.char(math.floor(val) % (2 ^ 8)))
val = math.floor(val / (2 ^ 8)) val = math.floor(val / (2 ^ 8))
end end
else else
table.insert(bytes, string.char(math.floor(mantissa) % (2 ^ 8))) table.insert(bytes, string.char(math.floor(mantissa) % (2 ^ 8)))
val = math.floor(mantissa / (2 ^ 8)) val = math.floor(mantissa / (2 ^ 8))
table.insert(bytes, string.char(math.floor(val) % (2 ^ 8))) table.insert(bytes, string.char(math.floor(val) % (2 ^ 8)))
val = math.floor(val / (2 ^ 8)) val = math.floor(val / (2 ^ 8))
end end
table.insert(bytes, string.char(math.floor(exponent * ((opt == 'd') and 16 or 128) + val) % (2 ^ 8))) table.insert(bytes, string.char(math.floor(exponent * ((opt == "d") and 16 or 128) + val) % (2 ^ 8)))
val = math.floor((exponent * ((opt == 'd') and 16 or 128) + val) / (2 ^ 8)) val = math.floor((exponent * ((opt == "d") and 16 or 128) + val) / (2 ^ 8))
table.insert(bytes, string.char(math.floor(sign * 128 + val) % (2 ^ 8))) table.insert(bytes, string.char(math.floor(sign * 128 + val) % (2 ^ 8)))
if not endianness then if not endianness then
table.insert(stream, string.reverse(table.concat(bytes))) table.insert(stream, string.reverse(table.concat(bytes)))
else else
table.insert(stream, table.concat(bytes)) table.insert(stream, table.concat(bytes))
end end
elseif opt == 's' then elseif opt == "s" then
table.insert(stream, tostring(table.remove(vars, 1))) table.insert(stream, tostring(table.remove(vars, 1)))
table.insert(stream, string.char(0)) table.insert(stream, string.char(0))
elseif opt == 'c' then elseif opt == "c" then
local n = format:sub(i + 1):match('%d+') local n = format:sub(i + 1):match("%d+")
local str = tostring(table.remove(vars, 1)) local str = tostring(table.remove(vars, 1))
local len = tonumber(n) local len = tonumber(n)
if len <= 0 then if len <= 0 then
len = str:len() len = str:len()
end end
if len - str:len() > 0 then if len - str:len() > 0 then
str = str .. string.rep(' ', len - str:len()) str = str .. string.rep(" ", len - str:len())
end end
table.insert(stream, str:sub(1, len)) table.insert(stream, str:sub(1, len))
end end
end end
return table.concat(stream) return table.concat(stream)
end end
function struct.unpack(format, stream, pos) function struct.unpack(format, stream, pos)
local vars = {} local vars = {}
local iterator = pos or 1 local iterator = pos or 1
local endianness = true local endianness = true
for i = 1, format:len() do for i = 1, format:len() do
local opt = format:sub(i, i) local opt = format:sub(i, i)
if opt == '<' then if opt == "<" then
endianness = true endianness = true
elseif opt == '>' then elseif opt == ">" then
endianness = false endianness = false
elseif opt:find('[bBhHiIlL]') then elseif opt:find("[bBhHiIlL]") then
local n = opt:find('[hH]') and 2 or opt:find('[iI]') and 4 or opt:find('[lL]') and 8 or 1 local n = opt:find("[hH]") and 2 or opt:find("[iI]") and 4 or opt:find("[lL]") and 8 or 1
local signed = opt:lower() == opt local signed = opt:lower() == opt
local val = 0 local val = 0
for j = 1, n do for j = 1, n do
local byte = string.byte(stream:sub(iterator, iterator)) local byte = string.byte(stream:sub(iterator, iterator))
if endianness then if endianness then
val = val + byte * (2 ^ ((j - 1) * 8)) val = val + byte * (2 ^ ((j - 1) * 8))
else else
val = val + byte * (2 ^ ((n - j) * 8)) val = val + byte * (2 ^ ((n - j) * 8))
end end
iterator = iterator + 1 iterator = iterator + 1
end end
if signed and val >= 2 ^ (n * 8 - 1) then if signed and val >= 2 ^ (n * 8 - 1) then
val = val - 2 ^ (n * 8) val = val - 2 ^ (n * 8)
end end
table.insert(vars, math.floor(val)) table.insert(vars, math.floor(val))
elseif opt:find('[fd]') then elseif opt:find("[fd]") then
local n = (opt == 'd') and 8 or 4 local n = (opt == "d") and 8 or 4
local x = stream:sub(iterator, iterator + n - 1) local x = stream:sub(iterator, iterator + n - 1)
iterator = iterator + n iterator = iterator + n
if not endianness then if not endianness then
x = string.reverse(x) x = string.reverse(x)
end end
local sign = 1 local sign = 1
local mantissa = string.byte(x, (opt == 'd') and 7 or 3) % ((opt == 'd') and 16 or 128) local mantissa = string.byte(x, (opt == "d") and 7 or 3) % ((opt == "d") and 16 or 128)
for j = n - 2, 1, -1 do for j = n - 2, 1, -1 do
mantissa = mantissa * (2 ^ 8) + string.byte(x, j) mantissa = mantissa * (2 ^ 8) + string.byte(x, j)
end end
if string.byte(x, n) > 127 then if string.byte(x, n) > 127 then
sign = -1 sign = -1
end end
local exponent = (string.byte(x, n) % 128) * ((opt == 'd') and 16 or 2) + local exponent = (string.byte(x, n) % 128) * ((opt == "d") and 16 or 2)
math.floor(string.byte(x, n - 1) / + math.floor(string.byte(x, n - 1) / ((opt == "d") and 16 or 128))
((opt == 'd') and 16 or 128)) if exponent == 0 then
if exponent == 0 then table.insert(vars, 0.0)
table.insert(vars, 0.0) else
else mantissa = (math.ldexp(mantissa, (opt == "d") and -52 or -23) + 1) * sign
mantissa = (math.ldexp(mantissa, (opt == 'd') and -52 or -23) + 1) * sign table.insert(vars, math.ldexp(mantissa, exponent - ((opt == "d") and 1023 or 127)))
table.insert(vars, math.ldexp(mantissa, exponent - ((opt == 'd') and 1023 or 127))) end
end elseif opt == "s" then
elseif opt == 's' then local bytes = {}
local bytes = {} for j = iterator, stream:len() do
for j = iterator, stream:len() do if stream:sub(j, j) == string.char(0) or stream:sub(j) == "" then
if stream:sub(j,j) == string.char(0) or stream:sub(j) == '' then break
break end
end
table.insert(bytes, stream:sub(j, j)) table.insert(bytes, stream:sub(j, j))
end end
local str = table.concat(bytes) local str = table.concat(bytes)
iterator = iterator + str:len() + 1 iterator = iterator + str:len() + 1
table.insert(vars, str) table.insert(vars, str)
elseif opt == 'c' then elseif opt == "c" then
local n = format:sub(i + 1):match('%d+') local n = format:sub(i + 1):match("%d+")
local len = tonumber(n) local len = tonumber(n)
if len <= 0 then if len <= 0 then
len = table.remove(vars) len = table.remove(vars)
end end
table.insert(vars, stream:sub(iterator, iterator + len - 1)) table.insert(vars, stream:sub(iterator, iterator + len - 1))
iterator = iterator + len iterator = iterator + len
end end
end end
return unpack(vars) return unpack(vars)
end end
return struct return struct

View file

@ -2,37 +2,37 @@ local Log = {}
Log.codes = {} Log.codes = {}
Log.levels = { Log.levels = {
{ "debug", "Comment" }, { "debug", "Comment" },
{ "info", "None" }, { "info", "None" },
{ "warn", "WarningMsg" }, { "warn", "WarningMsg" },
{ "error", "ErrorMsg" }, { "error", "ErrorMsg" },
} }
function Log:init(options) function Log:init(options)
self.level = options.level self.level = options.level
return self return self
end end
-- Initialize logger with log functions for each level -- Initialize logger with log functions for each level
for i = 1, #Log.levels do for i = 1, #Log.levels do
local level, hl = unpack(Log.levels[i]) local level, hl = unpack(Log.levels[i])
Log.codes[level] = i Log.codes[level] = i
Log[level] = function(self, message) Log[level] = function(self, message)
-- Skip if log level is not set or the log is below the configured or default level -- Skip if log level is not set or the log is below the configured or default level
if not self.level or self.codes[level] < self.codes[self.level] or type(message) ~= "string" then if not self.level or self.codes[level] < self.codes[self.level] or type(message) ~= "string" then
return return
end end
vim.schedule(function() vim.schedule(function()
local escaped_message = vim.fn.escape(message, '"'):gsub("\n", "\\n") local escaped_message = vim.fn.escape(message, '"'):gsub("\n", "\\n")
vim.cmd(string.format("echohl %s", hl)) vim.cmd(string.format("echohl %s", hl))
vim.cmd(string.format([[echom "[%s] %s"]], "presence.nvim", escaped_message)) vim.cmd(string.format([[echom "[%s] %s"]], "presence.nvim", escaped_message))
vim.cmd("echohl NONE") vim.cmd("echohl NONE")
end) end)
end end
end end
return Log return Log

View file

@ -1,9 +1,9 @@
local Discord = {} local Discord = {}
Discord.opcodes = { Discord.opcodes = {
auth = 0, auth = 0,
frame = 1, frame = 1,
closed = 2, closed = 2,
} }
-- Discord RPC Subscription events -- Discord RPC Subscription events
@ -11,190 +11,187 @@ Discord.opcodes = {
-- Ready: https://discord.com/developers/docs/topics/rpc#ready -- Ready: https://discord.com/developers/docs/topics/rpc#ready
-- Error: https://discord.com/developers/docs/topics/rpc#error -- Error: https://discord.com/developers/docs/topics/rpc#error
Discord.events = { Discord.events = {
READY = "READY", READY = "READY",
ERROR = "ERROR", ERROR = "ERROR",
} }
local struct = require("deps.struct") local struct = require("deps.struct")
-- Initialize a new Discord RPC client -- Initialize a new Discord RPC client
function Discord:init(options) function Discord:init(options)
self.log = options.logger self.log = options.logger
self.client_id = options.client_id self.client_id = options.client_id
self.ipc_socket = options.ipc_socket self.ipc_socket = options.ipc_socket
self.pipe = vim.loop.new_pipe(false) self.pipe = vim.loop.new_pipe(false)
return self return self
end end
-- Connect to the local Discord RPC socket -- Connect to the local Discord RPC socket
-- TODO Might need to check for pipes ranging from discord-ipc-0 to discord-ipc-9: -- TODO Might need to check for pipes ranging from discord-ipc-0 to discord-ipc-9:
-- https://github.com/discord/discord-rpc/blob/master/documentation/hard-mode.md#notes -- https://github.com/discord/discord-rpc/blob/master/documentation/hard-mode.md#notes
function Discord:connect(on_connect) function Discord:connect(on_connect)
if self.pipe:is_closing() then if self.pipe:is_closing() then
self.pipe = vim.loop.new_pipe(false) self.pipe = vim.loop.new_pipe(false)
end end
self.pipe:connect(self.ipc_socket, on_connect) self.pipe:connect(self.ipc_socket, on_connect)
end end
function Discord:is_connected() function Discord:is_connected()
return self.pipe:is_active() return self.pipe:is_active()
end end
-- Disconnect from the local Discord RPC socket -- Disconnect from the local Discord RPC socket
function Discord:disconnect(on_close) function Discord:disconnect(on_close)
self.pipe:shutdown() self.pipe:shutdown()
if not self.pipe:is_closing() then if not self.pipe:is_closing() then
self.pipe:close(on_close) self.pipe:close(on_close)
end end
end end
-- Make a remote procedure call to Discord -- Make a remote procedure call to Discord
-- Callback argument in format: on_response(error[, response_table]) -- Callback argument in format: on_response(error[, response_table])
function Discord:call(opcode, payload, on_response) function Discord:call(opcode, payload, on_response)
self.encode_json(payload, function(success, body) self.encode_json(payload, function(success, body)
if not success then if not success then
self.log:warn(string.format("Failed to encode payload: %s", vim.inspect(body))) self.log:warn(string.format("Failed to encode payload: %s", vim.inspect(body)))
return return
end end
-- Start reading for the response -- Start reading for the response
self.pipe:read_start(function(...) self.pipe:read_start(function(...)
self:read_message(payload.nonce, on_response, ...) self:read_message(payload.nonce, on_response, ...)
end) end)
-- Construct message denoting little endian, auth opcode, msg length -- Construct message denoting little endian, auth opcode, msg length
local message = struct.pack("<ii", opcode, #body)..body local message = struct.pack("<ii", opcode, #body) .. body
-- Write the message to the pipe -- Write the message to the pipe
self.pipe:write(message, function(err) self.pipe:write(message, function(err)
if err then if err then
local err_format = "Pipe write error - %s" local err_format = "Pipe write error - %s"
local err_message = string.format(err_format, err) local err_message = string.format(err_format, err)
on_response(err_message) on_response(err_message)
else else
self.log:debug("Wrote message to pipe") self.log:debug("Wrote message to pipe")
end end
end) end)
end) end)
end end
-- Read and handle socket messages -- Read and handle socket messages
function Discord:read_message(nonce, on_response, err, chunk) function Discord:read_message(nonce, on_response, err, chunk)
if err then if err then
local err_format = "Pipe read error - %s" local err_format = "Pipe read error - %s"
local err_message = string.format(err_format, err) local err_message = string.format(err_format, err)
on_response(err_message) on_response(err_message)
elseif chunk then
-- Strip header from the chunk
local message = chunk:match("({.+)")
local response_opcode = struct.unpack("<ii", chunk)
elseif chunk then self.decode_json(message, function(success, response)
-- Strip header from the chunk -- Check for a non-frame opcode in the response
local message = chunk:match("({.+)") if response_opcode ~= self.opcodes.frame then
local response_opcode = struct.unpack("<ii", chunk) local err_format = "Received unexpected opcode - %s (code %s)"
local err_message = string.format(err_format, response.message, response.code)
self.decode_json(message, function(success, response) return on_response(err_message)
-- Check for a non-frame opcode in the response end
if response_opcode ~= self.opcodes.frame then
local err_format = "Received unexpected opcode - %s (code %s)"
local err_message = string.format(err_format, response.message, response.code)
return on_response(err_message) -- Unable to decode the response
end if not success then
-- Indetermine state at this point, no choice but to simply warn on the parse failure
-- but invoke empty response callback as request may still have succeeded
self.log:warn(string.format("Failed to decode payload: %s", vim.inspect(message)))
return on_response()
end
-- Unable to decode the response -- Check for an error event response
if not success then if response.evt == self.events.ERROR then
-- Indetermine state at this point, no choice but to simply warn on the parse failure local data = response.data
-- but invoke empty response callback as request may still have succeeded local err_format = "Received error event - %s (code %s)"
self.log:warn(string.format("Failed to decode payload: %s", vim.inspect(message))) local err_message = string.format(err_format, data.message, data.code)
return on_response()
end
-- Check for an error event response return on_response(err_message)
if response.evt == self.events.ERROR then end
local data = response.data
local err_format = "Received error event - %s (code %s)"
local err_message = string.format(err_format, data.message, data.code)
return on_response(err_message) -- Check for a valid nonce value
end if response.nonce and response.nonce ~= vim.NIL and response.nonce ~= nonce then
local err_format = "Received unexpected nonce - %s (expected %s)"
local err_message = string.format(err_format, response.nonce, nonce)
-- Check for a valid nonce value return on_response(err_message)
if response.nonce and response.nonce ~= vim.NIL and response.nonce ~= nonce then end
local err_format = "Received unexpected nonce - %s (expected %s)"
local err_message = string.format(err_format, response.nonce, nonce)
return on_response(err_message) on_response(nil, response)
end end)
else
on_response(nil, response) -- TODO: Handle when pipe is closed
end) self.log:warn("Pipe was closed")
else end
-- TODO: Handle when pipe is closed
self.log:warn("Pipe was closed")
end
end end
-- Call to authorize the client connection with Discord -- Call to authorize the client connection with Discord
-- Callback argument in format: on_authorize(error[, response_table]) -- Callback argument in format: on_authorize(error[, response_table])
function Discord:authorize(on_authorize) function Discord:authorize(on_authorize)
local payload = { local payload = {
client_id = self.client_id, client_id = self.client_id,
v = 1, v = 1,
} }
self:call(self.opcodes.auth, payload, on_authorize) self:call(self.opcodes.auth, payload, on_authorize)
end end
-- Call to set the Neovim activity to Discord -- Call to set the Neovim activity to Discord
function Discord:set_activity(activity, on_response) function Discord:set_activity(activity, on_response)
local payload = { local payload = {
cmd = "SET_ACTIVITY", cmd = "SET_ACTIVITY",
nonce = self.generate_uuid(), nonce = self.generate_uuid(),
args = { args = {
activity = activity, activity = activity,
pid = vim.loop:os_getpid(), pid = vim.loop:os_getpid(),
}, },
} }
self:call(self.opcodes.frame, payload, on_response) self:call(self.opcodes.frame, payload, on_response)
end end
function Discord.generate_uuid(seed) function Discord.generate_uuid(seed)
local index = 0 local index = 0
local template ="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx" local template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
local uuid = template:gsub("[xy]", function(char) local uuid = template:gsub("[xy]", function(char)
-- Increment an index to seed per char -- Increment an index to seed per char
index = index + 1 index = index + 1
math.randomseed((seed or os.clock()) / index) math.randomseed((seed or os.clock()) / index)
local n = char == "x" local n = char == "x" and math.random(0, 0xf) or math.random(8, 0xb)
and math.random(0, 0xf)
or math.random(8, 0xb)
return string.format("%x", n) return string.format("%x", n)
end) end)
return uuid return uuid
end end
function Discord.decode_json(t, on_done) function Discord.decode_json(t, on_done)
vim.schedule(function() vim.schedule(function()
on_done(pcall(function() on_done(pcall(function()
return vim.fn.json_decode(t) return vim.fn.json_decode(t)
end)) end))
end) end)
end end
function Discord.encode_json(t, on_done) function Discord.encode_json(t, on_done)
vim.schedule(function() vim.schedule(function()
on_done(pcall(function() on_done(pcall(function()
return vim.fn.json_encode(t) return vim.fn.json_encode(t)
end)) end))
end) end)
end end
return Discord return Discord

View file

@ -11,266 +11,266 @@
-- go = { "Go", "https://go.dev/blog/go-brand/Go-Logo/PNG/Go-Logo_Aqua.png" }, -- go = { "Go", "https://go.dev/blog/go-brand/Go-Logo/PNG/Go-Logo_Aqua.png" },
-- } -- }
return { return {
[".aliases"] = { ".aliases", "shell" }, [".aliases"] = { ".aliases", "shell" },
[".appveyor.yml"] = { "AppVeyor config", "appveyor" }, [".appveyor.yml"] = { "AppVeyor config", "appveyor" },
[".babelrc"] = { "Babel config", "babel" }, [".babelrc"] = { "Babel config", "babel" },
[".babelrc.cjs"] = { "Babel config", "babel" }, [".babelrc.cjs"] = { "Babel config", "babel" },
[".babelrc.js"] = { "Babel config", "babel" }, [".babelrc.js"] = { "Babel config", "babel" },
[".babelrc.json"] = { "Babel config", "babel" }, [".babelrc.json"] = { "Babel config", "babel" },
[".babelrc.mjs"] = { "Babel config", "babel" }, [".babelrc.mjs"] = { "Babel config", "babel" },
[".bash_login"] = { ".bash_login", "shell" }, [".bash_login"] = { ".bash_login", "shell" },
[".bash_logout"] = { ".bash_logout", "shell" }, [".bash_logout"] = { ".bash_logout", "shell" },
[".bash_profile"] = { ".bash_profile", "shell" }, [".bash_profile"] = { ".bash_profile", "shell" },
[".bash_prompt"] = { ".bash_prompt", "shell" }, [".bash_prompt"] = { ".bash_prompt", "shell" },
[".bashrc"] = { ".bashrc", "shell" }, [".bashrc"] = { ".bashrc", "shell" },
[".cshrc"] = { ".cshrc", "shell" }, [".cshrc"] = { ".cshrc", "shell" },
[".dockercfg"] = { "Docker", "docker" }, [".dockercfg"] = { "Docker", "docker" },
[".dockerfile"] = { "Docker", "docker" }, [".dockerfile"] = { "Docker", "docker" },
[".dockerignore"] = { "Docker", "docker" }, [".dockerignore"] = { "Docker", "docker" },
[".editorconfig"] = { "EditorConfig", "editorconfig" }, [".editorconfig"] = { "EditorConfig", "editorconfig" },
[".eslintignore"] = { "ESLint", "eslint" }, [".eslintignore"] = { "ESLint", "eslint" },
[".eslintrc"] = { "ESLint", "eslint" }, [".eslintrc"] = { "ESLint", "eslint" },
[".eslintrc.cjs"] = { "ESLint", "eslint" }, [".eslintrc.cjs"] = { "ESLint", "eslint" },
[".eslintrc.js"] = { "ESLint", "eslint" }, [".eslintrc.js"] = { "ESLint", "eslint" },
[".eslintrc.json"] = { "ESLint", "eslint" }, [".eslintrc.json"] = { "ESLint", "eslint" },
[".eslintrc.yaml"] = { "ESLint", "eslint" }, [".eslintrc.yaml"] = { "ESLint", "eslint" },
[".eslintrc.yml"] = { "ESLint", "eslint" }, [".eslintrc.yml"] = { "ESLint", "eslint" },
[".gitattributes"] = { "git", "git" }, [".gitattributes"] = { "git", "git" },
[".gitconfig"] = { "git", "git" }, [".gitconfig"] = { "git", "git" },
[".gitignore"] = { "git", "git" }, [".gitignore"] = { "git", "git" },
[".gitlab-ci.yaml"] = { "GitLab CI", "gitlab" }, [".gitlab-ci.yaml"] = { "GitLab CI", "gitlab" },
[".gitlab-ci.yml"] = { "GitLab CI", "gitlab" }, [".gitlab-ci.yml"] = { "GitLab CI", "gitlab" },
[".gitmodules"] = { "git", "git" }, [".gitmodules"] = { "git", "git" },
[".login"] = { ".login", "shell" }, [".login"] = { ".login", "shell" },
[".logout"] = { ".login", "shell" }, [".logout"] = { ".login", "shell" },
[".luacheckrc"] = { ".luacheckrc", "lua" }, [".luacheckrc"] = { ".luacheckrc", "lua" },
[".npmignore"] = { "npm config", "npm" }, [".npmignore"] = { "npm config", "npm" },
[".npmrc"] = { "npm config", "npm" }, [".npmrc"] = { "npm config", "npm" },
[".nvmrc"] = { ".nvmrc", "nodejs" }, [".nvmrc"] = { ".nvmrc", "nodejs" },
[".prettierrc"] = { "Prettier", "prettier" }, [".prettierrc"] = { "Prettier", "prettier" },
[".prettierrc.cjs"] = { "Prettier", "prettier" }, [".prettierrc.cjs"] = { "Prettier", "prettier" },
[".prettierrc.js"] = { "Prettier", "prettier" }, [".prettierrc.js"] = { "Prettier", "prettier" },
[".prettierrc.json"] = { "Prettier", "prettier" }, [".prettierrc.json"] = { "Prettier", "prettier" },
[".prettierrc.json5"] = { "Prettier", "prettier" }, [".prettierrc.json5"] = { "Prettier", "prettier" },
[".prettierrc.toml"] = { "Prettier", "prettier" }, [".prettierrc.toml"] = { "Prettier", "prettier" },
[".prettierrc.yaml"] = { "Prettier", "prettier" }, [".prettierrc.yaml"] = { "Prettier", "prettier" },
[".prettierrc.yml"] = { "Prettier", "prettier" }, [".prettierrc.yml"] = { "Prettier", "prettier" },
[".profile"] = { ".profile", "shell" }, [".profile"] = { ".profile", "shell" },
[".tcshrc"] = { ".tcshrc", "shell" }, [".tcshrc"] = { ".tcshrc", "shell" },
[".terraformrc"] = { "Terraform config", "terraform" }, [".terraformrc"] = { "Terraform config", "terraform" },
[".tmux.conf"] = { "tmux", "tmux" }, [".tmux.conf"] = { "tmux", "tmux" },
[".travis.yml"] = { "Travis CI", "travis" }, [".travis.yml"] = { "Travis CI", "travis" },
[".vimrc"] = { ".vimrc", "vim" }, [".vimrc"] = { ".vimrc", "vim" },
[".watchmanconfig"] = { "Watchman config", "watchman" }, [".watchmanconfig"] = { "Watchman config", "watchman" },
[".yarnrc"] = { "Yarn config", "yarn" }, [".yarnrc"] = { "Yarn config", "yarn" },
[".zlogin"] = { ".zlogin", "shell" }, [".zlogin"] = { ".zlogin", "shell" },
[".zprofile"] = { ".zprofile", "shell" }, [".zprofile"] = { ".zprofile", "shell" },
[".zshenv"] = { ".zshenv", "shell" }, [".zshenv"] = { ".zshenv", "shell" },
[".zshrc"] = { ".zshrc", "shell" }, [".zshrc"] = { ".zshrc", "shell" },
["Brewfile"] = { "Brewfile", "homebrew" }, ["Brewfile"] = { "Brewfile", "homebrew" },
["Brewfile.lock.json"] = { "Brewfile.lock.json", "homebrew" }, ["Brewfile.lock.json"] = { "Brewfile.lock.json", "homebrew" },
["CHANGELOG"] = { "CHANGELOG", "text" }, ["CHANGELOG"] = { "CHANGELOG", "text" },
["CODE_OF_CONDUCT"] = { "Code of Conduct", "text" }, ["CODE_OF_CONDUCT"] = { "Code of Conduct", "text" },
["COMMIT_EDITMSG"] = { "git", "git" }, ["COMMIT_EDITMSG"] = { "git", "git" },
["CONTRIBUTING"] = { "CONTRIBUTING", "text" }, ["CONTRIBUTING"] = { "CONTRIBUTING", "text" },
["Cargo.lock"] = { "Cargo lockfile", "cargo" }, ["Cargo.lock"] = { "Cargo lockfile", "cargo" },
["Cargo.toml"] = { "Cargo.toml", "cargo" }, ["Cargo.toml"] = { "Cargo.toml", "cargo" },
["Dockerfile"] = { "Docker", "docker" }, ["Dockerfile"] = { "Docker", "docker" },
["Gemfile"] = { "Gemfile", "ruby" }, ["Gemfile"] = { "Gemfile", "ruby" },
["Gemfile.lock"] = { "Gemfile lockfile", "ruby" }, ["Gemfile.lock"] = { "Gemfile lockfile", "ruby" },
["LICENSE"] = { "LICENSE", "text" }, ["LICENSE"] = { "LICENSE", "text" },
["Makefile"] = { "Makefile", "code" }, ["Makefile"] = { "Makefile", "code" },
["Rakefile"] = { "Rakefile", "ruby" }, ["Rakefile"] = { "Rakefile", "ruby" },
["abookrc"] = { "abook", "abook" }, ["abookrc"] = { "abook", "abook" },
["alacritty.yaml"] = { "Alacritty config", "alacritty" }, ["alacritty.yaml"] = { "Alacritty config", "alacritty" },
["alacritty.yml"] = { "Alacritty config", "alacritty" }, ["alacritty.yml"] = { "Alacritty config", "alacritty" },
["appveyor.yml"] = { "AppVeyor config", "appveyor" }, ["appveyor.yml"] = { "AppVeyor config", "appveyor" },
["babel.config.cjs"] = { "Babel config", "babel" }, ["babel.config.cjs"] = { "Babel config", "babel" },
["babel.config.js"] = { "Babel config", "babel" }, ["babel.config.js"] = { "Babel config", "babel" },
["babel.config.json"] = { "Babel config", "babel" }, ["babel.config.json"] = { "Babel config", "babel" },
["babel.config.mjs"] = { "Babel config", "babel" }, ["babel.config.mjs"] = { "Babel config", "babel" },
["brew.sh"] = { "brew.sh", "homebrew" }, ["brew.sh"] = { "brew.sh", "homebrew" },
["docker-compose.yaml"] = { "Docker", "docker" }, ["docker-compose.yaml"] = { "Docker", "docker" },
["docker-compose.yml"] = { "Docker", "docker" }, ["docker-compose.yml"] = { "Docker", "docker" },
["gitconfig"] = { "git", "git" }, ["gitconfig"] = { "git", "git" },
["gitlab.rb"] = { "GitLab config", "gitlab" }, ["gitlab.rb"] = { "GitLab config", "gitlab" },
["gitlab.yml"] = { "GitLab config", "gitlab" }, ["gitlab.yml"] = { "GitLab config", "gitlab" },
["go.mod"] = { "go.mod", "go" }, ["go.mod"] = { "go.mod", "go" },
["go.sum"] = { "go.sum", "go" }, ["go.sum"] = { "go.sum", "go" },
["jest.config.js"] = { "Jest config", "jest" }, ["jest.config.js"] = { "Jest config", "jest" },
["jest.setup.js"] = { "Jest config", "jest" }, ["jest.setup.js"] = { "Jest config", "jest" },
["jest.setup.ts"] = { "Jest config", "jest" }, ["jest.setup.ts"] = { "Jest config", "jest" },
["kitty.conf"] = { "Kitty config", "kitty" }, ["kitty.conf"] = { "Kitty config", "kitty" },
["next-env.d.ts"] = { "Next.js config", "nextjs" }, ["next-env.d.ts"] = { "Next.js config", "nextjs" },
["next.config.js"] = { "Next.js config", "nextjs" }, ["next.config.js"] = { "Next.js config", "nextjs" },
["nginx"] = { "NGINX", "nginx" }, ["nginx"] = { "NGINX", "nginx" },
["nginx.conf"] = { "NGINX", "nginx" }, ["nginx.conf"] = { "NGINX", "nginx" },
["nuxt.config.js"] = { "Nuxt config", "nuxtjs" }, ["nuxt.config.js"] = { "Nuxt config", "nuxtjs" },
["prettier.config.cjs"] = { "Prettier", "prettier" }, ["prettier.config.cjs"] = { "Prettier", "prettier" },
["prettier.config.js"] = { "Prettier", "prettier" }, ["prettier.config.js"] = { "Prettier", "prettier" },
["profile"] = { "profile", "shell" }, ["profile"] = { "profile", "shell" },
["renovate.json"] = { "Renovate config", "renovate" }, ["renovate.json"] = { "Renovate config", "renovate" },
["requirements.txt"] = { "requirements.txt", "python" }, ["requirements.txt"] = { "requirements.txt", "python" },
["tailwind.config.js"] = { "Tailwind", "tailwind" }, ["tailwind.config.js"] = { "Tailwind", "tailwind" },
["terraform.rc"] = { "Terraform config", "terraform" }, ["terraform.rc"] = { "Terraform config", "terraform" },
["v.mod"] = { "v.mod", "vlang" }, ["v.mod"] = { "v.mod", "vlang" },
["watchman.json"] = { "Watchman config", "watchman" }, ["watchman.json"] = { "Watchman config", "watchman" },
["webpack.config.js"] = { "Webpack", "webpack" }, ["webpack.config.js"] = { "Webpack", "webpack" },
["webpack.config.ts"] = { "Webpack", "webpack" }, ["webpack.config.ts"] = { "Webpack", "webpack" },
["yarn.lock"] = { "Yarn lockfile", "yarn" }, ["yarn.lock"] = { "Yarn lockfile", "yarn" },
["zlogin"] = { "zlogin", "shell" }, ["zlogin"] = { "zlogin", "shell" },
["zlogout"] = { "zlogout", "shell" }, ["zlogout"] = { "zlogout", "shell" },
["zprofile"] = { "zprofile", "shell" }, ["zprofile"] = { "zprofile", "shell" },
["zshenv"] = { "zshenv", "shell" }, ["zshenv"] = { "zshenv", "shell" },
["zshrc"] = { "zshrc", "shell" }, ["zshrc"] = { "zshrc", "shell" },
addressbook = { "abook", "abook" }, addressbook = { "abook", "abook" },
ahk = { "Autohotkey", "autohotkey" }, ahk = { "Autohotkey", "autohotkey" },
applescript = { "Applescript", "applescript" }, applescript = { "Applescript", "applescript" },
bash = { "Bash script", "shell" }, bash = { "Bash script", "shell" },
bib = { "BibTeX", "latex" }, bib = { "BibTeX", "latex" },
c = { "C ", "c" }, c = { "C ", "c" },
cabal = { "Cabal file", "haskell" }, cabal = { "Cabal file", "haskell" },
cc = { "C++", "c_plus_plus" }, cc = { "C++", "c_plus_plus" },
cf = { "Configuration file", "config" }, cf = { "Configuration file", "config" },
cfg = { "Configuration file", "config" }, cfg = { "Configuration file", "config" },
cl = { "Common Lisp", "lisp" }, cl = { "Common Lisp", "lisp" },
clj = { "Clojure", "clojure" }, clj = { "Clojure", "clojure" },
cljs = { "ClojureScript", "clojurescript" }, cljs = { "ClojureScript", "clojurescript" },
cls = { "Visual Basic class module", "visual_basic" }, cls = { "Visual Basic class module", "visual_basic" },
cnf = { "Configuration file", "config" }, cnf = { "Configuration file", "config" },
coffee = { "CoffeeScript", "coffeescript" }, coffee = { "CoffeeScript", "coffeescript" },
conf = { "Configuration file", "config" }, conf = { "Configuration file", "config" },
config = { "Configuration file", "config" }, config = { "Configuration file", "config" },
cpp = { "C++", "c_plus_plus" }, cpp = { "C++", "c_plus_plus" },
cr = { "Crystal", "crystal" }, cr = { "Crystal", "crystal" },
cs = { "C#", "c_sharp" }, cs = { "C#", "c_sharp" },
css = { "CSS", "css" }, css = { "CSS", "css" },
cxx = { "C++", "c_plus_plus" }, cxx = { "C++", "c_plus_plus" },
d = { "D", "d" }, d = { "D", "d" },
dart = { "Dart", "dart" }, dart = { "Dart", "dart" },
dll = { "DLL file", "visual_basic" }, dll = { "DLL file", "visual_basic" },
e = { "Eiffel", "eiffel" }, e = { "Eiffel", "eiffel" },
elm = { "Elm", "elm" }, elm = { "Elm", "elm" },
erl = { "Erlang", "erlang" }, erl = { "Erlang", "erlang" },
ex = { "Elixir", "elixir" }, ex = { "Elixir", "elixir" },
expect = { "Expect", "tcl" }, expect = { "Expect", "tcl" },
fasl = { "Common Lisp", "lisp" }, fasl = { "Common Lisp", "lisp" },
fish = { "Fish script", "fish" }, fish = { "Fish script", "fish" },
fnl = { "Fennel", "fennel" }, fnl = { "Fennel", "fennel" },
fs = { "F#", "f_sharp" }, fs = { "F#", "f_sharp" },
g = { "ANTLR grammar", "antlr" }, g = { "ANTLR grammar", "antlr" },
g3 = { "ANTLR 3 grammar", "antlr" }, g3 = { "ANTLR 3 grammar", "antlr" },
g4 = { "ANTLR 4 grammar", "antlr" }, g4 = { "ANTLR 4 grammar", "antlr" },
gemspec = { "Gem Spec", "ruby" }, gemspec = { "Gem Spec", "ruby" },
go = { "Go", "go" }, go = { "Go", "go" },
gql = { "GraphQL", "graphql" }, gql = { "GraphQL", "graphql" },
graphql = { "GraphQL", "graphql" }, graphql = { "GraphQL", "graphql" },
groovy = { "Groovy", "groovy" }, groovy = { "Groovy", "groovy" },
gsh = { "Groovy", "groovy" }, gsh = { "Groovy", "groovy" },
gvy = { "Groovy", "groovy" }, gvy = { "Groovy", "groovy" },
gy = { "Groovy", "groovy" }, gy = { "Groovy", "groovy" },
h = { "C header file", "c" }, h = { "C header file", "c" },
hack = { "Hack", "hack" }, hack = { "Hack", "hack" },
haml = { "Haml", "haml" }, haml = { "Haml", "haml" },
hpp = { "C++ header file", "c_plus_plus" }, hpp = { "C++ header file", "c_plus_plus" },
hs = { "Haskell", "haskell" }, hs = { "Haskell", "haskell" },
html = { "HTML", "html" }, html = { "HTML", "html" },
hx = { "Haxe", "haxe" }, hx = { "Haxe", "haxe" },
hxx = { "C++ header file", "c_plus_plus" }, hxx = { "C++ header file", "c_plus_plus" },
idr = { "Idris", "idris" }, idr = { "Idris", "idris" },
ini = { "Configuration file", "config" }, ini = { "Configuration file", "config" },
ino = { "Arduino", "arduino" }, ino = { "Arduino", "arduino" },
ipynb = { "Jupyter Notebook", "jupyter" }, ipynb = { "Jupyter Notebook", "jupyter" },
java = { "Java", "java" }, java = { "Java", "java" },
jl = { "Julia", "julia" }, jl = { "Julia", "julia" },
js = { "JavaScript", "javascript" }, js = { "JavaScript", "javascript" },
json = { "JSON", "json" }, json = { "JSON", "json" },
jsx = { "React", "react" }, jsx = { "React", "react" },
ksh = { "KornShell script", "shell" }, ksh = { "KornShell script", "shell" },
kshrc = { "KornShell config", "shell" }, kshrc = { "KornShell config", "shell" },
kt = { "Kotlin", "kotlin" }, kt = { "Kotlin", "kotlin" },
kv = { "Kivy", "kivy" }, kv = { "Kivy", "kivy" },
l = { "Common Lisp", "lisp" }, l = { "Common Lisp", "lisp" },
less = { "Less", "less" }, less = { "Less", "less" },
lidr = { "Idris", "idris" }, lidr = { "Idris", "idris" },
liquid = { "Liquid", "liquid" }, liquid = { "Liquid", "liquid" },
lisp = { "Common Lisp", "lisp" }, lisp = { "Common Lisp", "lisp" },
log = { "Log file", "code" }, log = { "Log file", "code" },
lsp = { "Common Lisp", "lisp" }, lsp = { "Common Lisp", "lisp" },
lua = { "Lua", "lua" }, lua = { "Lua", "lua" },
m = { "MATLAB", "matlab" }, m = { "MATLAB", "matlab" },
markdown = { "Markdown", "markdown" }, markdown = { "Markdown", "markdown" },
mat = { "MATLAB", "matlab" }, mat = { "MATLAB", "matlab" },
md = { "Markdown", "markdown" }, md = { "Markdown", "markdown" },
mdx = { "MDX", "mdx" }, mdx = { "MDX", "mdx" },
mjs = { "JavaScript", "javascript" }, mjs = { "JavaScript", "javascript" },
ml = { "OCaml", "ocaml" }, ml = { "OCaml", "ocaml" },
nim = { "Nim", "nim" }, nim = { "Nim", "nim" },
nix = { "Nix", "nix" }, nix = { "Nix", "nix" },
norg = { "Neorg", "neorg" }, norg = { "Neorg", "neorg" },
org = { "Org", "org" }, org = { "Org", "org" },
pb = { "Protobuf", "protobuf" }, pb = { "Protobuf", "protobuf" },
pcss = { "PostCSS", "postcss" }, pcss = { "PostCSS", "postcss" },
pgsql = { "PostgreSQL", "pgsql" }, pgsql = { "PostgreSQL", "pgsql" },
php = { "PHP", "php" }, php = { "PHP", "php" },
pl = { "Perl", "perl" }, pl = { "Perl", "perl" },
plist = { "Property List", "markup" }, plist = { "Property List", "markup" },
postcss = { "PostCSS", "postcss" }, postcss = { "PostCSS", "postcss" },
proto = { "Protobuf", "protobuf" }, proto = { "Protobuf", "protobuf" },
ps1 = { "PowerShell", "powershell" }, ps1 = { "PowerShell", "powershell" },
psd1 = { "PowerShell", "powershell" }, psd1 = { "PowerShell", "powershell" },
psm1 = { "PowerShell", "powershell" }, psm1 = { "PowerShell", "powershell" },
purs = { "PureScript", "purescript" }, purs = { "PureScript", "purescript" },
py = { "Python", "python" }, py = { "Python", "python" },
r = { "R", "r" }, r = { "R", "r" },
raku = { "Raku", "raku" }, raku = { "Raku", "raku" },
rakudoc = { "Raku", "raku" }, rakudoc = { "Raku", "raku" },
rakumod = { "Raku", "raku" }, rakumod = { "Raku", "raku" },
rakutest = { "Raku", "raku" }, rakutest = { "Raku", "raku" },
rb = { "Ruby", "ruby" }, rb = { "Ruby", "ruby" },
re = { "Reason", "reason" }, re = { "Reason", "reason" },
res = { "ReScript", "rescript" }, res = { "ReScript", "rescript" },
rkt = { "Racket", "racket"}, rkt = { "Racket", "racket" },
rs = { "Rust", "rust" }, rs = { "Rust", "rust" },
sass = { "Sass", "sass" }, sass = { "Sass", "sass" },
scala = { "Scala", "scala" }, scala = { "Scala", "scala" },
scm = { "Scheme", "scheme" }, scm = { "Scheme", "scheme" },
scss = { "Sass", "scss" }, scss = { "Sass", "scss" },
sh = { "Shell script", "shell" }, sh = { "Shell script", "shell" },
shrc = { "Shell config", "shell" }, shrc = { "Shell config", "shell" },
snap = { "Jest Snapshot", "jest" }, snap = { "Jest Snapshot", "jest" },
sql = { "SQL", "database" }, sql = { "SQL", "database" },
ss = { "Scheme", "scheme" }, ss = { "Scheme", "scheme" },
svelte = { "Svelte", "svelte" }, svelte = { "Svelte", "svelte" },
svg = { "SVG", "markup" }, svg = { "SVG", "markup" },
swift = { "Swift", "swift" }, swift = { "Swift", "swift" },
tcl = { "Tcl", "tcl" }, tcl = { "Tcl", "tcl" },
tex = { "LaTeX", "latex" }, tex = { "LaTeX", "latex" },
text = { "Text file", "text" }, text = { "Text file", "text" },
tf = { "Terraform", "terraform" }, tf = { "Terraform", "terraform" },
tk = { "Tcl/Tk", "tcl" }, tk = { "Tcl/Tk", "tcl" },
tl = { "Teal", "teal" }, tl = { "Teal", "teal" },
toml = { "TOML", "toml" }, toml = { "TOML", "toml" },
ts = { "TypeScript", "typescript" }, ts = { "TypeScript", "typescript" },
tsx = { "React", "react" }, tsx = { "React", "react" },
txt = { "Text file", "text" }, txt = { "Text file", "text" },
uc = { "UnrealScript", "unreal" }, uc = { "UnrealScript", "unreal" },
v = { "Vlang", "vlang" }, v = { "Vlang", "vlang" },
vsh = { "Vlang shell script", "vlang" }, vsh = { "Vlang shell script", "vlang" },
vb = { "Visual Basic", "visual_basic" }, vb = { "Visual Basic", "visual_basic" },
vbp = { "Visual Basic project file", "visual_basic" }, vbp = { "Visual Basic project file", "visual_basic" },
vim = { "Vim", "vim" }, vim = { "Vim", "vim" },
viml = { "Vim", "vim" }, viml = { "Vim", "vim" },
vue = { "Vue", "vue" }, vue = { "Vue", "vue" },
wasm = { "WebAssembly", "webassembly" }, wasm = { "WebAssembly", "webassembly" },
wast = { "WebAssembly", "webassembly" }, wast = { "WebAssembly", "webassembly" },
wat = { "WebAssembly", "webassembly" }, wat = { "WebAssembly", "webassembly" },
xml = { "XML", "markup" }, xml = { "XML", "markup" },
xsd = { "XML Schema", "markup" }, xsd = { "XML Schema", "markup" },
xslt = { "XSLT", "markup" }, xslt = { "XSLT", "markup" },
yaml = { "YAML", "yaml" }, yaml = { "YAML", "yaml" },
yml = { "YAML", "yaml" }, yml = { "YAML", "yaml" },
zig = { "Zig", "zig" }, zig = { "Zig", "zig" },
zsh = { "Zsh script", "shell" }, zsh = { "Zsh script", "shell" },
zu = { "Zimbu", "zimbu" }, zu = { "Zimbu", "zimbu" },
} }

View file

@ -1,10 +1,10 @@
-- Different neovim file explorer names keyed by filetype or buffer name -- Different neovim file explorer names keyed by filetype or buffer name
return { return {
["NvimTree"] = "NvimTree", ["NvimTree"] = "NvimTree",
["NERD_tree_"] = "NERDTree", ["NERD_tree_"] = "NERDTree",
["[defx] default-"] = "Defx", ["[defx] default-"] = "Defx",
["netrw"] = "Netrw", ["netrw"] = "Netrw",
["TelescopePrompt"] = "Telescope", ["TelescopePrompt"] = "Telescope",
['neo-tree'] = 'Neotree', ["neo-tree"] = "Neotree",
['fern'] = 'Fern' ["fern"] = "Fern",
} }

File diff suppressed because it is too large Load diff