Skip to content

Latest commit

Β 

History

History
546 lines (455 loc) Β· 14.9 KB

dashboard.md

File metadata and controls

546 lines (455 loc) Β· 14.9 KB

🍿 dashboard

✨ Features

  • declarative configuration
  • flexible layouts
  • multiple vertical panes
  • built-in sections:
    • header: show a header
    • keys: show keymaps
    • projects: show recent projects
    • recent_files: show recent files
    • session: session support
    • startup: startup time (lazy.nvim)
    • terminal: colored terminal output
  • super fast terminal sections with automatic caching

πŸš€ Usage

The dashboard comes with a set of default sections, that can be customized with opts.preset or fully replaced with opts.sections.

The default preset comes with support for:

Section actions

A section can have an action property that will be executed as:

  • a command if it starts with :
  • a keymap if it's a string not starting with :
  • a function if it's a function
-- command
{
  action = ":Telescope find_files",
  key = "f",
},
-- keymap
{
  action = "<leader>ff",
  key = "f",
},
-- function
{
  action = function()
    require("telescope.builtin").find_files()
  end,
  key = "h",
},

Item text

Every item should have a text property with an array of snacks.dashboard.Text objects. If the text property is not provided, the snacks.dashboard.Config.formats will be used to generate the text.

In the example below, both sections are equivalent.

{
  text = {
    { "  ", hl = "SnacksDashboardIcon" },
    { "Find File", hl = "SnacksDashboardDesc", width = 50 },
    { "[f]", hl = "SnacksDashboardKey" },
  },
  action = ":Telescope find_files",
  key = "f",
},
{
  action = ":Telescope find_files",
  key = "f",
  desc = "Find File",
  icon = " ",
},

βš™οΈ Config

---@class snacks.dashboard.Config
---@field sections snacks.dashboard.Section
---@field formats table<string, snacks.dashboard.Text|fun(item:snacks.dashboard.Item, ctx:snacks.dashboard.Format.ctx):snacks.dashboard.Text>
{
  width = 60,
  row = nil, -- dashboard position. nil for center
  col = nil, -- dashboard position. nil for center
  pane_gap = 4, -- empty columns between vertical panes
  autokeys = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", -- autokey sequence
  -- These settings are used by some built-in sections
  preset = {
    -- Defaults to a picker that supports `fzf-lua`, `telescope.nvim` and `mini.pick`
    ---@type fun(cmd:string, opts:table)|nil
    pick = nil,
    -- Used by the `keys` section to show keymaps.
    -- Set your custom keymaps here.
    -- When using a function, the `items` argument are the default keymaps.
    ---@type snacks.dashboard.Item[]
    keys = {
      { icon = " ", key = "f", desc = "Find File", action = ":lua Snacks.dashboard.pick('files')" },
      { icon = "ο…› ", key = "n", desc = "New File", action = ":ene | startinsert" },
      { icon = "ο€’ ", key = "g", desc = "Find Text", action = ":lua Snacks.dashboard.pick('live_grep')" },
      { icon = "οƒ… ", key = "r", desc = "Recent Files", action = ":lua Snacks.dashboard.pick('oldfiles')" },
      { icon = " ", key = "c", desc = "Config", action = ":lua Snacks.dashboard.pick('files', {cwd = vim.fn.stdpath('config')})" },
      { icon = " ", key = "s", desc = "Restore Session", section = "session" },
      { icon = "σ°’² ", key = "L", desc = "Lazy", action = ":Lazy", enabled = package.loaded.lazy ~= nil },
      { icon = " ", key = "q", desc = "Quit", action = ":qa" },
    },
    -- Used by the `header` section
    header = [[
β–ˆβ–ˆβ–ˆβ•—   β–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•—   β–ˆβ–ˆβ•—β–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ•—   β–ˆβ–ˆβ–ˆβ•—
β–ˆβ–ˆβ–ˆβ–ˆβ•—  β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β•β•β•β–ˆβ–ˆβ•”β•β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ•‘
β–ˆβ–ˆβ•”β–ˆβ–ˆβ•— β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—  β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β–ˆβ–ˆβ–ˆβ–ˆβ•”β–ˆβ–ˆβ•‘
β–ˆβ–ˆβ•‘β•šβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β•  β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•‘β•šβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘β•šβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘
β–ˆβ–ˆβ•‘ β•šβ–ˆβ–ˆβ–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β• β•šβ–ˆβ–ˆβ–ˆβ–ˆβ•”β• β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β•šβ•β• β–ˆβ–ˆβ•‘
β•šβ•β•  β•šβ•β•β•β•β•šβ•β•β•β•β•β•β• β•šβ•β•β•β•β•β•   β•šβ•β•β•β•  β•šβ•β•β•šβ•β•     β•šβ•β•]],
  },
  -- item field formatters
  formats = {
    icon = function(item)
      if item.file and item.icon == "file" or item.icon == "directory" then
        return M.icon(item.file, item.icon)
      end
      return { item.icon, width = 2, hl = "icon" }
    end,
    footer = { "%s", align = "center" },
    header = { "%s", align = "center" },
    file = function(item, ctx)
      local fname = vim.fn.fnamemodify(item.file, ":~")
      fname = ctx.width and #fname > ctx.width and vim.fn.pathshorten(fname) or fname
      local dir, file = fname:match("^(.*)/(.+)$")
      return dir and { { dir .. "/", hl = "dir" }, { file, hl = "file" } } or { { fname, hl = "file" } }
    end,
  },
  sections = {
    { section = "header" },
    { section = "keys", gap = 1, padding = 1 },
    { section = "startup" },
  },
}

