Skip to content

Commit

Permalink
feat: init commit
Browse files Browse the repository at this point in the history
  • Loading branch information
rcarriga committed Aug 3, 2021
0 parents commit 57ca80d
Show file tree
Hide file tree
Showing 17 changed files with 722 additions and 0 deletions.
56 changes: 56 additions & 0 deletions .github/workflows/workflow.yaml
@@ -0,0 +1,56 @@
name: nvim-notify Workflow
on: [push]
jobs:
style:
name: style
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: JohnnyMorganz/stylua-action@1.0.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --check lua/ tests/

tests:
name: tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: date +%F > todays-date
- name: Restore cache for today's nightly.
uses: actions/cache@v2
with:
path: _neovim
key: ${{ runner.os }}-x64-${{ hashFiles('todays-date') }}

- name: Prepare dependencies
run: |
git clone --depth 1 https://github.com/nvim-lua/plenary.nvim ~/.local/share/nvim/site/pack/vendor/start/plenary.nvim
ln -s $(pwd) ~/.local/share/nvim/site/pack/vendor/start
- name: Run tests
run: |
curl -OL https://raw.githubusercontent.com/norcalli/bot-ci/master/scripts/github-actions-setup.sh
source github-actions-setup.sh nightly-x64
./scripts/test
release:
name: release
if: ${{ github.ref == 'refs/heads/master' }}
needs:
- style
- tests
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v1
with:
node-version: 12
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npx semantic-release
2 changes: 2 additions & 0 deletions .gitignore
@@ -0,0 +1,2 @@
neovim/
plenary.nvim/
12 changes: 12 additions & 0 deletions .releaserc.json
@@ -0,0 +1,12 @@
{
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
[
"@semantic-release/github",
{
"successComment": false
}
]
]
}
63 changes: 63 additions & 0 deletions README.md
@@ -0,0 +1,63 @@
# nvim-notify

**This is in proof of concept stage right now, changes are very likely but you are free to try it out and give feedback!**

A fancy, configurable, notification manager for NeoVim

