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:
commit
8b18beb367
15 changed files with 2264 additions and 1938 deletions
59
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
59
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
|
@ -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
|
||||||
|
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
|
@ -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.
|
|
34
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
34
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal 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
|
14
.github/workflows/CI.yml
vendored
14
.github/workflows/CI.yml
vendored
|
@ -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
10
.github/workflows/luacheck.yml
vendored
Normal 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
15
.github/workflows/stylua.yml
vendored
Normal 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
123
README.md
|
@ -1,41 +1,63 @@
|
||||||
<img src="https://gist.githubusercontent.com/andweeb/df3216345530234289b87cf5080c2c60/raw/8de399cfed82c137f793e9f580027b5246bc4379/presence.nvim.png" alt="presence.nvim">​
|
# 
|
||||||
|
|
||||||
**[Features](#features)** | **[Installation](#installation)** | **[Configuration](#configuration)** | **[Troubleshooting](#troubleshooting)** | **[Development](#development)** | **[Contributing](#contributing)**
|
This repository uses
|
||||||
|
[](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">
|

|
||||||
|
|
||||||
## 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).
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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" },
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
Loading…
Reference in a new issue