├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ └── ci.yml ├── .stylua.toml ├── plugin └── dashboard.lua ├── LICENSE ├── lua └── dashboard │ ├── events.lua │ ├── utils.lua │ ├── preview.lua │ ├── theme │ ├── header.lua │ ├── doom.lua │ └── hyper.lua │ └── init.lua ├── README.md └── doc └── dashboard.txt /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: glepnir 2 | custom: ['https://www.paypal.me/bobbyhub'] 3 | -------------------------------------------------------------------------------- /.stylua.toml: -------------------------------------------------------------------------------- 1 | column_width = 100 2 | line_endings = "Unix" 3 | indent_type = "Spaces" 4 | indent_width = 2 5 | quote_style = "AutoPreferSingle" 6 | call_parentheses = "Always" 7 | -------------------------------------------------------------------------------- /plugin/dashboard.lua: -------------------------------------------------------------------------------- 1 | -- version 0.2.3 2 | if vim.g.loaded_dashboard then 3 | return 4 | end 5 | 6 | vim.g.loaded_dashboard = 1 7 | 8 | vim.api.nvim_create_autocmd('UIEnter', { 9 | group = vim.api.nvim_create_augroup('Dashboard', { clear = true }), 10 | callback = function() 11 | if vim.fn.argc() == 0 and vim.fn.line2byte('$') == -1 then 12 | require('dashboard'):instance() 13 | end 14 | end, 15 | }) 16 | 17 | vim.api.nvim_create_user_command('Dashboard', function() 18 | require('dashboard'):instance() 19 | end, {}) 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | pull_request: 9 | branches: 10 | - master 11 | 12 | jobs: 13 | lint: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v3 17 | - name: Stylua 18 | uses: JohnnyMorganz/stylua-action@v1.1.2 19 | with: 20 | token: ${{ secrets.GITHUB_TOKEN }} 21 | args: --check . 22 | 23 | docs: 24 | runs-on: ubuntu-latest 25 | name: pandoc to vimdoc 26 | steps: 27 | - uses: actions/checkout@v3 28 | - name: panvimdoc 29 | uses: kdheepak/panvimdoc@main 30 | with: 31 | vimdoc: dashboard 32 | version: Nvim 0.8.0 33 | - uses: stefanzweifel/git-auto-commit-action@v4 34 | with: 35 | commit_message: 'chore(doc): auto generate docs' 36 | commit_user_name: "github-actions[bot]" 37 | commit_user_email: "github-actions[bot]@users.noreply.github.com" 38 | commit_author: "github-actions[bot] " 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 StephenHuan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lua/dashboard/events.lua: -------------------------------------------------------------------------------- 1 | local api, lsp, uv = vim.api, vim.lsp, vim.loop 2 | local au = {} 3 | 4 | function au.register_lsp_root(path) 5 | api.nvim_create_autocmd('VimLeavePre', { 6 | callback = function() 7 | local projects = {} 8 | for _, client in pairs(lsp.get_active_clients() or {}) do 9 | local root_dir = client.config.root_dir 10 | if root_dir and not vim.tbl_contains(projects, root_dir) then 11 | table.insert(projects, root_dir) 12 | end 13 | 14 | for _, folder in pairs(client.workspace_folders or {}) do 15 | if not vim.tbl_contains(projects, folder.name) then 16 | table.insert(projects, folder.name) 17 | end 18 | end 19 | end 20 | 21 | if #projects == 0 then 22 | return 23 | end 24 | 25 | -- callback hell holy shit but simply than write a async await lib 26 | -- also I don't link to add a thirdpart plugin. this is just a small code 27 | uv.fs_open(path, 'rs+', 438, function(err, fd) 28 | assert(not err, err) 29 | uv.fs_fstat(fd, function(err, stat) 30 | assert(not err, err) 31 | uv.fs_read(fd, stat.size, 0, function(err, data) 32 | assert(not err, err) 33 | local before = assert(loadstring(data)) 34 | local plist = before() 35 | if plist and #plist > 10 then 36 | plist = vim.list_slice(plist, 10) 37 | end 38 | plist = vim.tbl_filter(function(k) 39 | return not vim.tbl_contains(projects, k) 40 | end, plist or {}) 41 | plist = vim.list_extend(plist, projects) 42 | local dump = 'return ' .. vim.inspect(plist) 43 | uv.fs_write(fd, dump, 0, function(err, _) 44 | assert(not err, err) 45 | uv.fs_ftruncate(fd, #dump, function(err, _) 46 | assert(not err, err) 47 | uv.fs_close(fd) 48 | end) 49 | end) 50 | end) 51 | end) 52 | end) 53 | end, 54 | }) 55 | end 56 | 57 | return au 58 | -------------------------------------------------------------------------------- /lua/dashboard/utils.lua: -------------------------------------------------------------------------------- 1 | local uv = vim.loop 2 | local utils = {} 3 | 4 | utils.is_win = uv.os_uname().version:match('Windows') 5 | 6 | function utils.path_join(...) 7 | local path_sep = utils.is_win and '\\' or '/' 8 | return table.concat({ ... }, path_sep) 9 | end 10 | 11 | function utils.element_align(tbl) 12 | local lens = {} 13 | vim.tbl_map(function(k) 14 | table.insert(lens, vim.api.nvim_strwidth(k)) 15 | end, tbl) 16 | table.sort(lens) 17 | local max = lens[#lens] 18 | local res = {} 19 | for _, item in pairs(tbl) do 20 | local len = vim.api.nvim_strwidth(item) 21 | local times = math.floor((max - len) / vim.api.nvim_strwidth(' ')) 22 | item = item .. (' '):rep(times) 23 | table.insert(res, item) 24 | end 25 | return res 26 | end 27 | 28 | function utils.get_max_len(contents) 29 | vim.validate({ 30 | contents = { contents, 't' }, 31 | }) 32 | local cells = {} 33 | for _, v in pairs(contents) do 34 | table.insert(cells, vim.api.nvim_strwidth(v)) 35 | end 36 | table.sort(cells) 37 | return cells[#cells] 38 | end 39 | 40 | -- draw the graphics into the screen center 41 | function utils.center_align(tbl) 42 | vim.validate({ 43 | tbl = { tbl, 'table' }, 44 | }) 45 | local function fill_sizes(lines) 46 | local fills = {} 47 | for _, line in pairs(lines) do 48 | table.insert(fills, math.floor((vim.o.columns - vim.api.nvim_strwidth(line)) / 2)) 49 | end 50 | return fills 51 | end 52 | 53 | local centered_lines = {} 54 | local fills = fill_sizes(tbl) 55 | 56 | for i = 1, #tbl do 57 | local fill_line = (' '):rep(fills[i]) .. tbl[i] 58 | table.insert(centered_lines, fill_line) 59 | end 60 | 61 | return centered_lines 62 | end 63 | 64 | function utils.get_icon(ft) 65 | local ok, devicons = pcall(require, 'nvim-web-devicons') 66 | if not ok then 67 | vim.notify('[dashboard.nvim] not found nvim-web-devicons') 68 | return nil 69 | end 70 | return devicons.get_icon_by_filetype(ft, { default = true }) 71 | end 72 | 73 | function utils.read_project_cache(path) 74 | local fd = assert(uv.fs_open(path, 'r', tonumber('644', 8))) 75 | local stat = uv.fs_fstat(fd) 76 | local chunk = uv.fs_read(fd, stat.size, 0) 77 | local dump = assert(loadstring(chunk)) 78 | return dump() 79 | end 80 | 81 | function utils.async_read(path, callback) 82 | uv.fs_open(path, 'a+', 438, function(err, fd) 83 | assert(not err, err) 84 | uv.fs_fstat(fd, function(err, stat) 85 | assert(not err, err) 86 | uv.fs_read(fd, stat.size, 0, function(err, data) 87 | assert(not err, err) 88 | uv.fs_close(fd, function(err) 89 | assert(not err, err) 90 | callback(data) 91 | end) 92 | end) 93 | end) 94 | end) 95 | end 96 | 97 | function utils.disable_move_key(bufnr) 98 | local keys = { 'w', 'f', 'b', 'h', 'j', 'k', 'l', '', '', '', '' } 99 | vim.tbl_map(function(k) 100 | vim.keymap.set('n', k, '', { buffer = bufnr }) 101 | end, keys) 102 | end 103 | 104 | --- return the most recently files list 105 | function utils.get_mru_list() 106 | local mru = {} 107 | for _, file in pairs(vim.v.oldfiles or {}) do 108 | if file and vim.fn.filereadable(file) == 1 then 109 | table.insert(mru, file) 110 | end 111 | end 112 | return mru 113 | end 114 | 115 | function utils.get_packages_count() 116 | local count = 0 117 | ---@diagnostic disable-next-line: undefined-global 118 | if packer_plugins then 119 | ---@diagnostic disable-next-line: undefined-global 120 | count = #vim.tbl_keys(packer_plugins) 121 | end 122 | local status, lazy = pcall(require, 'lazy') 123 | if status then 124 | count = lazy.stats().count 125 | end 126 | return count 127 | end 128 | 129 | --- generate an empty table by length 130 | function utils.generate_empty_table(length) 131 | local empty_tbl = {} 132 | if length == 0 then 133 | return empty_tbl 134 | end 135 | 136 | for _ = 1, length do 137 | table.insert(empty_tbl, '') 138 | end 139 | return empty_tbl 140 | end 141 | 142 | function utils.generate_truncateline(cells) 143 | local char = '┉' 144 | return char:rep(math.floor(cells / vim.api.nvim_strwidth(char))) 145 | end 146 | 147 | function utils.get_vcs_root(buf) 148 | buf = buf or 0 149 | local path = vim.fn.fnamemodify(vim.api.nvim_buf_get_name(buf), ':p:h') 150 | local patterns = { '.git', '.hg', '.bzr', '.svn' } 151 | for _, pattern in pairs(patterns) do 152 | local root = vim.fs.find(pattern, { path = path, upward = true, stop = vim.env.HOME }) 153 | if root then 154 | return root 155 | end 156 | end 157 | end 158 | 159 | local index = 0 160 | function utils.gen_bufname(prefix) 161 | index = index + 1 162 | return prefix .. '-' .. index 163 | end 164 | 165 | return utils 166 | -------------------------------------------------------------------------------- /lua/dashboard/preview.lua: -------------------------------------------------------------------------------- 1 | local api = vim.api 2 | 3 | local view = {} 4 | 5 | function view:open_window(opt) 6 | local row = math.floor(opt.height / 5) 7 | local col = math.floor((vim.o.columns - opt.width) / 2) 8 | 9 | local opts = { 10 | relative = 'editor', 11 | row = row, 12 | col = col, 13 | width = opt.width, 14 | height = opt.height, 15 | style = 'minimal', 16 | noautocmd = true, 17 | } 18 | 19 | self.bufnr = api.nvim_create_buf(false, true) 20 | api.nvim_buf_set_option(self.bufnr, 'filetype', 'dashboardpreview') 21 | self.winid = api.nvim_open_win(self.bufnr, false, opts) 22 | if vim.fn.has('nvim-0.8') == 1 then 23 | local normal = api.nvim_get_hl_by_name('Normal', true) 24 | pcall(api.nvim_set_hl, 0, 'DashboardPreview', normal) 25 | else 26 | api.nvim_set_hl(0, 'DashboardPreview', { bg = 'none' }) 27 | end 28 | api.nvim_win_set_option(self.winid, 'winhl', 'Normal:DashboardPreview') 29 | return { self.bufnr, self.winid } 30 | end 31 | 32 | function view:close_preview_window() 33 | if self.bufnr and api.nvim_buf_is_loaded(self.bufnr) then 34 | api.nvim_buf_delete(self.bufnr, { force = true }) 35 | self.bufnr = nil 36 | end 37 | 38 | if self.winid and api.nvim_win_is_valid(self.winid) then 39 | api.nvim_win_close(self.winid, true) 40 | self.winid = nil 41 | end 42 | end 43 | 44 | function view:preview_events() 45 | local group = 46 | api.nvim_create_augroup('DashboardClosePreview' .. self.preview_bufnr, { clear = true }) 47 | 48 | --refresh the preview window col position. 49 | local function refresh_preview_wincol() 50 | if not self.preview_winid or not api.nvim_win_is_valid(self.preview_winid) then 51 | return 52 | end 53 | 54 | local winconfig = api.nvim_win_get_config(self.preview_winid) 55 | local cur_width = api.nvim_win_get_width(self.main_winid) 56 | if cur_width ~= self.win_width then 57 | local wins = api.nvim_list_wins() 58 | if #wins == 2 then 59 | local scol = bit.rshift(vim.o.columns, 1) - bit.rshift(winconfig.width, 1) 60 | winconfig.col[false] = scol 61 | api.nvim_win_set_config(self.preview_winid, winconfig) 62 | self.win_width = cur_width 63 | return 64 | end 65 | 66 | if #wins == 3 then 67 | local new_win = vim.tbl_filter(function(k) 68 | return k ~= self.main_winid and k ~= self.preview_winid 69 | end, wins)[1] 70 | winconfig.col[false] = winconfig.col[false] + api.nvim_win_get_width(new_win) 71 | api.nvim_win_set_config(self.preview_winid, winconfig) 72 | self.win_width = cur_width 73 | end 74 | end 75 | end 76 | 77 | api.nvim_create_autocmd('BufEnter', { 78 | group = group, 79 | callback = function(opt) 80 | local ignored = { 'prompt', 'nofile' } 81 | if vim.tbl_contains(ignored, vim.bo[opt.buf].buftype) then 82 | return 83 | end 84 | 85 | if 86 | vim.bo[opt.buf].filetype ~= 'dashboard' 87 | and opt.buf ~= self.preview_bufnr 88 | and self.winid 89 | and api.nvim_win_is_valid(self.preview_winid) 90 | then 91 | api.nvim_win_close(self.preview_winid, true) 92 | self.preview_winid = nil 93 | self.preview_bufnr = nil 94 | self.main_winid = nil 95 | self.win_width = nil 96 | pcall(api.nvim_del_augroup_by_id, group) 97 | end 98 | end, 99 | desc = 'Dashboard close or regenerate preview window', 100 | }) 101 | 102 | local function winresized() 103 | api.nvim_create_autocmd('WinResized', { 104 | group = group, 105 | callback = function() 106 | refresh_preview_wincol() 107 | end, 108 | desc = ' Dashboard preview window resized for nvim 0.9', 109 | }) 110 | end 111 | 112 | api.nvim_create_autocmd('VimResized', { 113 | group = group, 114 | callback = function() 115 | refresh_preview_wincol() 116 | end, 117 | }) 118 | 119 | if vim.fn.has('nvim-0.9') == 1 then 120 | winresized() 121 | else 122 | ---@deprecated when 0.9 version release remove 123 | api.nvim_create_autocmd('BufEnter', { 124 | group = group, 125 | callback = function() 126 | refresh_preview_wincol() 127 | end, 128 | desc = 'dashboard preview window resize for neovim 0.8+ version', 129 | }) 130 | end 131 | end 132 | 133 | function view:open_preview(opt) 134 | self.preview_bufnr, self.preview_winid = unpack(view:open_window(opt)) 135 | 136 | api.nvim_buf_call(self.preview_bufnr, function() 137 | vim.fn.termopen(opt.cmd, { 138 | on_exit = function() end, 139 | }) 140 | end) 141 | self.main_winid = api.nvim_get_current_win() 142 | self.win_width = api.nvim_win_get_width(self.main_winid) 143 | 144 | self:preview_events() 145 | end 146 | 147 | return view 148 | -------------------------------------------------------------------------------- /lua/dashboard/theme/header.lua: -------------------------------------------------------------------------------- 1 | local api = vim.api 2 | local utils = require('dashboard.utils') 3 | 4 | local function week_ascii_text() 5 | return { 6 | ['Monday'] = { 7 | '', 8 | '███╗ ███╗ ██████╗ ███╗ ██╗██████╗ █████╗ ██╗ ██╗', 9 | '████╗ ████║██╔═══██╗████╗ ██║██╔══██╗██╔══██╗╚██╗ ██╔╝', 10 | '██╔████╔██║██║ ██║██╔██╗ ██║██║ ██║███████║ ╚████╔╝ ', 11 | '██║╚██╔╝██║██║ ██║██║╚██╗██║██║ ██║██╔══██║ ╚██╔╝ ', 12 | '██║ ╚═╝ ██║╚██████╔╝██║ ╚████║██████╔╝██║ ██║ ██║ ', 13 | '╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝╚═════╝ ╚═╝ ╚═╝ ╚═╝ ', 14 | '', 15 | }, 16 | ['Tuesday'] = { 17 | '', 18 | '████████╗██╗ ██╗███████╗███████╗██████╗ █████╗ ██╗ ██╗', 19 | '╚══██╔══╝██║ ██║██╔════╝██╔════╝██╔══██╗██╔══██╗╚██╗ ██╔╝', 20 | ' ██║ ██║ ██║█████╗ ███████╗██║ ██║███████║ ╚████╔╝ ', 21 | ' ██║ ██║ ██║██╔══╝ ╚════██║██║ ██║██╔══██║ ╚██╔╝ ', 22 | ' ██║ ╚██████╔╝███████╗███████║██████╔╝██║ ██║ ██║ ', 23 | ' ╚═╝ ╚═════╝ ╚══════╝╚══════╝╚═════╝ ╚═╝ ╚═╝ ╚═╝ ', 24 | '', 25 | }, 26 | ['Wednesday'] = { 27 | '', 28 | '██╗ ██╗███████╗██████╗ ███╗ ██╗███████╗███████╗██████╗ █████╗ ██╗ ██╗', 29 | '██║ ██║██╔════╝██╔══██╗████╗ ██║██╔════╝██╔════╝██╔══██╗██╔══██╗╚██╗ ██╔╝', 30 | '██║ █╗ ██║█████╗ ██║ ██║██╔██╗ ██║█████╗ ███████╗██║ ██║███████║ ╚████╔╝ ', 31 | '██║███╗██║██╔══╝ ██║ ██║██║╚██╗██║██╔══╝ ╚════██║██║ ██║██╔══██║ ╚██╔╝ ', 32 | '╚███╔███╔╝███████╗██████╔╝██║ ╚████║███████╗███████║██████╔╝██║ ██║ ██║ ', 33 | '', 34 | }, 35 | ['Thursday'] = { 36 | '', 37 | '████████╗██╗ ██╗██╗ ██╗██████╗ ███████╗██████╗ █████╗ ██╗ ██╗', 38 | '╚══██╔══╝██║ ██║██║ ██║██╔══██╗██╔════╝██╔══██╗██╔══██╗╚██╗ ██╔╝', 39 | ' ██║ ███████║██║ ██║██████╔╝███████╗██║ ██║███████║ ╚████╔╝ ', 40 | ' ██║ ██╔══██║██║ ██║██╔══██╗╚════██║██║ ██║██╔══██║ ╚██╔╝ ', 41 | ' ██║ ██║ ██║╚██████╔╝██║ ██║███████║██████╔╝██║ ██║ ██║ ', 42 | ' ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═════╝ ╚═╝ ╚═╝ ╚═╝ ', 43 | '', 44 | }, 45 | ['Friday'] = { 46 | '', 47 | '███████╗██████╗ ██╗██████╗ █████╗ ██╗ ██╗', 48 | '██╔════╝██╔══██╗██║██╔══██╗██╔══██╗╚██╗ ██╔╝', 49 | '█████╗ ██████╔╝██║██║ ██║███████║ ╚████╔╝ ', 50 | '██╔══╝ ██╔══██╗██║██║ ██║██╔══██║ ╚██╔╝ ', 51 | '██║ ██║ ██║██║██████╔╝██║ ██║ ██║ ', 52 | '╚═╝ ╚═╝ ╚═╝╚═╝╚═════╝ ╚═╝ ╚═╝ ╚═╝ ', 53 | '', 54 | }, 55 | ['Saturday'] = { 56 | '', 57 | '███████╗ █████╗ ████████╗██╗ ██╗██████╗ ██████╗ █████╗ ██╗ ██╗', 58 | '██╔════╝██╔══██╗╚══██╔══╝██║ ██║██╔══██╗██╔══██╗██╔══██╗╚██╗ ██╔╝', 59 | '███████╗███████║ ██║ ██║ ██║██████╔╝██║ ██║███████║ ╚████╔╝ ', 60 | '╚════██║██╔══██║ ██║ ██║ ██║██╔══██╗██║ ██║██╔══██║ ╚██╔╝ ', 61 | '███████║██║ ██║ ██║ ╚██████╔╝██║ ██║██████╔╝██║ ██║ ██║ ', 62 | '╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝ ╚═╝ ', 63 | '', 64 | }, 65 | ['Sunday'] = { 66 | '', 67 | '███████╗██╗ ██╗███╗ ██╗██████╗ █████╗ ██╗ ██╗', 68 | '██╔════╝██║ ██║████╗ ██║██╔══██╗██╔══██╗╚██╗ ██╔╝', 69 | '███████╗██║ ██║██╔██╗ ██║██║ ██║███████║ ╚████╔╝ ', 70 | '╚════██║██║ ██║██║╚██╗██║██║ ██║██╔══██║ ╚██╔╝ ', 71 | '███████║╚██████╔╝██║ ╚████║██████╔╝██║ ██║ ██║ ', 72 | '╚══════╝ ╚═════╝ ╚═╝ ╚═══╝╚═════╝ ╚═╝ ╚═╝ ╚═╝ ', 73 | '', 74 | }, 75 | } 76 | end 77 | 78 | local function default_header() 79 | return { 80 | '', 81 | ' ██████╗ █████╗ ███████╗██╗ ██╗██████╗ ██████╗ █████╗ ██████╗ ██████╗ ', 82 | ' ██╔══██╗██╔══██╗██╔════╝██║ ██║██╔══██╗██╔═══██╗██╔══██╗██╔══██╗██╔══██╗ ', 83 | ' ██║ ██║███████║███████╗███████║██████╔╝██║ ██║███████║██████╔╝██║ ██║ ', 84 | ' ██║ ██║██╔══██║╚════██║██╔══██║██╔══██╗██║ ██║██╔══██║██╔══██╗██║ ██║ ', 85 | ' ██████╔╝██║ ██║███████║██║ ██║██████╔╝╚██████╔╝██║ ██║██║ ██║██████╔╝ ', 86 | ' ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ', 87 | '', 88 | } 89 | end 90 | 91 | local function week_header(concat, append) 92 | local week = week_ascii_text() 93 | local daysoftheweek = 94 | { 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' } 95 | local day = daysoftheweek[os.date('*t').wday] 96 | local tbl = week[day] 97 | table.insert(tbl, os.date('%Y-%m-%d %H:%M:%S ') .. (concat or '')) 98 | if append then 99 | vim.list_extend(tbl, append) 100 | end 101 | table.insert(tbl, '') 102 | return tbl 103 | end 104 | 105 | local function generate_header(config) 106 | if not vim.bo[config.bufnr].modifiable then 107 | vim.bo[config.bufnr].modifiable = true 108 | end 109 | if not config.command then 110 | local header = config.week_header 111 | and config.week_header.enable 112 | and week_header(config.week_header.concat, config.week_header.append) 113 | or (config.header or default_header()) 114 | api.nvim_buf_set_lines(config.bufnr, 0, -1, false, utils.center_align(header)) 115 | 116 | for i, _ in ipairs(header) do 117 | vim.api.nvim_buf_add_highlight(config.bufnr, 0, 'DashboardHeader', i - 1, 0, -1) 118 | end 119 | return 120 | end 121 | 122 | local empty_table = utils.generate_empty_table(config.file_height + 4) 123 | api.nvim_buf_set_lines(config.bufnr, 0, -1, false, utils.center_align(empty_table)) 124 | local preview = require('dashboard.preview') 125 | preview:open_preview({ 126 | width = config.file_width, 127 | height = config.file_height, 128 | cmd = config.command .. ' ' .. config.file_path, 129 | }) 130 | end 131 | 132 | return { 133 | generate_header = generate_header, 134 | } 135 | -------------------------------------------------------------------------------- /lua/dashboard/theme/doom.lua: -------------------------------------------------------------------------------- 1 | local api = vim.api 2 | local utils = require('dashboard.utils') 3 | 4 | local function generate_center(config) 5 | local lines = {} 6 | local center = config.center 7 | or { 8 | { desc = 'Please config your own center section', key = 'p' }, 9 | } 10 | 11 | local counts = {} 12 | for _, item in pairs(center) do 13 | local count = item.keymap and #item.keymap or 0 14 | local line = (item.icon or '') .. item.desc 15 | 16 | if item.key then 17 | line = line .. (' '):rep(#item.key + 4) 18 | count = count + #item.key + 3 19 | if type(item.action) == 'string' then 20 | vim.keymap.set('n', item.key, function() 21 | local dump = loadstring(item.action) 22 | if not dump then 23 | vim.cmd(item.action) 24 | else 25 | dump() 26 | end 27 | end, { buffer = config.bufnr, nowait = true, silent = true }) 28 | elseif type(item.action) == 'function' then 29 | vim.keymap.set( 30 | 'n', 31 | item.key, 32 | item.action, 33 | { buffer = config.bufnr, nowait = true, silent = true } 34 | ) 35 | end 36 | end 37 | 38 | if item.keymap then 39 | line = line .. (' '):rep(#item.keymap) 40 | end 41 | 42 | table.insert(lines, line) 43 | table.insert(lines, '') 44 | table.insert(counts, count) 45 | table.insert(counts, 0) 46 | end 47 | 48 | lines = utils.element_align(lines) 49 | lines = utils.center_align(lines) 50 | for i, count in ipairs(counts) do 51 | lines[i] = lines[i]:sub(1, #lines[i] - count) 52 | end 53 | 54 | local first_line = api.nvim_buf_line_count(config.bufnr) 55 | api.nvim_buf_set_lines(config.bufnr, first_line, -1, false, lines) 56 | 57 | if not config.center then 58 | return 59 | end 60 | 61 | local ns = api.nvim_create_namespace('DashboardDoom') 62 | local seed = 0 63 | local pos_map = {} 64 | for i = 1, #lines do 65 | if lines[i]:find('%w') then 66 | local idx = i == 1 and i or i - seed 67 | seed = seed + 1 68 | pos_map[i] = idx 69 | local _, scol = lines[i]:find('%s+') 70 | local ecol = scol + (config.center[idx].icon and #config.center[idx].icon or 0) 71 | 72 | if config.center[idx].icon then 73 | api.nvim_buf_add_highlight( 74 | config.bufnr, 75 | 0, 76 | config.center[idx].icon_hl or 'DashboardIcon', 77 | first_line + i - 1, 78 | 0, 79 | ecol 80 | ) 81 | end 82 | 83 | api.nvim_buf_add_highlight( 84 | config.bufnr, 85 | 0, 86 | config.center[idx].desc_hl or 'DashboardDesc', 87 | first_line + i - 1, 88 | ecol, 89 | -1 90 | ) 91 | 92 | if config.center[idx].key then 93 | local virt_tbl = {} 94 | if config.center[idx].keymap then 95 | table.insert(virt_tbl, { config.center[idx].keymap, 'DashboardShortCut' }) 96 | end 97 | table.insert( 98 | virt_tbl, 99 | { ' [' .. config.center[idx].key .. ']', config.center[idx].key_hl or 'DashboardKey' } 100 | ) 101 | api.nvim_buf_set_extmark(config.bufnr, ns, first_line + i - 1, 0, { 102 | virt_text_pos = 'eol', 103 | virt_text = virt_tbl, 104 | }) 105 | end 106 | end 107 | end 108 | 109 | local line = api.nvim_buf_get_lines(config.bufnr, first_line, first_line + 1, false)[1] 110 | local col = line:find('%w') 111 | api.nvim_win_set_cursor(config.winid, { first_line + 1, col - 1 }) 112 | 113 | local bottom = api.nvim_buf_line_count(config.bufnr) 114 | vim.defer_fn(function() 115 | local before = 0 116 | api.nvim_create_autocmd('CursorMoved', { 117 | buffer = config.bufnr, 118 | callback = function() 119 | local curline = api.nvim_win_get_cursor(0)[1] 120 | if curline < first_line + 1 then 121 | curline = bottom - 1 122 | elseif curline > bottom - 1 then 123 | curline = first_line + 1 124 | elseif not api.nvim_get_current_line():find('%w') then 125 | curline = curline + (before > curline and -1 or 1) 126 | end 127 | before = curline 128 | api.nvim_win_set_cursor(config.winid, { curline, col - 1 }) 129 | end, 130 | }) 131 | end, 0) 132 | 133 | vim.keymap.set('n', config.confirm_key or '', function() 134 | local curline = api.nvim_win_get_cursor(0)[1] 135 | local index = pos_map[curline - first_line] 136 | if index and config.center[index].action then 137 | if type(config.center[index].action) == 'string' then 138 | local dump = loadstring(config.center[index].action) 139 | if not dump then 140 | vim.cmd(config.center[index].action) 141 | else 142 | dump() 143 | end 144 | elseif type(config.center[index].action) == 'function' then 145 | config.center[index].action() 146 | else 147 | print('Error with action, check your config') 148 | end 149 | end 150 | end, { buffer = config.bufnr, nowait = true, silent = true }) 151 | end 152 | 153 | local function generate_footer(config) 154 | local first_line = api.nvim_buf_line_count(config.bufnr) 155 | local footer = type(config.footer) == 'function' and config.footer() 156 | or config.footer 157 | or { '', '', 'neovim loaded ' .. utils.get_packages_count() .. ' packages' } 158 | api.nvim_buf_set_lines(config.bufnr, first_line, -1, false, utils.center_align(footer)) 159 | for i = 1, #footer do 160 | api.nvim_buf_add_highlight(config.bufnr, 0, 'DashboardFooter', first_line + i - 1, 0, -1) 161 | end 162 | end 163 | 164 | ---@private 165 | local function theme_instance(config) 166 | require('dashboard.theme.header').generate_header(config) 167 | generate_center(config) 168 | generate_footer(config) 169 | api.nvim_set_option_value('modifiable', false, { buf = config.bufnr }) 170 | end 171 | 172 | return setmetatable({}, { 173 | __call = function(_, t) 174 | return theme_instance(t) 175 | end, 176 | }) 177 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Fancy and Blazing Fast start screen plugin of neovim 3 |

4 | 5 | |
Hyper
|
Doom
| 6 | | --- | --- | 7 | |
|
| 8 | 9 | # Feature 10 | 11 | - 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. 12 | - Blazing fast 13 | 14 | 15 | # Install 16 | 17 | - Lazy.nvim 18 | 19 | ```lua 20 | { 21 | 'glepnir/dashboard-nvim', 22 | event = 'VimEnter', 23 | config = function() 24 | require('dashboard').setup { 25 | -- config 26 | } 27 | end, 28 | dependencies = { {'nvim-tree/nvim-web-devicons'}} 29 | } 30 | ``` 31 | 32 | - Packer 33 | 34 | ```lua 35 | use { 36 | 'glepnir/dashboard-nvim', 37 | event = 'VimEnter', 38 | config = function() 39 | require('dashboard').setup { 40 | -- config 41 | } 42 | end, 43 | requires = {'nvim-tree/nvim-web-devicons'} 44 | } 45 | ``` 46 | 47 | # Configuration 48 | 49 | ## Options 50 | 51 | ```lua 52 | theme = 'hyper' -- theme is doom and hyper default is hyper 53 | disable_move -- defualt is false disable move keymap for hyper 54 | shortcut_type -- shorcut type 'letter' or 'number' 55 | change_to_vcs_root -- default is false,for open file in hyper mru. it will change to the root of vcs 56 | config = {}, -- config used for theme 57 | hide = { 58 | statusline -- hide statusline default is true 59 | tabline -- hide the tabline 60 | winbar -- hide winbar 61 | }, 62 | preview = { 63 | command -- preview command 64 | file_path -- preview file path 65 | file_height -- preview file height 66 | file_width -- preview file width 67 | }, 68 | ``` 69 | 70 | ## Theme config 71 | 72 | the `config` field is used for theme. general field 73 | 74 | ```lua 75 | config = { 76 | header -- type is table def 77 | week_header = { 78 | enable --boolean use a week header 79 | concat --concat string after time string line 80 | append --table append after time string line 81 | }, 82 | disable_move -- boolean default is false disable move key 83 | } 84 | ``` 85 | 86 | ### Hyper 87 | 88 | when use `hyper` theme the available options in `config` is 89 | 90 | ```lua 91 | config = { 92 | shortcut = { 93 | -- action can be a function type 94 | { desc = string, group = 'highlight group', key = 'shortcut key', action = 'action when you press key' }, 95 | }, 96 | packages = { enable = true }, -- show how many plugins neovim loaded 97 | -- limit how many projects list, action when you press key or enter it will run this action. 98 | -- action can be a functino type, e.g. 99 | -- action = func(path) vim.cmd('Telescope find_files cwd=' .. path) end 100 | project = { enable = true, limit = 8, icon = 'your icon', label = '', action = 'Telescope find_files cwd=' }, 101 | mru = { limit = 10, icon = 'your icon', label = '', }, 102 | footer = {}, -- footer 103 | } 104 | ``` 105 | 106 | ### Doom 107 | 108 | when use `doom` theme the available options in `config` is 109 | 110 | ```lua 111 | config = { 112 | center = { 113 | { 114 | icon = '', 115 | icon_hl = 'group', 116 | desc = 'description', 117 | desc_hl = 'group', 118 | key = 'shortcut key in dashboard buffer not keymap !!', 119 | key_hl = 'group', 120 | action = '', 121 | }, 122 | }, 123 | footer = {}, 124 | } 125 | ``` 126 | 127 | notice if you don't link config every highlight group. you can ignore this key. 128 | dashboard will use default highlight group like `DashboardKey/Icon/Desc` instead 129 | 130 | ### Commands 131 | 132 | - `Dashboard` open dashboard 133 | - `DbProjectDelete count` delete project in cache works for hyper theme. count is number 134 | 135 | ### Highlight 136 | 137 | all highlight groups 138 | 139 | ``` 140 | -- General 141 | DashboardHeader DashboardFooter 142 | -- Hyper theme 143 | DashboardProjectTitle DashboardProjectTitleIcon DashboardProjectIcon 144 | DashboardMruTitle DashboardMruIcon DashboardFiles DashboardShotCutIcon 145 | -- Doome theme 146 | DashboardDesc DashboardKey DashboardIcon DashboardShotCut 147 | ``` 148 | 149 | ### Example config 150 | 151 | example config of screenshot 152 | 153 |
154 | Hyper 155 | 156 | ```lua 157 | db.setup({ 158 | theme = 'hyper', 159 | config = { 160 | week_header = { 161 | enable = true, 162 | }, 163 | shortcut = { 164 | { desc = ' Update', group = '@property', action = 'Lazy update', key = 'u' }, 165 | { 166 | icon = ' ', 167 | icon_hl = '@variable', 168 | desc = 'Files', 169 | group = 'Label', 170 | action = 'Telescope find_files', 171 | key = 'f', 172 | }, 173 | { 174 | desc = ' Apps', 175 | group = 'DiagnosticHint', 176 | action = 'Telescope app', 177 | key = 'a', 178 | }, 179 | { 180 | desc = ' dotfiles', 181 | group = 'Number', 182 | action = 'Telescope dotfiles', 183 | key = 'd', 184 | }, 185 | }, 186 | }, 187 | }) 188 | ``` 189 |
190 | 191 |
192 | Doom 193 | 194 | ```lua 195 | db.setup({ 196 | theme = 'doom', 197 | config = { 198 | header = {}, --your header 199 | center = { 200 | { 201 | icon = ' ', 202 | icon_hl = 'Title', 203 | desc = 'Find File ', 204 | desc_hl = 'String', 205 | key = 'b', 206 | keymap = 'SPC f f', 207 | key_hl = 'Number', 208 | action = 'lua print(2)' 209 | }, 210 | { 211 | icon = ' ', 212 | desc = 'Find Dotfiles', 213 | key = 'f', 214 | keymap = 'SPC f d', 215 | action = 'lua print(3)' 216 | }, 217 | }, 218 | footer = {} --your footer 219 | } 220 | }) 221 | ``` 222 |
0 then 211 | config = vim.tbl_extend('force', config, self.opts.preview) 212 | end 213 | 214 | require('dashboard.theme.' .. opts.theme)(config) 215 | self:cache_ui_options(opts) 216 | 217 | api.nvim_create_autocmd('VimResized', { 218 | buffer = self.bufnr, 219 | callback = function() 220 | require('dashboard.theme.' .. opts.theme)(config) 221 | vim.bo[self.bufnr].modifiable = false 222 | end, 223 | }) 224 | 225 | api.nvim_create_autocmd('BufEnter', { 226 | callback = function(opt) 227 | local bufs = api.nvim_list_bufs() 228 | bufs = vim.tbl_filter(function(k) 229 | return vim.bo[k].filetype == 'dashboard' 230 | end, bufs) 231 | if #bufs == 0 then 232 | self:cache_opts() 233 | self:restore_options() 234 | clean_ctx() 235 | pcall(api.nvim_del_autocmd, opt.id) 236 | end 237 | end, 238 | desc = '[Dashboard] clean dashboard data reduce memory', 239 | }) 240 | end 241 | 242 | -- create dashboard instance 243 | function db:instance() 244 | local mode = api.nvim_get_mode().mode 245 | if mode == 'i' or not vim.bo.modifiable then 246 | return 247 | end 248 | 249 | if not vim.o.hidden and vim.bo.modified then 250 | --save before open 251 | vim.cmd.write() 252 | return 253 | end 254 | 255 | if vim.fn.line2byte('$') ~= -1 then 256 | vim.cmd('noautocmd') 257 | self.bufnr = api.nvim_create_buf(true, true) 258 | else 259 | self.bufnr = api.nvim_get_current_buf() 260 | end 261 | 262 | self.winid = api.nvim_get_current_win() 263 | api.nvim_win_set_buf(self.winid, self.bufnr) 264 | 265 | self.user_cursor_line = vim.opt.cursorline:get() 266 | buf_local() 267 | if self.opts then 268 | self:load_theme(self.opts) 269 | else 270 | self:get_opts(function(obj) 271 | self:load_theme(obj) 272 | end) 273 | end 274 | end 275 | 276 | function db.setup(opts) 277 | opts = opts or {} 278 | ctx.opts = vim.tbl_deep_extend('force', default_options(), opts) 279 | end 280 | 281 | return setmetatable(ctx, db) 282 | -------------------------------------------------------------------------------- /doc/dashboard.txt: -------------------------------------------------------------------------------- 1 | *dashboard.txt* For Nvim 0.8.0 Last change: 2023 March 16 2 | 3 | ============================================================================== 4 | Table of Contents *dashboard-table-of-contents* 5 | 6 | 1. Feature |dashboard-feature| 7 | 2. Install |dashboard-install| 8 | 3. Configuration |dashboard-configuration| 9 | - Options |dashboard-configuration-options| 10 | - Theme config |dashboard-configuration-theme-config| 11 | 4. Backers |dashboard-backers| 12 | 5. Donate |dashboard-donate| 13 | 6. LICENSE |dashboard-license| 14 | Fancy and Blazing Fast start screen plugin of neovim ----------------------------------- ----------------------------------- 15 | 16 | 17 | ----------------------------------- ----------------------------------- 18 | 19 | ============================================================================== 20 | 1. Feature *dashboard-feature* 21 | 22 | 23 | - 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. 24 | - Blazing fast 25 | 26 | 27 | ============================================================================== 28 | 2. Install *dashboard-install* 29 | 30 | 31 | - Lazy.nvim 32 | 33 | >lua 34 | { 35 | 'glepnir/dashboard-nvim', 36 | event = 'VimEnter', 37 | config = function() 38 | require('dashboard').setup { 39 | -- config 40 | } 41 | end, 42 | dependencies = { {'nvim-tree/nvim-web-devicons'}} 43 | } 44 | < 45 | 46 | 47 | - Packer 48 | 49 | >lua 50 | use { 51 | 'glepnir/dashboard-nvim', 52 | event = 'VimEnter', 53 | config = function() 54 | require('dashboard').setup { 55 | -- config 56 | } 57 | end, 58 | requires = {'nvim-tree/nvim-web-devicons'} 59 | } 60 | < 61 | 62 | 63 | ============================================================================== 64 | 3. Configuration *dashboard-configuration* 65 | 66 | 67 | OPTIONS *dashboard-configuration-options* 68 | 69 | >lua 70 | theme = 'hyper' -- theme is doom and hyper default is hyper 71 | disable_move -- defualt is false disable move keymap for hyper 72 | shortcut_type -- shorcut type 'letter' or 'number' 73 | change_to_vcs_root -- default is false,for open file in hyper mru. it will change to the root of vcs 74 | config = {}, -- config used for theme 75 | hide = { 76 | statusline -- hide statusline default is true 77 | tabline -- hide the tabline 78 | winbar -- hide winbar 79 | }, 80 | preview = { 81 | command -- preview command 82 | file_path -- preview file path 83 | file_height -- preview file height 84 | file_width -- preview file width 85 | }, 86 | < 87 | 88 | 89 | THEME CONFIG *dashboard-configuration-theme-config* 90 | 91 | the `config` field is used for theme. general field 92 | 93 | >lua 94 | config = { 95 | header -- type is table def 96 | week_header = { 97 | enable --boolean use a week header 98 | concat --concat string after time string line 99 | append --table append after time string line 100 | }, 101 | disable_move -- boolean default is false disable move key 102 | } 103 | < 104 | 105 | 106 | HYPER ~ 107 | 108 | when use `hyper` theme the available options in `config` is 109 | 110 | >lua 111 | config = { 112 | shortcut = { 113 | -- action can be a function type 114 | { desc = string, group = 'highlight group', key = 'shortcut key', action = 'action when you press key' }, 115 | }, 116 | packages = { enable = true }, -- show how many plugins neovim loaded 117 | -- limit how many projects list, action when you press key or enter it will run this action. 118 | -- action can be a functino type, e.g. 119 | -- action = func(path) vim.cmd('Telescope find_files cwd=' .. path) end 120 | project = { enable = true, limit = 8, icon = 'your icon', label = '', action = 'Telescope find_files cwd=' }, 121 | mru = { limit = 10, icon = 'your icon', label = '', }, 122 | footer = {}, -- footer 123 | } 124 | < 125 | 126 | 127 | DOOM ~ 128 | 129 | when use `doom` theme the available options in `config` is 130 | 131 | >lua 132 | config = { 133 | center = { 134 | { 135 | icon = '', 136 | icon_hl = 'group', 137 | desc = 'description', 138 | desc_hl = 'group', 139 | key = 'shortcut key in dashboard buffer not keymap !!', 140 | key_hl = 'group', 141 | action = '', 142 | }, 143 | }, 144 | footer = {}, 145 | } 146 | < 147 | 148 | notice if you don’t link config every highlight group. you can ignore this 149 | key. dashboard will use default highlight group like `DashboardKey/Icon/Desc` 150 | instead 151 | 152 | 153 | COMMANDS ~ 154 | 155 | 156 | - `Dashboard` open dashboard 157 | - `DbProjectDelete count` delete project in cache works for hyper theme. count is number 158 | 159 | 160 | HIGHLIGHT ~ 161 | 162 | all highlight groups 163 | 164 | > 165 | -- General 166 | DashboardHeader DashboardFooter 167 | -- Hyper theme 168 | DashboardProjectTitle DashboardProjectTitleIcon DashboardProjectIcon 169 | DashboardMruTitle DashboardMruIcon DashboardFiles DashboardShotCutIcon 170 | -- Doome theme 171 | DashboardDesc DashboardKey DashboardIcon DashboardShotCut 172 | < 173 | 174 | 175 | EXAMPLE CONFIG ~ 176 | 177 | example config of screenshot 178 | 179 | Hyper ~ 180 | 181 | >lua 182 | db.setup({ 183 | theme = 'hyper', 184 | config = { 185 | week_header = { 186 | enable = true, 187 | }, 188 | shortcut = { 189 | { desc = ' Update', group = '@property', action = 'Lazy update', key = 'u' }, 190 | { 191 | icon = ' ', 192 | icon_hl = '@variable', 193 | desc = 'Files', 194 | group = 'Label', 195 | action = 'Telescope find_files', 196 | key = 'f', 197 | }, 198 | { 199 | desc = ' Apps', 200 | group = 'DiagnosticHint', 201 | action = 'Telescope app', 202 | key = 'a', 203 | }, 204 | { 205 | desc = ' dotfiles', 206 | group = 'Number', 207 | action = 'Telescope dotfiles', 208 | key = 'd', 209 | }, 210 | }, 211 | }, 212 | }) 213 | < 214 | 215 | Doom ~ 216 | 217 | >lua 218 | db.setup({ 219 | theme = 'doom', 220 | config = { 221 | header = {}, --your header 222 | center = { 223 | { 224 | icon = ' ', 225 | icon_hl = 'Title', 226 | desc = 'Find File ', 227 | desc_hl = 'String', 228 | key = 'b', 229 | keymap = 'SPC f f', 230 | key_hl = 'Number', 231 | action = 'lua print(2)' 232 | }, 233 | { 234 | icon = ' ', 235 | desc = 'Find Dotfiles', 236 | key = 'f', 237 | keymap = 'SPC f d', 238 | action = 'lua print(3)' 239 | }, 240 | }, 241 | footer = {} --your footer 242 | } 243 | }) 244 | < 245 | 246 | 254 | - Removed Ueberzug script, as the Ueberzug author has deleted the repository. 255 | 256 | 257 | TODO ~ 258 | 259 | 260 | - I will write a plugin to implement some popular terminal evaluators image protocol then I think 261 | can make it work with dashboard 262 | 263 | 264 | ============================================================================== 265 | 4. Backers *dashboard-backers* 266 | 267 | @RakerZh 268 | 269 | 270 | ============================================================================== 271 | 5. Donate *dashboard-donate* 272 | 273 | If you’d like to support my work financially, buy me a drink through Github 274 | Sponsor or 275 | 276 | 277 | ============================================================================== 278 | 6. LICENSE *dashboard-license* 279 | 280 | MIT 281 | 282 | ============================================================================== 283 | 7. Links *dashboard-links* 284 | 285 | 1. *@RakerZh*: 286 | 2. **: https://img.shields.io/badge/PayPal-00457C?style=for-the-badge&logo=paypal&logoColor=white 287 | 288 | Generated by panvimdoc 289 | 290 | vim:tw=78:ts=8:noet:ft=help:norl: 291 | -------------------------------------------------------------------------------- /lua/dashboard/theme/hyper.lua: -------------------------------------------------------------------------------- 1 | local api, keymap = vim.api, vim.keymap 2 | local utils = require('dashboard.utils') 3 | local ns = api.nvim_create_namespace('dashboard') 4 | 5 | local function gen_shortcut(config) 6 | local shortcut = config.shortcut 7 | or { 8 | { desc = '[ Github]', group = 'DashboardShortCut' }, 9 | { desc = '[ glepnir]', group = 'DashboardShortCut' }, 10 | { desc = '[ 0.2.3]', group = 'DashboardShortCut' }, 11 | } 12 | 13 | if vim.tbl_isempty(shortcut) then 14 | shortcut = {} 15 | end 16 | 17 | local lines = '' 18 | for _, item in pairs(shortcut) do 19 | local str = item.icon and item.icon .. item.desc or item.desc 20 | if item.key then 21 | str = str .. '[' .. item.key .. ']' 22 | end 23 | lines = lines .. ' ' .. str 24 | end 25 | 26 | local first_line = api.nvim_buf_line_count(config.bufnr) 27 | api.nvim_buf_set_lines(config.bufnr, first_line, -1, false, utils.center_align({ lines })) 28 | 29 | local line = api.nvim_buf_get_lines(config.bufnr, first_line, -1, false)[1] 30 | local start = line:find('[^%s]') - 1 31 | for _, item in pairs(shortcut) do 32 | local _end = start + (item.icon and #(item.icon .. item.desc) or #item.desc) 33 | if item.key then 34 | _end = _end + api.nvim_strwidth(item.key) + 2 35 | keymap.set('n', item.key, function() 36 | if type(item.action) == 'string' then 37 | local dump = loadstring(item.action) 38 | if not dump then 39 | vim.cmd(item.action) 40 | else 41 | dump() 42 | end 43 | elseif type(item.action) == 'function' then 44 | item.action() 45 | end 46 | end, { buffer = config.bufnr, nowait = true, silent = true }) 47 | end 48 | 49 | api.nvim_buf_add_highlight( 50 | config.bufnr, 51 | 0, 52 | item.group or 'DashboardShortCut', 53 | first_line, 54 | start, 55 | _end 56 | ) 57 | 58 | if item.icon then 59 | api.nvim_buf_add_highlight( 60 | config.bufnr, 61 | 0, 62 | item.icon_hl or 'DashboardShortCutIcon', 63 | first_line, 64 | start, 65 | start + #item.icon 66 | ) 67 | end 68 | start = _end + 2 69 | end 70 | end 71 | 72 | local function load_packages(config) 73 | local packages = config.packages or { 74 | enable = true, 75 | } 76 | if not packages.enable then 77 | return 78 | end 79 | 80 | local lines = { 81 | '', 82 | 'neovim loaded ' .. utils.get_packages_count() .. ' packages', 83 | } 84 | 85 | local first_line = api.nvim_buf_line_count(config.bufnr) 86 | api.nvim_buf_set_lines(config.bufnr, first_line, -1, false, utils.center_align(lines)) 87 | 88 | for i, _ in pairs(lines) do 89 | api.nvim_buf_add_highlight(config.bufnr, 0, 'Comment', first_line + i - 1, 0, -1) 90 | end 91 | end 92 | 93 | local function reverse(tbl) 94 | for i = 1, math.floor(#tbl / 2) do 95 | tbl[i], tbl[#tbl - i + 1] = tbl[#tbl - i + 1], tbl[i] 96 | end 97 | end 98 | 99 | local function project_list(config, callback) 100 | config.project = vim.tbl_extend('force', { 101 | limit = 8, 102 | enable = true, 103 | icon = ' ', 104 | icon_hl = 'DashboardRecentProjectIcon', 105 | action = 'Telescope find_files cwd=', 106 | label = ' Recent Projects:', 107 | }, config.project or {}) 108 | 109 | local function read_project(data) 110 | local res = {} 111 | local dump = assert(loadstring(data)) 112 | local list = dump() 113 | if list then 114 | list = vim.list_slice(list, #list - config.project.limit) 115 | end 116 | for _, dir in ipairs(list or {}) do 117 | dir = dir:gsub(vim.env.HOME, '~') 118 | table.insert(res, (' '):rep(3) .. ' ' .. dir) 119 | end 120 | 121 | if #res == 0 then 122 | table.insert(res, (' '):rep(3) .. ' empty project') 123 | else 124 | reverse(res) 125 | end 126 | 127 | table.insert(res, 1, config.project.icon .. config.project.label) 128 | table.insert(res, 1, '') 129 | table.insert(res, '') 130 | return res 131 | end 132 | 133 | utils.async_read( 134 | config.path, 135 | vim.schedule_wrap(function(data) 136 | local res = {} 137 | if config.project.enable then 138 | res = read_project(data) 139 | end 140 | callback(res) 141 | end) 142 | ) 143 | end 144 | 145 | local function mru_list(config) 146 | config.mru = vim.tbl_extend('force', { 147 | icon = ' ', 148 | limit = 10, 149 | icon_hl = 'DashboardMruIcon', 150 | label = ' Most Recent Files:', 151 | }, config.mru or {}) 152 | 153 | local list = { 154 | config.mru.icon .. config.mru.label, 155 | } 156 | 157 | local groups = {} 158 | local mlist = utils.get_mru_list() 159 | 160 | for _, file in pairs(vim.list_slice(mlist, 1, config.mru.limit)) do 161 | local ft = vim.filetype.match({ filename = file }) 162 | local icon, group = utils.get_icon(ft) 163 | icon = icon or ' ' 164 | if not utils.is_win then 165 | file = file:gsub(vim.env.HOME, '~') 166 | end 167 | file = icon .. ' ' .. file 168 | table.insert(groups, { #icon, group }) 169 | table.insert(list, (' '):rep(3) .. file) 170 | end 171 | 172 | if #list == 1 then 173 | table.insert(list, (' '):rep(3) .. ' empty files') 174 | end 175 | return list, groups 176 | end 177 | 178 | local function letter_hotkey(config) 179 | local list = { 106, 107 } 180 | for _, item in pairs(config.shortcut or {}) do 181 | if item.key then 182 | table.insert(list, item.key:byte()) 183 | end 184 | end 185 | math.randomseed(os.time()) 186 | return function() 187 | while true do 188 | local key = math.random(97, 122) 189 | if not vim.tbl_contains(list, key) then 190 | table.insert(list, key) 191 | return string.char(key) 192 | end 193 | end 194 | end 195 | end 196 | 197 | local function number_hotkey() 198 | local start = 0 199 | return function() 200 | start = start + 1 201 | return start 202 | end 203 | end 204 | 205 | local function gen_hotkey(config) 206 | if config.shortcut_type == 'number' then 207 | return number_hotkey() 208 | end 209 | return letter_hotkey(config) 210 | end 211 | 212 | local function map_key(config, key, content) 213 | keymap.set('n', key, function() 214 | local text = content or api.nvim_get_current_line() 215 | local scol = utils.is_win and text:find('%w') or text:find('%p') 216 | text = text:sub(scol) 217 | local path = text:sub(1, text:find('%w(%s+)$')) 218 | path = vim.fs.normalize(path) 219 | if vim.fn.isdirectory(path) == 1 then 220 | vim.cmd('lcd ' .. path) 221 | if type(config.project.action) == 'function' then 222 | config.project.action(path) 223 | elseif type(config.project.action) == 'string' then 224 | local dump = loadstring(config.project.action) 225 | if not dump then 226 | vim.cmd(config.project.action .. path) 227 | else 228 | dump(path) 229 | end 230 | end 231 | else 232 | vim.cmd('edit ' .. path) 233 | local root = utils.get_vcs_root() 234 | if not config.change_to_vcs_root then 235 | return 236 | end 237 | if #root > 0 then 238 | vim.cmd('lcd ' .. vim.fn.fnamemodify(root[#root], ':h')) 239 | else 240 | vim.cmd('lcd ' .. vim.fn.fnamemodify(path, ':h')) 241 | end 242 | end 243 | end, { buffer = config.bufnr, silent = true, nowait = true }) 244 | end 245 | 246 | local function gen_center(plist, config) 247 | local mlist, mgroups = mru_list(config) 248 | local plist_len = #plist 249 | if plist_len == 0 then 250 | plist[#plist + 1] = '' 251 | plist_len = 1 252 | end 253 | ---@diagnostic disable-next-line: param-type-mismatch 254 | vim.list_extend(plist, mlist) 255 | local max_len = utils.get_max_len(plist) 256 | if max_len <= 40 then 257 | local fill = (' '):rep(math.floor(vim.o.columns / 4)) 258 | for i, v in pairs(plist) do 259 | plist[i] = v .. fill 260 | end 261 | end 262 | 263 | plist = utils.element_align(plist) 264 | plist = utils.center_align(plist) 265 | local first_line = api.nvim_buf_line_count(config.bufnr) 266 | api.nvim_buf_set_lines(config.bufnr, first_line, -1, false, plist) 267 | 268 | local start_col = plist[plist_len + 2]:find('[^%s]') - 1 269 | local _, scol = plist[2]:find('%S') 270 | 271 | local hotkey = gen_hotkey(config) 272 | 273 | api.nvim_buf_add_highlight(config.bufnr, 0, 'DashboardProjectTitle', first_line + 1, 0, -1) 274 | api.nvim_buf_add_highlight( 275 | config.bufnr, 276 | 0, 277 | 'DashboardProjectTitleIcon', 278 | first_line + 1, 279 | 0, 280 | scol + #config.project.icon 281 | ) 282 | 283 | for i = 3, plist_len do 284 | api.nvim_buf_add_highlight( 285 | config.bufnr, 286 | 0, 287 | 'DashboardProjectIcon', 288 | first_line + i - 1, 289 | 0, 290 | start_col + 3 291 | ) 292 | api.nvim_buf_add_highlight( 293 | config.bufnr, 294 | 0, 295 | 'DashboardFiles', 296 | first_line + i - 1, 297 | start_col + 3, 298 | -1 299 | ) 300 | local text = api.nvim_buf_get_lines(config.bufnr, first_line + i - 1, first_line + i, false)[1] 301 | if text and text:find('%w') and not text:find('empty') then 302 | local key = tostring(hotkey()) 303 | api.nvim_buf_set_extmark(config.bufnr, ns, first_line + i - 1, 0, { 304 | virt_text = { { key, 'DashboardShortCut' } }, 305 | virt_text_pos = 'eol', 306 | }) 307 | map_key(config, key, text) 308 | end 309 | end 310 | 311 | -- initialize the cursor pos 312 | api.nvim_win_set_cursor(config.winid, { first_line + 3, start_col + 4 }) 313 | 314 | api.nvim_buf_add_highlight(config.bufnr, 0, 'DashboardMruTitle', first_line + plist_len, 0, -1) 315 | api.nvim_buf_add_highlight( 316 | config.bufnr, 317 | 0, 318 | 'DashboardMruIcon', 319 | first_line + plist_len, 320 | 0, 321 | scol + #config.mru.icon 322 | ) 323 | 324 | for i, data in pairs(mgroups) do 325 | local len, group = unpack(data) 326 | api.nvim_buf_add_highlight( 327 | config.bufnr, 328 | 0, 329 | group, 330 | first_line + i + plist_len, 331 | start_col, 332 | start_col + len 333 | ) 334 | api.nvim_buf_add_highlight( 335 | config.bufnr, 336 | 0, 337 | 'DashboardFiles', 338 | first_line + i + plist_len, 339 | start_col + len, 340 | -1 341 | ) 342 | 343 | local text = api.nvim_buf_get_lines( 344 | config.bufnr, 345 | first_line + i + plist_len, 346 | first_line + i + plist_len + 1, 347 | false 348 | )[1] 349 | if text and text:find('%w') then 350 | local key = tostring(hotkey()) 351 | api.nvim_buf_set_extmark(config.bufnr, ns, first_line + i + plist_len, 0, { 352 | virt_text = { { key, 'DashboardShortCut' } }, 353 | virt_text_pos = 'eol', 354 | }) 355 | map_key(config, key, text) 356 | end 357 | end 358 | end 359 | 360 | local function gen_footer(config) 361 | local footer = { 362 | '', 363 | ' 🚀 Every day matters', 364 | } 365 | 366 | if type(config.footer) == 'string' then 367 | local dump = loadstring(config.footer) 368 | if dump then 369 | footer = dump() 370 | end 371 | elseif type(config.footer) == 'function' then 372 | footer = config.footer() 373 | end 374 | 375 | local first_line = api.nvim_buf_line_count(config.bufnr) 376 | api.nvim_buf_set_lines(config.bufnr, first_line, -1, false, utils.center_align(footer)) 377 | 378 | ---@diagnostic disable-next-line: param-type-mismatch 379 | for i, _ in pairs(footer) do 380 | api.nvim_buf_add_highlight(config.bufnr, 0, 'DashboardFooter', first_line + i - 1, 0, -1) 381 | end 382 | end 383 | 384 | local function project_delete() 385 | api.nvim_create_user_command('DbProjectDelete', function(args) 386 | local path = utils.path_join(vim.fn.stdpath('cache'), 'dashboard', 'cache') 387 | utils.async_read( 388 | path, 389 | vim.schedule_wrap(function(data) 390 | local dump = assert(loadstring(data)) 391 | local list = dump() 392 | local count = tonumber(args.args) 393 | if vim.tbl_count(list) < count then 394 | return 395 | end 396 | list = vim.list_slice(list, count + 1) 397 | local str = string.dump(assert(loadstring('return ' .. vim.inspect(list)))) 398 | local handle = io.open(path, 'w+') 399 | if not handle then 400 | return 401 | end 402 | handle:write(str) 403 | handle:close() 404 | end) 405 | ) 406 | end, { 407 | nargs = '+', 408 | }) 409 | end 410 | 411 | local function theme_instance(config) 412 | project_list(config, function(plist) 413 | if config.disable_move then 414 | utils.disable_move_key(config.bufnr) 415 | end 416 | require('dashboard.theme.header').generate_header(config) 417 | gen_shortcut(config) 418 | load_packages(config) 419 | gen_center(plist, config) 420 | gen_footer(config) 421 | map_key(config, config.confirm_key or '') 422 | require('dashboard.events').register_lsp_root(config.path) 423 | local size = math.floor(vim.o.lines / 2) 424 | - math.ceil(api.nvim_buf_line_count(config.bufnr) / 2) 425 | - 2 426 | local fill = utils.generate_empty_table(size) 427 | api.nvim_buf_set_lines(config.bufnr, 0, 0, false, fill) 428 | vim.bo[config.bufnr].modifiable = false 429 | project_delete() 430 | end) 431 | end 432 | 433 | return setmetatable({}, { 434 | __call = function(_, t) 435 | theme_instance(t) 436 | end, 437 | }) 438 | --------------------------------------------------------------------------------