![notify](https://user-images.githubusercontent.com/24252670/128085627-d1c0d929-5a98-4743-9cf0-5c1bc3367f0a.gif)

## Usage

Simply call the module with a message!

```lua
require("notify")("My super important message")
```

Other plugins can use the notification windows by setting it as your default notify function

```lua
vim.notify = require("notify")
```

You can supply a level to change the border highlighting
```lua
vim.notify("This is an error message", "error")
```

There are a number of custom options that can be supplied in a table as the third argument:

- `timeout`: Number of milliseconds to show the window (default 5000)
- `on_open`: A function to call with the window ID as an argument after opening
- `on_close`: A function to call with the window ID as an argument after closing
- `title`: Title string for the header
- `icon`: Icon to use for the header

Sample code for the GIF above:
```lua
local plugin = "My Awesome Plugin"

vim.notify("This is an error message.\nSomething went wrong!", "error", {
title = plugin,
on_open = function()
vim.notify("Attempting recovery.", vim.lsp.log_levels.WARN, {
title = plugin,
})
local timer = vim.loop.new_timer()
timer:start(2000, 0, function()
vim.notify({ "Fixing problem.", "Please wait..." }, "info", {
title = plugin,
timeout = 3000,
on_close = function()
vim.notify("Problem solved", nil, { title = plugin })
vim.notify("Error code 0x0395AF", 1, { title = plugin })
end,
})
end)
end,
})
```

## Configuration

TODO!
5 changes: 5 additions & 0 deletions lua/notify/animate/init.lua
@@ -0,0 +1,5 @@
local M = {}

M.spring = require("notify.animate.spring")

return M
67 changes: 67 additions & 0 deletions lua/notify/animate/spring.lua
@@ -0,0 +1,67 @@
-- Adapted from https://gist.github.com/Fraktality/1033625223e13c01aa7144abe4aaf54d
-- Explanation found here https://www.ryanjuckett.com/damped-springs/
local pi = math.pi
local exp = math.exp
local sin = math.sin
local cos = math.cos
local sqrt = math.sqrt

---@class SpringState
---@field position number
---@field goal number
---@field velocity number | nil
---@field damping number
---@field frequency number

---@param dt number @Step in time
---@param state SpringState
---@return SpringState
return function(dt, state)
local damping = state.damping
local angular_freq = state.frequency * 2 * pi
local cur_os = state.position
local cur_vel = state.velocity or 0
local goal = state.goal

local offset = cur_os - goal
local decay = exp(-dt * damping * angular_freq)

local new_pos
local new_vel

if damping == 1 then -- critically damped
new_pos = (cur_vel * dt + offset * (angular_freq * dt + 1)) * decay + goal
new_vel = (cur_vel - angular_freq * dt * (offset * angular_freq + cur_vel)) * decay
elseif damping < 1 then -- underdamped
local c = sqrt(1 - damping * damping)

local i = cos(angular_freq * c * dt)
local j = sin(angular_freq * c * dt)

new_pos = (i * offset + j * (cur_vel + damping * angular_freq * offset) / (angular_freq * c))
* decay
+ goal
new_vel = (i * c * cur_vel - j * (cur_vel * damping + angular_freq * offset)) * decay / c
elseif damping > 1 then -- overdamped
local c = sqrt(damping * damping - 1)

local r1 = -angular_freq * (damping - c)
local r2 = -angular_freq * (damping + c)

local co2 = (cur_vel - r1 * offset) / (2 * angular_freq * c)
local co1 = offset - co2

local e1 = co1 * exp(r1 * dt)
local e2 = co2 * exp(r2 * dt)

new_pos = e1 + e2 + goal
new_pos = r1 * e1 + r2 * e2
end
return {
position = new_pos,
velocity = new_vel,
goal = goal,
damping = state.damping,
frequency = state.frequency,
}
end
5 changes: 5 additions & 0 deletions lua/notify/animate/window.lua
@@ -0,0 +1,5 @@
local WindowAnimator = {}

function WindowAnimator:update_states() end

return WindowAnimator
10 changes: 10 additions & 0 deletions lua/notify/config/highlights.lua
@@ -0,0 +1,10 @@
vim.cmd("hi default NotifyERROR guifg=#8A1F1F")
vim.cmd("hi default NotifyWARN guifg=#79491D")
vim.cmd("hi default NotifyINFO guifg=#4F6752")
vim.cmd("hi default NotifyDEBUG guifg=#8B8B8B")
vim.cmd("hi default NotifyTRACE guifg=#4F3552")
vim.cmd("hi default NotifyERRORTitle guifg=#F70067")
vim.cmd("hi default NotifyWARNTitle guifg=#F79000")
vim.cmd("hi default NotifyINFOTitle guifg=#A9FF68")
vim.cmd("hi default NotifyDEBUGTitle guifg=#8B8B8B")
vim.cmd("hi default NotifyTRACETitle guifg=#D484FF")
27 changes: 27 additions & 0 deletions lua/notify/config/init.lua
@@ -0,0 +1,27 @@
local M = {}

require("notify.config.highlights")

local default_config = {
icons = {
ERROR = "",
WARN = "",
INFO = "",
DEBUG = "",
TRACE = "",
},
}

local user_config = default_config

function M.setup(config)
local filled = vim.tbl_deep_extend("keep", config or {}, default_config)
user_config = filled
require("dapui.config.highlights").setup()
end

function M.icons()
return user_config.icons
end

return M
83 changes: 83 additions & 0 deletions lua/notify/init.lua
@@ -0,0 +1,83 @@
local NotificationRenderer = require("notify.render")
local config = require("notify.config")

local renderer = NotificationRenderer()

local running = false

local function run()
running = true
local succees, ran = pcall(renderer.step, renderer, 30 / 1000)
if not succees then
print("Error running notification service: " .. ran)
running = false
return
end
if not ran then
running = false
return
end
vim.defer_fn(run, 30)
end

local notifications = {}

---@class Notification
---@field level string
---@field message string
---@field timeout number
---@field title string
---@field icon string
---@field time number
---@field width number
---@field on_open fun(win: number) | nil
---@field on_close fun(win: number) | nil
local Notification = {}

function Notification:new(message, level, opts)
if type(level) == "number" then
level = vim.lsp.log_levels[level]
end
if type(message) == "string" then
message = vim.split(message, "\n")
end
level = vim.fn.toupper(level or "info")
local notif = {
message = message,
title = opts.title or "",
icon = opts.icon or config.icons()[level] or config.icons().INFO,
time = vim.fn.localtime(),
timeout = opts.timeout or 5000,
level = level,
on_open = opts.on_open,
on_close = opts.on_close,
}
self.__index = self
setmetatable(notif, self)
return notif
end

---@class NotifyOptions
---@field title string | nil
---@field icon string | nil
---@field timeout number | nil
---@field on_open fun(win: number) | nil
---@field on_close fun(win: number) | nil

---@param opts NotifyOptions
local function notify(_, message, level, opts)
vim.schedule(function()
local notif = Notification:new(message, level, opts or {})
notifications[#notifications + 1] = notif
renderer:queue(notif)
if not running then
run()
end
end)
end

local M = {}

setmetatable(M, { __call = notify })

return M

0 comments on commit 57ca80d

Please sign in to comment.