1

Refresh generated nvim config

This commit is contained in:
2024-06-05 13:03:21 +02:00
parent c9bb45dfc4
commit bbcc7f34a3
31 changed files with 3002 additions and 0 deletions

View File

@ -0,0 +1,2 @@
github: glepnir
custom: ['https://www.paypal.me/bobbyhub']

View File

@ -0,0 +1,24 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.

View File

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

View File

@ -0,0 +1,38 @@
name: ci
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Stylua
uses: JohnnyMorganz/stylua-action@v1.1.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --check .
docs:
runs-on: ubuntu-latest
name: pandoc to vimdoc
steps:
- uses: actions/checkout@v3
- name: panvimdoc
uses: kdheepak/panvimdoc@main
with:
vimdoc: dashboard
version: Nvim 0.8.0
- uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: 'chore(doc): auto generate docs'
commit_user_name: "github-actions[bot]"
commit_user_email: "github-actions[bot]@users.noreply.github.com"
commit_author: "github-actions[bot] <github-actions[bot]@users.noreply.github.com>"

View File

@ -0,0 +1,6 @@
column_width = 100
line_endings = "Unix"
indent_type = "Spaces"
indent_width = 2
quote_style = "AutoPreferSingle"
call_parentheses = "Always"

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 StephenHuan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,250 @@
<h1 align="center">
Fancy and Blazing Fast start screen plugin of neovim
</h1>
| <center>Hyper</center> | <center>Doom</center> |
| --- | --- |
| <center><img src="https://user-images.githubusercontent.com/41671631/215015845-b13343c4-427e-45d6-9f92-267ab909eff1.png" width=80% height=80%/></center>|<center> <img src="https://user-images.githubusercontent.com/41671631/214518543-d7d6afbf-f405-4a6f-a505-568c5a101e92.png" width=80% height=80%/> </center>|
# Feature
- Low memory usage. dashboard does not store the all user configs in memory like header etc these string will take some memory. now it will be clean after you open a file. you can still use dashboard command to open a new one , then dashboard will read the config from cache.
- Blazing fast
# Install
- Lazy.nvim
```lua
{
'nvimdev/dashboard-nvim',
event = 'VimEnter',
config = function()
require('dashboard').setup {
-- config
}
end,
dependencies = { {'nvim-tree/nvim-web-devicons'}}
}
```
- Packer
```lua
use {
'nvimdev/dashboard-nvim',
event = 'VimEnter',
config = function()
require('dashboard').setup {
-- config
}
end,
requires = {'nvim-tree/nvim-web-devicons'}
}
```
# Configuration
## Options
```lua
theme = 'hyper' -- theme is doom and hyper default is hyper
disable_move -- default is false disable move keymap for hyper
shortcut_type -- shorcut type 'letter' or 'number'
change_to_vcs_root -- default is false,for open file in hyper mru. it will change to the root of vcs
config = {}, -- config used for theme
hide = {
statusline -- hide statusline default is true
tabline -- hide the tabline
winbar -- hide winbar
},
preview = {
command -- preview command
file_path -- preview file path
file_height -- preview file height
file_width -- preview file width
},
```
## Theme config
the `config` field is used for theme. general field
```lua
config = {
header -- type is table def
week_header = {
enable --boolean use a week header
concat --concat string after time string line
append --table append after time string line
},
disable_move -- boolean default is false disable move key
}
```
### Hyper
when use `hyper` theme the available options in `config` is
```lua
config = {
shortcut = {
-- action can be a function type
{ desc = string, group = 'highlight group', key = 'shortcut key', action = 'action when you press key' },
},
packages = { enable = true }, -- show how many plugins neovim loaded
-- limit how many projects list, action when you press key or enter it will run this action.
-- action can be a functino type, e.g.
-- action = func(path) vim.cmd('Telescope find_files cwd=' .. path) end
project = { enable = true, limit = 8, icon = 'your icon', label = '', action = 'Telescope find_files cwd=' },
mru = { limit = 10, icon = 'your icon', label = '', cwd_only = false },
footer = {}, -- footer
}
```
### Doom
when use `doom` theme the available options in `config` is
```lua
config = {
center = {
{
icon = '',
icon_hl = 'group',
desc = 'description',
desc_hl = 'group',
key = 'shortcut key in dashboard buffer not keymap !!',
key_hl = 'group',
key_format = ' [%s]', -- `%s` will be substituted with value of `key`
action = '',
},
},
footer = {},
}
```
notice if you don't link config every highlight group. you can ignore this key.
dashboard will use default highlight group like `DashboardKey/Icon/Desc` instead
### Commands
- `Dashboard` open dashboard
- `DbProjectDelete count` delete project in cache works for hyper theme. count is number
- `DashboardUpdateFooter` updates the content of the Footer
### Highlight
all highlight groups
```
-- General
DashboardHeader DashboardFooter
-- Hyper theme
DashboardProjectTitle DashboardProjectTitleIcon DashboardProjectIcon
DashboardMruTitle DashboardMruIcon DashboardFiles DashboardShortCutIcon
-- Doome theme
DashboardDesc DashboardKey DashboardIcon DashboardShortCut
```
### Example config
example config of screenshot
<details>
<summary> Hyper </summary>
```lua
db.setup({
theme = 'hyper',
config = {
week_header = {
enable = true,
},
shortcut = {
{ desc = '󰊳 Update', group = '@property', action = 'Lazy update', key = 'u' },
{
icon = ' ',
icon_hl = '@variable',
desc = 'Files',
group = 'Label',
action = 'Telescope find_files',
key = 'f',
},
{
desc = ' Apps',
group = 'DiagnosticHint',
action = 'Telescope app',
key = 'a',
},
{
desc = ' dotfiles',
group = 'Number',
action = 'Telescope dotfiles',
key = 'd',
},
},
},
})
```
</details>
<details>
<summary> Doom </summary>
```lua
db.setup({
theme = 'doom',
config = {
header = {}, --your header
center = {
{
icon = ' ',
icon_hl = 'Title',
desc = 'Find File ',
desc_hl = 'String',
key = 'b',
keymap = 'SPC f f',
key_hl = 'Number',
key_format = ' %s', -- remove default surrounding `[]`
action = 'lua print(2)'
},
{
icon = ' ',
desc = 'Find Dotfiles',
key = 'f',
keymap = 'SPC f d',
key_format = ' %s', -- remove default surrounding `[]`
action = 'lua print(3)'
},
},
footer = {} --your footer
}
})
```
</details
### Changed
- Removed Session as a start screen plugin speed is first.if you want use session you can take a
look at [glepnir/dbsession.nvim](https://github.com/glepnir/dbsession.nvim)
- Removed Ueberzug script, as the Ueberzug author has deleted the repository.
### TODO
- I will write a plugin to implement some popular terminal evaluators image protocol then I think
can make it work with dashboard
# Backers
[@RakerZh](https://github.com/RakerZh)
# Donate
If you'd like to support my work financially, buy me a drink through Github Sponsor or [![](https://img.shields.io/badge/PayPal-00457C?style=for-the-badge&logo=paypal&logoColor=white)](https://paypal.me/bobbyhub)
# LICENSE
MIT

View File

@ -0,0 +1,289 @@
*dashboard.txt* For Nvim 0.8.0 Last change: 2024 May 17
==============================================================================
Table of Contents *dashboard-table-of-contents*
1. Feature |dashboard-feature|
2. Install |dashboard-install|
3. Configuration |dashboard-configuration|
- Options |dashboard-configuration-options|
- Theme config |dashboard-configuration-theme-config|
4. Backers |dashboard-backers|
5. Donate |dashboard-donate|
6. LICENSE |dashboard-license|
7. Links |dashboard-links|
Fancy and Blazing Fast start screen plugin of neovim ----------------------------------- -----------------------------------
----------------------------------- -----------------------------------
==============================================================================
1. Feature *dashboard-feature*
- Low memory usage. dashboard does not store the all user configs in memory like header etc these string will take some memory. now it will be clean after you open a file. you can still use dashboard command to open a new one , then dashboard will read the config from cache.
- Blazing fast
==============================================================================
2. Install *dashboard-install*
- Lazy.nvim
>lua
{
'nvimdev/dashboard-nvim',
event = 'VimEnter',
config = function()
require('dashboard').setup {
-- config
}
end,
dependencies = { {'nvim-tree/nvim-web-devicons'}}
}
<
- Packer
>lua
use {
'nvimdev/dashboard-nvim',
event = 'VimEnter',
config = function()
require('dashboard').setup {
-- config
}
end,
requires = {'nvim-tree/nvim-web-devicons'}
}
<
==============================================================================
3. Configuration *dashboard-configuration*
OPTIONS *dashboard-configuration-options*
>lua
theme = 'hyper' -- theme is doom and hyper default is hyper
disable_move -- default is false disable move keymap for hyper
shortcut_type -- shorcut type 'letter' or 'number'
change_to_vcs_root -- default is false,for open file in hyper mru. it will change to the root of vcs
config = {}, -- config used for theme
hide = {
statusline -- hide statusline default is true
tabline -- hide the tabline
winbar -- hide winbar
},
preview = {
command -- preview command
file_path -- preview file path
file_height -- preview file height
file_width -- preview file width
},
<
THEME CONFIG *dashboard-configuration-theme-config*
the `config` field is used for theme. general field
>lua
config = {
header -- type is table def
week_header = {
enable --boolean use a week header
concat --concat string after time string line
append --table append after time string line
},
disable_move -- boolean default is false disable move key
}
<
HYPER ~
when use `hyper` theme the available options in `config` is
>lua
config = {
shortcut = {
-- action can be a function type
{ desc = string, group = 'highlight group', key = 'shortcut key', action = 'action when you press key' },
},
packages = { enable = true }, -- show how many plugins neovim loaded
-- limit how many projects list, action when you press key or enter it will run this action.
-- action can be a functino type, e.g.
-- action = func(path) vim.cmd('Telescope find_files cwd=' .. path) end
project = { enable = true, limit = 8, icon = 'your icon', label = '', action = 'Telescope find_files cwd=' },
mru = { limit = 10, icon = 'your icon', label = '', cwd_only = false },
footer = {}, -- footer
}
<
DOOM ~
when use `doom` theme the available options in `config` is
>lua
config = {
center = {
{
icon = '',
icon_hl = 'group',
desc = 'description',
desc_hl = 'group',
key = 'shortcut key in dashboard buffer not keymap !!',
key_hl = 'group',
key_format = ' [%s]', -- `%s` will be substituted with value of `key`
action = '',
},
},
footer = {},
}
<
notice if you dont link config every highlight group. you can ignore this
key. dashboard will use default highlight group like `DashboardKey/Icon/Desc`
instead
COMMANDS ~
- `Dashboard` open dashboard
- `DbProjectDelete count` delete project in cache works for hyper theme. count is number
- `DashboardUpdateFooter` updates the content of the Footer
HIGHLIGHT ~
all highlight groups
>
-- General
DashboardHeader DashboardFooter
-- Hyper theme
DashboardProjectTitle DashboardProjectTitleIcon DashboardProjectIcon
DashboardMruTitle DashboardMruIcon DashboardFiles DashboardShortCutIcon
-- Doome theme
DashboardDesc DashboardKey DashboardIcon DashboardShortCut
<
EXAMPLE CONFIG ~
example config of screenshot
Hyper ~
>lua
db.setup({
theme = 'hyper',
config = {
week_header = {
enable = true,
},
shortcut = {
{ desc = '󰊳 Update', group = '@property', action = 'Lazy update', key = 'u' },
{
icon = ' ',
icon_hl = '@variable',
desc = 'Files',
group = 'Label',
action = 'Telescope find_files',
key = 'f',
},
{
desc = ' Apps',
group = 'DiagnosticHint',
action = 'Telescope app',
key = 'a',
},
{
desc = ' dotfiles',
group = 'Number',
action = 'Telescope dotfiles',
key = 'd',
},
},
},
})
<
Doom ~
>lua
db.setup({
theme = 'doom',
config = {
header = {}, --your header
center = {
{
icon = ' ',
icon_hl = 'Title',
desc = 'Find File ',
desc_hl = 'String',
key = 'b',
keymap = 'SPC f f',
key_hl = 'Number',
key_format = ' %s', -- remove default surrounding `[]`
action = 'lua print(2)'
},
{
icon = ' ',
desc = 'Find Dotfiles',
key = 'f',
keymap = 'SPC f d',
key_format = ' %s', -- remove default surrounding `[]`
action = 'lua print(3)'
},
},
footer = {} --your footer
}
})
<
</details
CHANGED ~
- Removed Session as a start screen plugin speed is first.if you want use session you can take a
look at glepnir/dbsession.nvim <https://github.com/glepnir/dbsession.nvim>
- Removed Ueberzug script, as the Ueberzug author has deleted the repository.
TODO ~
- I will write a plugin to implement some popular terminal evaluators image protocol then I think
can make it work with dashboard
==============================================================================
4. Backers *dashboard-backers*
@RakerZh <https://github.com/RakerZh>
==============================================================================
5. Donate *dashboard-donate*
If youd like to support my work financially, buy me a drink through Github
Sponsor or <https://paypal.me/bobbyhub>
==============================================================================
6. LICENSE *dashboard-license*
MIT
==============================================================================
7. Links *dashboard-links*
1. *@RakerZh*:
2. **: https://img.shields.io/badge/PayPal-00457C?style=for-the-badge&logo=paypal&logoColor=white
Generated by panvimdoc <https://github.com/kdheepak/panvimdoc>
vim:tw=78:ts=8:noet:ft=help:norl:

View File

@ -0,0 +1,11 @@
dashboard-backers dashboard.txt /*dashboard-backers*
dashboard-configuration dashboard.txt /*dashboard-configuration*
dashboard-configuration-options dashboard.txt /*dashboard-configuration-options*
dashboard-configuration-theme-config dashboard.txt /*dashboard-configuration-theme-config*
dashboard-donate dashboard.txt /*dashboard-donate*
dashboard-feature dashboard.txt /*dashboard-feature*
dashboard-install dashboard.txt /*dashboard-install*
dashboard-license dashboard.txt /*dashboard-license*
dashboard-links dashboard.txt /*dashboard-links*
dashboard-table-of-contents dashboard.txt /*dashboard-table-of-contents*
dashboard.txt dashboard.txt /*dashboard.txt*

View File

@ -0,0 +1,59 @@
local api, lsp, uv = vim.api, vim.lsp, vim.loop
local au = {}
local get_lsp_clients = vim.fn.has('nvim-0.10') == 1 and vim.lsp.get_clients
or lsp.get_active_clients
function au.register_lsp_root(path)
api.nvim_create_autocmd('VimLeavePre', {
callback = function()
local projects = {}
for _, client in pairs(get_lsp_clients() or {}) do
local root_dir = client.config.root_dir
if root_dir and not vim.tbl_contains(projects, root_dir) then
table.insert(projects, root_dir)
end
for _, folder in pairs(client.workspace_folders or {}) do
if not vim.tbl_contains(projects, folder.name) then
table.insert(projects, folder.name)
end
end
end
if #projects == 0 then
return
end
-- callback hell holy shit but simply than write a async await lib
-- also I don't link to add a thirdpart plugin. this is just a small code
uv.fs_open(path, 'r+', 384, function(err, fd)
assert(not err, err)
uv.fs_fstat(fd, function(err, stat)
assert(not err, err)
uv.fs_read(fd, stat.size, 0, function(err, data)
assert(not err, err)
local before = assert(loadstring(data))
local plist = before()
if plist and #plist > 10 then
plist = vim.list_slice(plist, 10)
end
plist = vim.tbl_filter(function(k)
return not vim.tbl_contains(projects, k)
end, plist or {})
plist = vim.list_extend(plist, projects)
local dump = 'return ' .. vim.inspect(plist)
uv.fs_write(fd, dump, 0, function(err, _)
assert(not err, err)
uv.fs_ftruncate(fd, #dump, function(err, _)
assert(not err, err)
uv.fs_close(fd)
end)
end)
end)
end)
end)
end,
})
end
return au

View File

@ -0,0 +1,278 @@
local api, fn = vim.api, vim.fn
local utils = require('dashboard.utils')
local ctx = {}
local db = {}
db.__index = db
db.__newindex = function(t, k, v)
rawset(t, k, v)
end
local function clean_ctx()
for k, _ in pairs(ctx) do
ctx[k] = nil
end
end
local function cache_dir()
local dir = utils.path_join(vim.fn.stdpath('cache'), 'dashboard')
if fn.isdirectory(dir) == 0 then
fn.mkdir(dir, 'p')
end
return dir
end
local function cache_path()
local dir = cache_dir()
return utils.path_join(dir, 'cache')
end
local function conf_cache_path()
return utils.path_join(cache_dir(), 'conf')
end
local function default_options()
return {
theme = 'hyper',
disable_move = false,
shortcut_type = 'letter',
buffer_name = 'Dashboard',
change_to_vcs_root = false,
config = {
week_header = {
enable = false,
concat = nil,
append = nil,
},
},
hide = {
statusline = true,
tabline = true,
},
preview = {
command = '',
file_path = nil,
file_height = 0,
file_width = 0,
},
}
end
local function buf_local()
local opts = {
['bufhidden'] = 'wipe',
['colorcolumn'] = '',
['foldcolumn'] = '0',
['matchpairs'] = '',
['buflisted'] = false,
['cursorcolumn'] = false,
['cursorline'] = false,
['list'] = false,
['number'] = false,
['relativenumber'] = false,
['spell'] = false,
['swapfile'] = false,
['readonly'] = false,
['filetype'] = 'dashboard',
['wrap'] = false,
['signcolumn'] = 'no',
['winbar'] = '',
}
for opt, val in pairs(opts) do
vim.opt_local[opt] = val
end
if fn.has('nvim-0.9') == 1 then
vim.opt_local.stc = ''
end
end
function db:new_file()
vim.cmd('enew')
if self.user_laststatus_value then
vim.opt_local.laststatus = self.user_laststatus_value
self.user_laststatus_value = nil
end
if self.user_tabline_value then
vim.opt_local.showtabline = self.user_showtabline_value
self.user_showtabline_value = nil
end
end
-- cache the user options value restore after leave the dahsboard buffer
-- or use DashboardNewFile command
function db:cache_ui_options(opts)
if opts.hide.statusline then
---@diagnostic disable-next-line: param-type-mismatch
self.user_laststatus_value = vim.opt.laststatus:get()
vim.opt.laststatus = 0
end
if opts.hide.tabline then
---@diagnostic disable-next-line: param-type-mismatch
self.user_tabline_value = vim.opt.showtabline:get()
vim.opt.showtabline = 0
end
end
function db:restore_options()
if self.user_cursor_line then
vim.opt.cursorline = self.user_cursor_line
self.user_cursor_line = nil
end
if self.user_laststatus_value then
vim.opt.laststatus = tonumber(self.user_laststatus_value)
self.user_laststatus_value = nil
end
if self.user_tabline_value then
vim.opt.showtabline = tonumber(self.user_tabline_value)
self.user_tabline_value = nil
end
end
function db:cache_opts()
if not self.opts then
return
end
local uv = vim.loop
local path = conf_cache_path()
if self.opts.config.shortcut then
for _, item in pairs(self.opts.config.shortcut) do
if type(item.action) == 'function' then
---@diagnostic disable-next-line: param-type-mismatch
local dump = assert(string.dump(item.action))
item.action = dump
end
end
end
if self.opts.config.project and type(self.opts.config.project.action) == 'function' then
---@diagnostic disable-next-line: param-type-mismatch
local dump = assert(string.dump(self.opts.config.project.action))
self.opts.config.project.action = dump
end
if self.opts.config.center then
for _, item in pairs(self.opts.config.center) do
if type(item.action) == 'function' then
---@diagnostic disable-next-line: param-type-mismatch
local dump = assert(string.dump(item.action))
item.action = dump
end
end
end
if self.opts.config.footer and type(self.opts.config.footer) == 'function' then
---@diagnostic disable-next-line: param-type-mismatch
local dump = assert(string.dump(self.opts.config.footer))
self.opts.config.footer = dump
end
local dump = vim.json.encode(self.opts)
uv.fs_open(path, 'w+', tonumber('664', 8), function(err, fd)
assert(not err, err)
---@diagnostic disable-next-line: redefined-local
uv.fs_write(fd, dump, 0, function(err, _)
assert(not err, err)
uv.fs_close(fd)
end)
end)
end
function db:get_opts(callback)
utils.async_read(
conf_cache_path(),
vim.schedule_wrap(function(data)
if not data or #data == 0 then
return
end
local obj = vim.json.decode(data)
if obj then
callback(obj)
end
end)
)
end
function db:load_theme(opts)
local config = vim.tbl_extend('force', opts.config, {
path = cache_path(),
bufnr = self.bufnr,
winid = self.winid,
confirm_key = opts.confirm_key or nil,
shortcut_type = opts.shortcut_type,
change_to_vcs_root = opts.change_to_vcs_root,
})
if #opts.preview.command > 0 then
config = vim.tbl_extend('force', config, opts.preview)
end
require('dashboard.theme.' .. opts.theme)(config)
self:cache_ui_options(opts)
api.nvim_create_autocmd('VimResized', {
buffer = self.bufnr,
callback = function()
require('dashboard.theme.' .. opts.theme)(config)
vim.bo[self.bufnr].modifiable = false
end,
})
api.nvim_create_autocmd('BufEnter', {
callback = function(opt)
local bufs = api.nvim_list_bufs()
bufs = vim.tbl_filter(function(k)
return vim.bo[k].filetype == 'dashboard'
end, bufs)
if #bufs == 0 then
self:cache_opts()
self:restore_options()
clean_ctx()
pcall(api.nvim_del_autocmd, opt.id)
end
end,
desc = '[Dashboard] clean dashboard data reduce memory',
})
end
-- create dashboard instance
function db:instance()
local mode = api.nvim_get_mode().mode
if mode == 'i' or not vim.bo.modifiable then
return
end
if not vim.o.hidden and vim.bo.modified then
--save before open
vim.cmd.write()
return
end
if not utils.buf_is_empty(0) then
self.bufnr = api.nvim_create_buf(false, true)
else
self.bufnr = api.nvim_get_current_buf()
end
self.winid = api.nvim_get_current_win()
api.nvim_win_set_buf(self.winid, self.bufnr)
self.user_cursor_line = vim.opt.cursorline:get()
buf_local()
if self.opts then
self:load_theme(self.opts)
else
self:get_opts(function(obj)
self:load_theme(obj)
end)
end
end
function db.setup(opts)
opts = opts or {}
ctx.opts = vim.tbl_deep_extend('force', default_options(), opts)
end
return setmetatable(ctx, db)

View File

@ -0,0 +1,138 @@
local api = vim.api
local db = require('dashboard')
local view = {}
function view:open_window(opt)
local row = math.floor(opt.height / 5)
local col = math.floor((vim.o.columns - opt.width) / 2)
local opts = {
relative = 'editor',
row = row,
col = col,
width = opt.width,
height = opt.height,
style = 'minimal',
noautocmd = true,
}
self.bufnr = api.nvim_create_buf(false, true)
api.nvim_buf_set_option(self.bufnr, 'filetype', 'dashboardpreview')
self.winid = api.nvim_open_win(self.bufnr, false, opts)
if vim.fn.has('nvim-0.8') == 1 then
local normal = api.nvim_get_hl_by_name('Normal', true)
pcall(api.nvim_set_hl, 0, 'DashboardPreview', normal)
else
api.nvim_set_hl(0, 'DashboardPreview', { bg = 'none' })
end
api.nvim_win_set_option(self.winid, 'winhl', 'Normal:DashboardPreview')
return { self.bufnr, self.winid }
end
function view:close_preview_window()
if self.bufnr and api.nvim_buf_is_loaded(self.bufnr) then
api.nvim_buf_delete(self.bufnr, { force = true })
self.bufnr = nil
end
if self.winid and api.nvim_win_is_valid(self.winid) then
api.nvim_win_close(self.winid, true)
self.winid = nil
end
end
function view:preview_events()
local group =
api.nvim_create_augroup('DashboardClosePreview' .. self.preview_bufnr, { clear = true })
--refresh the preview window col position.
local function refresh_preview_wincol()
if not self.preview_winid or not api.nvim_win_is_valid(self.preview_winid) then
return
end
local winconfig = api.nvim_win_get_config(self.preview_winid)
local cur_width = api.nvim_win_get_width(self.main_winid)
if cur_width ~= self.win_width then
local wins = api.nvim_list_wins()
if #wins == 2 then
local scol = bit.rshift(vim.o.columns, 1) - bit.rshift(winconfig.width, 1)
winconfig.col[false] = scol
api.nvim_win_set_config(self.preview_winid, winconfig)
self.win_width = cur_width
return
end
if #wins == 3 then
local new_win = vim.tbl_filter(function(k)
return k ~= self.main_winid and k ~= self.preview_winid
end, wins)[1]
winconfig.col[false] = winconfig.col[false] + api.nvim_win_get_width(new_win)
api.nvim_win_set_config(self.preview_winid, winconfig)
self.win_width = cur_width
end
end
end
local function winresized()
api.nvim_create_autocmd('WinResized', {
group = group,
callback = function()
refresh_preview_wincol()
end,
desc = ' Dashboard preview window resized for nvim 0.9',
})
end
api.nvim_create_autocmd('VimResized', {
group = group,
callback = function()
refresh_preview_wincol()
end,
})
if vim.fn.has('nvim-0.9') == 1 then
winresized()
else
---@deprecated when 0.9 version release remove
api.nvim_create_autocmd('BufEnter', {
group = group,
callback = function()
refresh_preview_wincol()
end,
desc = 'dashboard preview window resize for neovim 0.8+ version',
})
end
end
function view:open_preview(opt)
self.preview_bufnr, self.preview_winid = unpack(view:open_window(opt))
api.nvim_buf_call(self.preview_bufnr, function()
vim.fn.termopen(opt.cmd, {
on_exit = function() end,
})
end)
self.main_winid = api.nvim_get_current_win()
self.win_width = api.nvim_win_get_width(self.main_winid)
api.nvim_create_autocmd('BufWipeout', {
buffer = db.bufnr,
callback = function()
if self.winid and api.nvim_win_is_valid(self.preview_winid) then
api.nvim_win_close(self.preview_winid, true)
self.preview_winid = nil
self.preview_bufnr = nil
self.main_winid = nil
self.win_width = nil
end
end,
once = true,
desc = 'make preview have same lifetime with dashboard buffer',
})
self:preview_events()
end
return view

View File

@ -0,0 +1,225 @@
local api, keymap = vim.api, vim.keymap
local utils = require('dashboard.utils')
local function generate_center(config)
local lines = {}
local center = config.center
or {
{ desc = 'Please config your own center section', key = 'p' },
}
local counts = {}
for _, item in pairs(center) do
local count = item.keymap and #item.keymap or 0
local line = (item.icon or '') .. item.desc
if item.key then
line = line .. (' '):rep(#item.key + 4)
count = count + #item.key + 3
local desc = 'Dashboard-action: ' .. item.desc:gsub('^%s+', '')
keymap.set('n', item.key, function()
if type(item.action) == 'string' then
local dump = loadstring(item.action)
if not dump then
vim.cmd(item.action)
else
dump()
end
elseif type(item.action) == 'function' then
item.action()
end
end, { buffer = config.bufnr, nowait = true, silent = true, desc = desc })
end
if item.keymap then
line = line .. (' '):rep(#item.keymap)
end
table.insert(lines, line)
table.insert(lines, '')
table.insert(counts, count)
table.insert(counts, 0)
end
lines = utils.element_align(lines)
lines = utils.center_align(lines)
for i, count in ipairs(counts) do
lines[i] = lines[i]:sub(1, #lines[i] - count)
end
local first_line = api.nvim_buf_line_count(config.bufnr)
api.nvim_buf_set_lines(config.bufnr, first_line, -1, false, lines)
if not config.center then
return
end
local ns = api.nvim_create_namespace('DashboardDoom')
local seed = 0
local pos_map = {}
for i = 1, #lines do
if lines[i]:find('%w') then
local idx = i == 1 and i or i - seed
seed = seed + 1
pos_map[i] = idx
local _, scol = lines[i]:find('%s+')
local ecol = scol + (config.center[idx].icon and #config.center[idx].icon or 0)
if config.center[idx].icon then
api.nvim_buf_add_highlight(
config.bufnr,
0,
config.center[idx].icon_hl or 'DashboardIcon',
first_line + i - 1,
0,
ecol
)
end
api.nvim_buf_add_highlight(
config.bufnr,
0,
config.center[idx].desc_hl or 'DashboardDesc',
first_line + i - 1,
ecol,
-1
)
if config.center[idx].key then
local virt_tbl = {}
if config.center[idx].keymap then
table.insert(virt_tbl, { config.center[idx].keymap, 'DashboardShortCut' })
end
table.insert(virt_tbl, {
string.format(config.center[idx].key_format or ' [%s]', config.center[idx].key),
config.center[idx].key_hl or 'DashboardKey',
})
api.nvim_buf_set_extmark(config.bufnr, ns, first_line + i - 1, 0, {
virt_text_pos = 'eol',
virt_text = virt_tbl,
})
end
end
end
local line = api.nvim_buf_get_lines(config.bufnr, first_line, first_line + 1, false)[1]
local col = line:find('%w')
local col_width = api.nvim_strwidth(line:sub(1, col))
col = col and col - 1 or 9999
api.nvim_win_set_cursor(config.winid, { first_line + 1, col })
local bottom = api.nvim_buf_line_count(config.bufnr)
vim.defer_fn(function()
local before = 0
if api.nvim_get_current_buf() ~= config.bufnr then
return
end
api.nvim_create_autocmd('CursorMoved', {
buffer = config.bufnr,
callback = function()
local buf = api.nvim_win_get_buf(0)
if vim.api.nvim_buf_get_option(buf, 'filetype') ~= 'dashboard' then
return
end
local curline = api.nvim_win_get_cursor(0)[1]
if curline < first_line + 1 then
curline = bottom - 1
elseif curline > bottom - 1 then
curline = first_line + 1
elseif not api.nvim_get_current_line():find('%w') then
curline = curline + (before > curline and -1 or 1)
end
before = curline
-- FIX: #422: In Lua the length of a string is the numbers of bytes not
-- the number of characters.
local curline_str = api.nvim_buf_get_lines(config.bufnr, curline - 1, curline, false)[1]
local delta = col_width - api.nvim_strwidth(curline_str:sub(1, col + 1))
api.nvim_win_set_cursor(config.winid, { curline, col + delta })
end,
})
end, 0)
keymap.set('n', config.confirm_key or '<CR>', function()
local curline = api.nvim_win_get_cursor(0)[1]
local index = pos_map[curline - first_line]
if index and config.center[index].action then
if type(config.center[index].action) == 'string' then
local dump = loadstring(config.center[index].action)
if not dump then
vim.cmd(config.center[index].action)
else
dump()
end
elseif type(config.center[index].action) == 'function' then
config.center[index].action()
else
print('Error with action, check your config')
end
end
end, { buffer = config.bufnr, nowait = true, silent = true })
end
local function generate_footer(config)
local first_line = api.nvim_buf_line_count(config.bufnr)
local package_manager_stats = utils.get_package_manager_stats()
local footer = {}
if package_manager_stats.name == 'lazy' then
footer = {
'',
'',
'Startuptime: ' .. package_manager_stats.time .. ' ms',
'Plugins: '
.. package_manager_stats.loaded
.. ' loaded / '
.. package_manager_stats.count
.. ' installed',
}
else
footer = {
'',
'neovim loaded ' .. package_manager_stats.count .. ' plugins',
}
end
if config.footer then
if type(config.footer) == 'function' then
footer = config.footer()
elseif type(config.footer) == 'string' then
local dump = loadstring(config.footer)
if dump then
footer = dump()
end
elseif type(config.footer) == 'table' then
footer = config.footer
end
end
api.nvim_buf_set_lines(config.bufnr, first_line, -1, false, utils.center_align(footer))
for i = 1, #footer do
api.nvim_buf_add_highlight(config.bufnr, 0, 'DashboardFooter', first_line + i - 1, 0, -1)
end
utils.add_update_footer_command(config.bufnr, footer)
end
---@private
local function theme_instance(config)
require('dashboard.theme.header').generate_header(config)
generate_center(config)
generate_footer(config)
api.nvim_set_option_value('modifiable', false, { buf = config.bufnr })
api.nvim_set_option_value('modified', false, { buf = config.bufnr })
--defer until next event loop
vim.schedule(function()
api.nvim_exec_autocmds('User', {
pattern = 'DashboardLoaded',
modeline = false,
})
end)
end
return setmetatable({}, {
__call = function(_, t)
return theme_instance(t)
end,
})

View File

@ -0,0 +1,135 @@
local api = vim.api
local utils = require('dashboard.utils')
local function week_ascii_text()
return {
['Monday'] = {
'',
'███╗ ███╗ ██████╗ ███╗ ██╗██████╗ █████╗ ██╗ ██╗',
'████╗ ████║██╔═══██╗████╗ ██║██╔══██╗██╔══██╗╚██╗ ██╔╝',
'██╔████╔██║██║ ██║██╔██╗ ██║██║ ██║███████║ ╚████╔╝ ',
'██║╚██╔╝██║██║ ██║██║╚██╗██║██║ ██║██╔══██║ ╚██╔╝ ',
'██║ ╚═╝ ██║╚██████╔╝██║ ╚████║██████╔╝██║ ██║ ██║ ',
'╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝╚═════╝ ╚═╝ ╚═╝ ╚═╝ ',
'',
},
['Tuesday'] = {
'',
'████████╗██╗ ██╗███████╗███████╗██████╗ █████╗ ██╗ ██╗',
'╚══██╔══╝██║ ██║██╔════╝██╔════╝██╔══██╗██╔══██╗╚██╗ ██╔╝',
' ██║ ██║ ██║█████╗ ███████╗██║ ██║███████║ ╚████╔╝ ',
' ██║ ██║ ██║██╔══╝ ╚════██║██║ ██║██╔══██║ ╚██╔╝ ',
' ██║ ╚██████╔╝███████╗███████║██████╔╝██║ ██║ ██║ ',
' ╚═╝ ╚═════╝ ╚══════╝╚══════╝╚═════╝ ╚═╝ ╚═╝ ╚═╝ ',
'',
},
['Wednesday'] = {
'',
'██╗ ██╗███████╗██████╗ ███╗ ██╗███████╗███████╗██████╗ █████╗ ██╗ ██╗',
'██║ ██║██╔════╝██╔══██╗████╗ ██║██╔════╝██╔════╝██╔══██╗██╔══██╗╚██╗ ██╔╝',
'██║ █╗ ██║█████╗ ██║ ██║██╔██╗ ██║█████╗ ███████╗██║ ██║███████║ ╚████╔╝ ',
'██║███╗██║██╔══╝ ██║ ██║██║╚██╗██║██╔══╝ ╚════██║██║ ██║██╔══██║ ╚██╔╝ ',
'╚███╔███╔╝███████╗██████╔╝██║ ╚████║███████╗███████║██████╔╝██║ ██║ ██║ ',
' ╚══╝╚══╝ ╚══════╝╚═════╝ ╚═╝ ╚═══╝╚══════╝╚══════╝╚═════╝ ╚═╝ ╚═╝ ╚═╝ ',
'',
},
['Thursday'] = {
'',
'████████╗██╗ ██╗██╗ ██╗██████╗ ███████╗██████╗ █████╗ ██╗ ██╗',
'╚══██╔══╝██║ ██║██║ ██║██╔══██╗██╔════╝██╔══██╗██╔══██╗╚██╗ ██╔╝',
' ██║ ███████║██║ ██║██████╔╝███████╗██║ ██║███████║ ╚████╔╝ ',
' ██║ ██╔══██║██║ ██║██╔══██╗╚════██║██║ ██║██╔══██║ ╚██╔╝ ',
' ██║ ██║ ██║╚██████╔╝██║ ██║███████║██████╔╝██║ ██║ ██║ ',
' ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═════╝ ╚═╝ ╚═╝ ╚═╝ ',
'',
},
['Friday'] = {
'',
'███████╗██████╗ ██╗██████╗ █████╗ ██╗ ██╗',
'██╔════╝██╔══██╗██║██╔══██╗██╔══██╗╚██╗ ██╔╝',
'█████╗ ██████╔╝██║██║ ██║███████║ ╚████╔╝ ',
'██╔══╝ ██╔══██╗██║██║ ██║██╔══██║ ╚██╔╝ ',
'██║ ██║ ██║██║██████╔╝██║ ██║ ██║ ',
'╚═╝ ╚═╝ ╚═╝╚═╝╚═════╝ ╚═╝ ╚═╝ ╚═╝ ',
'',
},
['Saturday'] = {
'',
'███████╗ █████╗ ████████╗██╗ ██╗██████╗ ██████╗ █████╗ ██╗ ██╗',
'██╔════╝██╔══██╗╚══██╔══╝██║ ██║██╔══██╗██╔══██╗██╔══██╗╚██╗ ██╔╝',
'███████╗███████║ ██║ ██║ ██║██████╔╝██║ ██║███████║ ╚████╔╝ ',
'╚════██║██╔══██║ ██║ ██║ ██║██╔══██╗██║ ██║██╔══██║ ╚██╔╝ ',
'███████║██║ ██║ ██║ ╚██████╔╝██║ ██║██████╔╝██║ ██║ ██║ ',
'╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝ ╚═╝ ',
'',
},
['Sunday'] = {
'',
'███████╗██╗ ██╗███╗ ██╗██████╗ █████╗ ██╗ ██╗',
'██╔════╝██║ ██║████╗ ██║██╔══██╗██╔══██╗╚██╗ ██╔╝',
'███████╗██║ ██║██╔██╗ ██║██║ ██║███████║ ╚████╔╝ ',
'╚════██║██║ ██║██║╚██╗██║██║ ██║██╔══██║ ╚██╔╝ ',
'███████║╚██████╔╝██║ ╚████║██████╔╝██║ ██║ ██║ ',
'╚══════╝ ╚═════╝ ╚═╝ ╚═══╝╚═════╝ ╚═╝ ╚═╝ ╚═╝ ',
'',
},
}
end
local function default_header()
return {
'',
' ██████╗ █████╗ ███████╗██╗ ██╗██████╗ ██████╗ █████╗ ██████╗ ██████╗ ',
' ██╔══██╗██╔══██╗██╔════╝██║ ██║██╔══██╗██╔═══██╗██╔══██╗██╔══██╗██╔══██╗ ',
' ██║ ██║███████║███████╗███████║██████╔╝██║ ██║███████║██████╔╝██║ ██║ ',
' ██║ ██║██╔══██║╚════██║██╔══██║██╔══██╗██║ ██║██╔══██║██╔══██╗██║ ██║ ',
' ██████╔╝██║ ██║███████║██║ ██║██████╔╝╚██████╔╝██║ ██║██║ ██║██████╔╝ ',
' ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ',
'',
}
end
local function week_header(concat, append)
local week = week_ascii_text()
local daysoftheweek =
{ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' }
local day = daysoftheweek[os.date('*t').wday]
local tbl = week[day]
table.insert(tbl, os.date('%Y-%m-%d %H:%M:%S ') .. (concat or ''))
if append then
vim.list_extend(tbl, append)
end
table.insert(tbl, '')
return tbl
end
local function generate_header(config)
if not vim.bo[config.bufnr].modifiable then
vim.bo[config.bufnr].modifiable = true
end
if not config.command then
local header = config.week_header
and config.week_header.enable
and week_header(config.week_header.concat, config.week_header.append)
or (config.header or default_header())
api.nvim_buf_set_lines(config.bufnr, 0, -1, false, utils.center_align(header))
for i, _ in ipairs(header) do
vim.api.nvim_buf_add_highlight(config.bufnr, 0, 'DashboardHeader', i - 1, 0, -1)
end
return
end
local empty_table = utils.generate_empty_table(config.file_height + 4)
api.nvim_buf_set_lines(config.bufnr, 0, -1, false, utils.center_align(empty_table))
local preview = require('dashboard.preview')
preview:open_preview({
width = config.file_width,
height = config.file_height,
cmd = config.command .. ' ' .. config.file_path,
})
end
return {
generate_header = generate_header,
}

View File

@ -0,0 +1,533 @@
local api, keymap, uv = vim.api, vim.keymap, vim.loop
local utils = require('dashboard.utils')
local ns = api.nvim_create_namespace('dashboard')
local function gen_shortcut(config)
local shortcut = config.shortcut
or {
{ desc = '[ Github]', group = 'DashboardShortCut' },
{ desc = '[ glepnir]', group = 'DashboardShortCut' },
{ desc = '[ 0.2.3]', group = 'DashboardShortCut' },
}
if vim.tbl_isempty(shortcut) then
shortcut = {}
end
local lines = ''
for _, item in pairs(shortcut) do
local str = item.icon and item.icon .. item.desc or item.desc
if item.key then
str = str .. '[' .. item.key .. ']'
end
lines = lines .. ' ' .. str
end
local first_line = api.nvim_buf_line_count(config.bufnr)
api.nvim_buf_set_lines(config.bufnr, first_line, -1, false, utils.center_align({ lines }))
local line = api.nvim_buf_get_lines(config.bufnr, first_line, -1, false)[1]
local start = line:find('[^%s]') - 1
for _, item in pairs(shortcut) do
local _end = start + (item.icon and #(item.icon .. item.desc) or #item.desc)
if item.key then
_end = _end + api.nvim_strwidth(item.key) + 2
keymap.set('n', item.key, function()
if type(item.action) == 'string' then
local dump = loadstring(item.action)
if not dump then
vim.cmd(item.action)
else
dump()
end
elseif type(item.action) == 'function' then
item.action()
end
end, { buffer = config.bufnr, nowait = true, silent = true })
end
api.nvim_buf_add_highlight(
config.bufnr,
0,
item.group or 'DashboardShortCut',
first_line,
start,
_end
)
if item.icon then
api.nvim_buf_add_highlight(
config.bufnr,
0,
item.icon_hl or 'DashboardShortCutIcon',
first_line,
start,
start + #item.icon
)
end
start = _end + 2
end
end
local function load_packages(config)
local packages = config.packages or {
enable = true,
}
if not packages.enable then
return
end
local package_manager_stats = utils.get_package_manager_stats()
local lines = {}
if package_manager_stats.name == 'lazy' then
lines = {
'',
'Startuptime: ' .. package_manager_stats.time .. ' ms',
'Plugins: '
.. package_manager_stats.loaded
.. ' loaded / '
.. package_manager_stats.count
.. ' installed',
}
else
lines = {
'',
'neovim loaded ' .. package_manager_stats.count .. ' plugins',
}
end
local first_line = api.nvim_buf_line_count(config.bufnr)
api.nvim_buf_set_lines(config.bufnr, first_line, -1, false, utils.center_align(lines))
for i, _ in pairs(lines) do
api.nvim_buf_add_highlight(config.bufnr, 0, 'Comment', first_line + i - 1, 0, -1)
end
end
local function reverse(tbl)
for i = 1, math.floor(#tbl / 2) do
tbl[i], tbl[#tbl - i + 1] = tbl[#tbl - i + 1], tbl[i]
end
end
local function project_list(config, callback)
config.project = vim.tbl_extend('force', {
limit = 8,
enable = true,
icon = '󰏓 ',
icon_hl = 'DashboardRecentProjectIcon',
action = 'Telescope find_files cwd=',
label = ' Recent Projects:',
}, config.project or {})
local function read_project(data)
local res = {}
data = string.gsub(data, '%z', '')
local dump = assert(loadstring(data))
local list = dump()
if list then
list = vim.list_slice(list, #list - config.project.limit)
end
for _, dir in ipairs(list or {}) do
dir = dir:gsub(vim.env.HOME, '~')
table.insert(res, (' '):rep(3) .. '' .. dir)
end
if #res == 0 then
table.insert(res, (' '):rep(3) .. ' empty project')
else
reverse(res)
end
table.insert(res, 1, config.project.icon .. config.project.label)
table.insert(res, 1, '')
table.insert(res, '')
return res
end
utils.async_read(
config.path,
vim.schedule_wrap(function(data)
local res = {}
if config.project.enable then
res = read_project(data)
end
callback(res)
end)
)
end
local function mru_list(config)
config.mru = vim.tbl_extend('force', {
icon = '',
limit = 10,
icon_hl = 'DashboardMruIcon',
label = ' Most Recent Files:',
cwd_only = false,
}, config.mru or {})
local list = {
config.mru.icon .. config.mru.label,
}
local groups = {}
local mlist = utils.get_mru_list()
if config.mru.cwd_only then
local cwd = uv.cwd()
mlist = vim.tbl_filter(function(file)
local file_dir = vim.fn.fnamemodify(file, ':p:h')
if file_dir and cwd then
return file_dir:find(cwd, 1, true) == 1
end
end, mlist)
end
for _, file in pairs(vim.list_slice(mlist, 1, config.mru.limit)) do
local filename = vim.fn.fnamemodify(file, ':t')
local icon, group = utils.get_icon(filename)
icon = icon or ''
if config.mru.cwd_only then
file = vim.fn.fnamemodify(file, ':.')
elseif not utils.is_win then
file = vim.fn.fnamemodify(file, ':~')
end
file = icon .. ' ' .. file
table.insert(groups, { #icon, group })
table.insert(list, (' '):rep(3) .. file)
end
if #list == 1 then
table.insert(list, (' '):rep(3) .. ' empty files')
end
return list, groups
end
local function shuffle_table(table)
for i = #table, 2, -1 do
local j = math.random(i)
table[i], table[j] = table[j], table[i]
end
end
local function letter_hotkey(config)
-- Reserve j, k keys to move up and down.
local list = { 106, 107 }
for _, item in pairs(config.shortcut or {}) do
if item.key then
table.insert(list, item.key:byte())
end
end
math.randomseed(os.time())
-- Create key table, fill it with unused characters.
local unused_keys = {}
-- a - z
for key = 97, 122 do
if not vim.tbl_contains(list, key) then
table.insert(unused_keys, key)
end
end
shuffle_table(unused_keys)
local unused_uppercase_keys = {}
-- A - Z
for key = 65, 90 do
if not vim.tbl_contains(list, key) then
table.insert(unused_uppercase_keys, key)
end
end
shuffle_table(unused_uppercase_keys)
-- Push shuffled uppercase keys after the lowercase ones
for _, key in pairs(unused_uppercase_keys) do
table.insert(unused_keys, key)
end
local fallback_hotkey = 0
return function()
if #unused_keys ~= 0 then
-- Pop an unused key to use it as a hotkey.
local key = table.remove(unused_keys, 1)
return string.char(key)
else
-- All keys are already used. Fallback to the number generation.
fallback_hotkey = fallback_hotkey + 1
return fallback_hotkey
end
end
end
local function number_hotkey()
local start = 0
return function()
start = start + 1
return start
end
end
local function gen_hotkey(config)
if config.shortcut_type == 'number' then
return number_hotkey()
end
return letter_hotkey(config)
end
local function map_key(config, key, content)
keymap.set('n', key, function()
local text = content or api.nvim_get_current_line()
local scol = utils.is_win and text:find('%w') or text:find('%p')
local path = nil
if scol ~= nil then -- scol == nil if pressing enter in empty space
if text:sub(scol, scol + 1) ~= '~/' then -- is relative path
scol = math.min(text:find('%w'), text:find('%p'))
end
text = text:sub(scol)
path = text:sub(1, text:find('%w(%s+)$'))
path = vim.fs.normalize(path)
end
if path == nil then
vim.cmd('enew')
elseif vim.fn.isdirectory(path) == 1 then
vim.cmd('lcd ' .. path)
if type(config.project.action) == 'function' then
config.project.action(path)
elseif type(config.project.action) == 'string' then
local dump = loadstring(config.project.action)
if not dump then
vim.cmd(config.project.action .. path)
else
dump(path)
end
end
else
vim.cmd('edit ' .. vim.fn.fnameescape(path))
local root = utils.get_vcs_root()
if not config.change_to_vcs_root then
return
end
if #root > 0 then
vim.cmd('lcd ' .. vim.fn.fnamemodify(root[#root], ':h'))
else
vim.cmd('lcd ' .. vim.fn.fnamemodify(path, ':h'))
end
end
end, { buffer = config.bufnr, silent = true, nowait = true })
end
local function gen_center(plist, config)
local mlist, mgroups = mru_list(config)
local plist_len = #plist
if plist_len == 0 then
plist[#plist + 1] = ''
plist_len = 1
end
---@diagnostic disable-next-line: param-type-mismatch
vim.list_extend(plist, mlist)
local max_len = utils.get_max_len(plist)
if max_len <= 40 then
local fill = (' '):rep(math.floor(vim.o.columns / 4))
for i, v in pairs(plist) do
plist[i] = v .. fill
end
end
plist = utils.element_align(plist)
plist = utils.center_align(plist)
local first_line = api.nvim_buf_line_count(config.bufnr)
api.nvim_buf_set_lines(config.bufnr, first_line, -1, false, plist)
local start_col = plist[plist_len + 2]:find('[^%s]') - 1
local _, scol = plist[2]:find('%S')
local hotkey = gen_hotkey(config)
api.nvim_buf_add_highlight(config.bufnr, 0, 'DashboardProjectTitle', first_line + 1, 0, -1)
api.nvim_buf_add_highlight(
config.bufnr,
0,
'DashboardProjectTitleIcon',
first_line + 1,
0,
scol + #config.project.icon
)
for i = 3, plist_len do
api.nvim_buf_add_highlight(
config.bufnr,
0,
'DashboardProjectIcon',
first_line + i - 1,
0,
start_col + 3
)
api.nvim_buf_add_highlight(
config.bufnr,
0,
'DashboardFiles',
first_line + i - 1,
start_col + 3,
-1
)
local text = api.nvim_buf_get_lines(config.bufnr, first_line + i - 1, first_line + i, false)[1]
if text and text:find('%w') and not text:find('empty') then
local key = tostring(hotkey())
api.nvim_buf_set_extmark(config.bufnr, ns, first_line + i - 1, 0, {
virt_text = { { key, 'DashboardShortCut' } },
virt_text_pos = 'eol',
})
map_key(config, key, text)
end
end
-- initialize the cursor pos
api.nvim_win_set_cursor(config.winid, { first_line + 3, start_col + 4 })
api.nvim_buf_add_highlight(config.bufnr, 0, 'DashboardMruTitle', first_line + plist_len, 0, -1)
api.nvim_buf_add_highlight(
config.bufnr,
0,
'DashboardMruIcon',
first_line + plist_len,
0,
scol + #config.mru.icon
)
for i, data in pairs(mgroups) do
local len, group = unpack(data)
api.nvim_buf_add_highlight(
config.bufnr,
0,
group,
first_line + i + plist_len,
start_col,
start_col + len
)
api.nvim_buf_add_highlight(
config.bufnr,
0,
'DashboardFiles',
first_line + i + plist_len,
start_col + len,
-1
)
local text = api.nvim_buf_get_lines(
config.bufnr,
first_line + i + plist_len,
first_line + i + plist_len + 1,
false
)[1]
if text and text:find('%w') then
local key = tostring(hotkey())
api.nvim_buf_set_extmark(config.bufnr, ns, first_line + i + plist_len, 0, {
virt_text = { { key, 'DashboardShortCut' } },
virt_text_pos = 'eol',
})
map_key(config, key, text)
end
end
end
local function gen_footer(config)
local footer = {
'',
' 🚀 Sharp tools make good work.',
}
if type(config.footer) == 'string' then
local dump = loadstring(config.footer)
if dump then
footer = dump()
end
elseif type(config.footer) == 'function' then
footer = config.footer()
elseif type(config.footer) == 'table' then
footer = config.footer
end
local first_line = api.nvim_buf_line_count(config.bufnr)
api.nvim_buf_set_lines(config.bufnr, first_line, -1, false, utils.center_align(footer))
---@diagnostic disable-next-line: param-type-mismatch
for i, _ in pairs(footer) do
api.nvim_buf_add_highlight(config.bufnr, 0, 'DashboardFooter', first_line + i - 1, 0, -1)
end
utils.add_update_footer_command(config.bufnr, footer)
end
local function project_delete()
api.nvim_create_user_command('DbProjectDelete', function(args)
local path = utils.path_join(vim.fn.stdpath('cache'), 'dashboard', 'cache')
utils.async_read(
path,
vim.schedule_wrap(function(data)
local dump = assert(loadstring(data))
local list = dump()
local count = tonumber(args.args)
if vim.tbl_count(list) < count then
return
end
list = vim.list_slice(list, count + 1)
local str = string.dump(assert(loadstring('return ' .. vim.inspect(list))))
local handle = io.open(path, 'w+')
if not handle then
return
end
handle:write(str)
handle:close()
end)
)
end, {
nargs = '+',
})
end
local function theme_instance(config)
project_list(config, function(plist)
if not api.nvim_buf_is_valid(config.bufnr) then
return
end
if config.disable_move then
utils.disable_move_key(config.bufnr)
end
require('dashboard.theme.header').generate_header(config)
if not config.shortcut or not vim.tbl_isempty(config.shortcut) then
gen_shortcut(config)
end
load_packages(config)
gen_center(plist, config)
gen_footer(config)
map_key(config, config.confirm_key or '<CR>')
require('dashboard.events').register_lsp_root(config.path)
local size = math.floor(vim.o.lines / 2)
- math.ceil(api.nvim_buf_line_count(config.bufnr) / 2)
- 2
local fill = utils.generate_empty_table(size)
api.nvim_buf_set_lines(config.bufnr, 0, 0, false, fill)
vim.bo[config.bufnr].modifiable = false
vim.bo[config.bufnr].modified = false
--defer until next event loop
vim.schedule(function()
api.nvim_exec_autocmds('User', {
pattern = 'DashboardLoaded',
modeline = false,
})
end)
project_delete()
end)
end
return setmetatable({}, {
__call = function(_, t)
theme_instance(t)
end,
})

View File

@ -0,0 +1,198 @@
local uv = vim.loop
local utils = {}
utils.is_win = uv.os_uname().version:match('Windows')
function utils.path_join(...)
local path_sep = utils.is_win and '\\' or '/'
return table.concat({ ... }, path_sep)
end
function utils.element_align(tbl)
local lens = {}
vim.tbl_map(function(k)
table.insert(lens, vim.api.nvim_strwidth(k))
end, tbl)
table.sort(lens)
local max = lens[#lens]
local res = {}
for _, item in pairs(tbl) do
local len = vim.api.nvim_strwidth(item)
local times = math.floor((max - len) / vim.api.nvim_strwidth(' '))
item = item .. (' '):rep(times)
table.insert(res, item)
end
return res
end
function utils.get_max_len(contents)
vim.validate({
contents = { contents, 't' },
})
local cells = {}
for _, v in pairs(contents) do
table.insert(cells, vim.api.nvim_strwidth(v))
end
table.sort(cells)
return cells[#cells]
end
-- draw the graphics into the screen center
function utils.center_align(tbl)
vim.validate({
tbl = { tbl, 'table' },
})
local function fill_sizes(lines)
local fills = {}
for _, line in pairs(lines) do
table.insert(fills, math.floor((vim.o.columns - vim.api.nvim_strwidth(line)) / 2))
end
return fills
end
local centered_lines = {}
local fills = fill_sizes(tbl)
for i = 1, #tbl do
local fill_line = (' '):rep(fills[i]) .. tbl[i]
table.insert(centered_lines, fill_line)
end
return centered_lines
end
function utils.get_icon(filename)
local ok, devicons = pcall(require, 'nvim-web-devicons')
if not ok then
vim.notify('[dashboard.nvim] not found nvim-web-devicons')
return nil
end
return devicons.get_icon(filename, nil, { default = true })
end
function utils.read_project_cache(path)
local fd = assert(uv.fs_open(path, 'r', tonumber('644', 8)))
local stat = uv.fs_fstat(fd)
local chunk = uv.fs_read(fd, stat.size, 0)
local dump = assert(loadstring(chunk))
return dump()
end
function utils.async_read(path, callback)
uv.fs_open(path, 'a+', 438, function(err, fd)
assert(not err, err)
uv.fs_fstat(fd, function(err, stat)
assert(not err, err)
uv.fs_read(fd, stat.size, 0, function(err, data)
assert(not err, err)
uv.fs_close(fd, function(err)
assert(not err, err)
callback(data)
end)
end)
end)
end)
end
function utils.disable_move_key(bufnr)
local keys = { 'w', 'f', 'b', 'h', 'j', 'k', 'l', '<Up>', '<Down>', '<Left>', '<Right>' }
vim.tbl_map(function(k)
vim.keymap.set('n', k, '<Nop>', { buffer = bufnr })
end, keys)
end
--- return the most recently files list
function utils.get_mru_list()
local mru = {}
for _, file in pairs(vim.v.oldfiles or {}) do
if file and vim.fn.filereadable(file) == 1 then
table.insert(mru, file)
end
end
return mru
end
function utils.get_package_manager_stats()
local package_manager_stats = { name = '', count = 0, loaded = 0, time = 0 }
---@diagnostic disable-next-line: undefined-global
if packer_plugins then
package_manager_stats.name = 'packer'
---@diagnostic disable-next-line: undefined-global
package_manager_stats.count = #vim.tbl_keys(packer_plugins)
end
local status, lazy = pcall(require, 'lazy')
if status then
package_manager_stats.name = 'lazy'
package_manager_stats.loaded = lazy.stats().loaded
package_manager_stats.count = lazy.stats().count
package_manager_stats.time = lazy.stats().startuptime
end
return package_manager_stats
end
--- generate an empty table by length
function utils.generate_empty_table(length)
local empty_tbl = {}
if length == 0 then
return empty_tbl
end
for _ = 1, length do
table.insert(empty_tbl, '')
end
return empty_tbl
end
function utils.generate_truncateline(cells)
local char = ''
return char:rep(math.floor(cells / vim.api.nvim_strwidth(char)))
end
function utils.get_vcs_root(buf)
buf = buf or 0
local path = vim.fn.fnamemodify(vim.api.nvim_buf_get_name(buf), ':p:h')
local patterns = { '.git', '.hg', '.bzr', '.svn' }
for _, pattern in pairs(patterns) do
local root = vim.fs.find(pattern, { path = path, upward = true, stop = vim.env.HOME })
if root then
return root
end
end
end
local index = 0
function utils.gen_bufname(prefix)
index = index + 1
return prefix .. '-' .. index
end
function utils.buf_is_empty(bufnr)
bufnr = bufnr or 0
return vim.api.nvim_buf_line_count(0) == 1
and vim.api.nvim_buf_get_lines(0, 0, -1, false)[1] == ''
end
local last_footer_size = nil
function utils.add_update_footer_command(bufnr, footer)
vim.api.nvim_create_user_command('DashboardUpdateFooter', function(args)
if last_footer_size == nil then
last_footer_size = #footer
end
local first_line = vim.api.nvim_buf_line_count(bufnr)
vim.bo[bufnr].modifiable = true
vim.api.nvim_buf_set_lines(
bufnr,
first_line - last_footer_size,
-1,
false,
utils.center_align(args.fargs)
)
vim.bo[bufnr].modifiable = false
vim.bo[bufnr].modified = false
last_footer_size = #args.fargs -- For future calculation of size
end, { nargs = '*' })
end
return utils

View File

@ -0,0 +1,27 @@
-- version 0.2.3
local g = vim.api.nvim_create_augroup('dashboard', { clear = true })
vim.api.nvim_create_autocmd('StdinReadPre', {
group = g,
callback = function()
vim.g.read_from_stdin = 1
end,
})
vim.api.nvim_create_autocmd('UIEnter', {
group = g,
callback = function()
if
vim.fn.argc() == 0
and vim.api.nvim_buf_get_name(0) == ''
and vim.g.read_from_stdin == nil
then
require('dashboard'):instance()
end
end,
})
vim.api.nvim_create_user_command('Dashboard', function()
require('dashboard'):instance()
end, {})