πŸš€ Examples

advanced

A more advanced example using multiple panes image

{
  sections = {
    { section = "header" },
    {
      pane = 2,
      section = "terminal",
      cmd = "colorscript -e square",
      height = 5,
      padding = 1,
    },
    { section = "keys", gap = 1, padding = 1 },
    { pane = 2, icon = "ο…› ", title = "Recent Files", section = "recent_files", indent = 2, padding = 1 },
    { pane = 2, icon = " ", title = "Projects", section = "projects", indent = 2, padding = 1 },
    {
      pane = 2,
      icon = "ξœ₯ ",
      title = "Git Status",
      section = "terminal",
      enabled = Snacks.git.get_root() ~= nil,
      cmd = "hub status --short --branch --renames",
      height = 5,
      padding = 1,
      ttl = 5 * 60,
      indent = 3,
    },
    { section = "startup" },
  },
}

chafa

An example using the chafa command to display an image image

{
  sections = {
    {
      section = "terminal",
      cmd = "chafa ~/.config/wall.png --format symbols --symbols vhalf --size 60x17 --stretch; sleep .1",
      height = 17,
      padding = 1,
    },
    {
      pane = 2,
      { section = "keys", gap = 1, padding = 1 },
      { section = "startup" },
    },
  },
}

compact_files

A more compact version of the files example image

{
  sections = {
    { section = "header" },
    { icon = "ο„œ ", title = "Keymaps", section = "keys", indent = 2, padding = 1 },
    { icon = "ο…› ", title = "Recent Files", section = "recent_files", indent = 2, padding = 1 },
    { icon = " ", title = "Projects", section = "projects", indent = 2, padding = 1 },
    { section = "startup" },
  },
}

doom

Similar to the Emacs Doom dashboard image

{
  sections = {
    { section = "header" },
    { section = "keys", gap = 1, padding = 1 },
    { section = "startup" },
  },
}

files

A simple example with a header, keys, recent files, and projects image

{
  sections = {
    { section = "header" },
    { section = "keys", gap = 1 },
    { icon = "ο…› ", title = "Recent Files", section = "recent_files", indent = 2, padding = { 2, 2 } },
    { icon = " ", title = "Projects", section = "projects", indent = 2, padding = 2 },
    { section = "startup" },
  },
}

pokemon

Pokemons, because why not? image

{
  sections = {
    { section = "header" },
    { section = "keys", gap = 1, padding = 1 },
    { section = "startup" },
    {
      section = "terminal",
      cmd = "pokemon-colorscripts -r --no-title; sleep .1",
      random = 10,
      pane = 2,
      indent = 4,
      height = 30,
    },
  },
}

startify

Similar to the Vim Startify dashboard image

{
  formats = {
    key = function(item)
      return { { "[", hl = "special" }, { item.key, hl = "key" }, { "]", hl = "special" } }
    end,
  },
  sections = {
    { section = "terminal", cmd = "fortune -s | cowsay", hl = "header", padding = 1, indent = 8 },
    { title = "MRU", padding = 1 },
    { section = "recent_files", limit = 8, padding = 1 },
    { title = "MRU ", file = vim.fn.fnamemodify(".", ":~"), padding = 1 },
    { section = "recent_files", cwd = true, limit = 8, padding = 1 },
    { title = "Sessions", padding = 1 },
    { section = "projects", padding = 1 },
    { title = "Bookmarks", padding = 1 },
    { section = "keys" },
  },
}

🎨 Styles

dashboard

The default style for the dashboard. When opening the dashboard during startup, only the bo and wo options are used. The other options are used with :lua Snacks.dashboard()

{
  zindex = 10,
  height = 0,
  width = 0,
  bo = {
    bufhidden = "wipe",
    buftype = "nofile",
    filetype = "snacks_dashboard",
    swapfile = false,
    undofile = false,
  },
  wo = {
    colorcolumn = "",
    cursorcolumn = false,
    cursorline = false,
    list = false,
    number = false,
    relativenumber = false,
    sidescrolloff = 0,
    signcolumn = "no",
    spell = false,
    statuscolumn = "",
    statusline = "",
    winbar = "",
    winhighlight = "Normal:SnacksDashboardNormal,NormalFloat:SnacksDashboardNormal",
    wrap = false,
  },
}

πŸ“š Types

---@class snacks.dashboard.Item
---@field indent? number
---@field align? "left" | "center" | "right"
---@field gap? number the number of empty lines between child items
---@field padding? number | {[1]:number, [2]:number} bottom or {bottom, top} padding
--- The action to run when the section is selected or the key is pressed.
--- * if it's a string starting with `:`, it will be run as a command
--- * if it's a string, it will be executed as a keymap
--- * if it's a function, it will be called
---@field action? snacks.dashboard.Action
---@field enabled? boolean|fun(opts:snacks.dashboard.Opts):boolean if false, the section will be disabled
---@field section? string the name of a section to include. See `Snacks.dashboard.sections`
---@field [string] any section options
---@field key? string shortcut key
---@field autokey? boolean automatically assign a numerical key
---@field label? string
---@field desc? string
---@field file? string
---@field footer? string
---@field header? string
---@field icon? string
---@field title? string
---@field text? string|snacks.dashboard.Text[]
---@alias snacks.dashboard.Format.ctx {width?:number}
---@alias snacks.dashboard.Action string|fun(self:snacks.dashboard.Class)
---@alias snacks.dashboard.Gen fun(self:snacks.dashboard.Class):snacks.dashboard.Section?
---@alias snacks.dashboard.Section snacks.dashboard.Item|snacks.dashboard.Gen|snacks.dashboard.Section[]
---@class snacks.dashboard.Text
---@field [1] string the text
---@field hl? string the highlight group
---@field width? number the width used for alignment
---@field align? "left" | "center" | "right"
---@class snacks.dashboard.Opts: snacks.dashboard.Config
---@field buf? number the buffer to use. If not provided, a new buffer will be created
---@field win? number the window to use. If not provided, a new floating window will be created

πŸ“¦ Module

Snacks.dashboard()

---@type fun(opts?: snacks.dashboard.Opts): snacks.dashboard.Class
Snacks.dashboard()

Snacks.dashboard.have_plugin()

Checks if the plugin is installed. Only works with lazy.nvim

---@param name string
Snacks.dashboard.have_plugin(name)

Snacks.dashboard.health()

Snacks.dashboard.health()

Snacks.dashboard.icon()

Get an icon

---@param name string
---@param cat? string
---@return snacks.dashboard.Text
Snacks.dashboard.icon(name, cat)

Snacks.dashboard.open()

---@param opts? snacks.dashboard.Opts
---@return snacks.dashboard.Class
Snacks.dashboard.open(opts)

Snacks.dashboard.pick()

Used by the default preset to pick something

---@param cmd? string
Snacks.dashboard.pick(cmd, opts)

Snacks.dashboard.sections.header()

---@return snacks.dashboard.Gen
Snacks.dashboard.sections.header()

Snacks.dashboard.sections.keys()

---@return snacks.dashboard.Gen
Snacks.dashboard.sections.keys()

Snacks.dashboard.sections.projects()

Get the most recent projects based on git roots of recent files. The default action will change the directory to the project root, try to restore the session and open the picker if the session is not restored. You can customize the behavior by providing a custom action. Use opts.dirs to provide a list of directories to use instead of the git roots.

---@param opts? {limit?:number, dirs?:(string[]|fun():string[]), pick?:boolean, session?:boolean, action?:fun(dir)}
Snacks.dashboard.sections.projects(opts)

Snacks.dashboard.sections.recent_files()

Get the most recent files, optionally filtered by the current working directory or a custom directory.

---@param opts? {limit?:number, cwd?:string|boolean}
---@return snacks.dashboard.Gen
Snacks.dashboard.sections.recent_files(opts)

Snacks.dashboard.sections.session()

Adds a section to restore the session if any of the supported plugins are installed.

---@param item? snacks.dashboard.Item
---@return snacks.dashboard.Item?
Snacks.dashboard.sections.session(item)

Snacks.dashboard.sections.startup()

Add the startup section

---@return snacks.dashboard.Section?
Snacks.dashboard.sections.startup()

Snacks.dashboard.sections.terminal()

---@param opts {cmd:string|string[], ttl?:number, height?:number, width?:number, random?:number}|snacks.dashboard.Item
---@return snacks.dashboard.Gen
Snacks.dashboard.sections.terminal(opts)

Snacks.dashboard.setup()

Check if the dashboard should be opened

Snacks.dashboard.setup()

Snacks.dashboard.update()

Update the dashboard

Snacks.dashboard.update()