Skip to content

Latest commit

 

History

History
306 lines (266 loc) · 8.99 KB

image.md

File metadata and controls

306 lines (266 loc) · 8.99 KB

🍿 image

Image

✨ Features

  • Image viewer using the Kitty Graphics Protocol.
  • open images in a wide range of formats: pdf, png, jpg, jpeg, gif, bmp, webp, tiff, heic, avif, mp4, mov, avi, mkv, webm
  • Supports inline image rendering in: markdown, html, norg, tsx, javascript, css, vue, svelte, scss, latex, typst
  • LaTex math expressions in markdown and latex documents

Terminal support:

  • kitty
  • ghostty
  • wezterm Wezterm has only limited support for the kitty graphics protocol. Inline image rendering is not supported.
  • tmux Snacks automatically tries to enable allow-passthrough=on for tmux, but you may need to enable it manually in your tmux configuration.
  • zellij is not supported, since they don't have any support for passthrough

Image will be transferred to the terminal by filename or by sending the image date in case ssh is detected.

In some cases you may need to force snacks to detect or not detect a certain environment. You can do this by setting SNACKS_${ENV_NAME} to true or false.

For example, to force detection of ghostty you can set SNACKS_GHOSTTY=true.

In order to automatically display the image when opening an image file, or to have imaged displayed in supported document formats like markdown or html, you need to enable the image plugin in your snacks config.

ImageMagick is required to convert images to the supported formats (all except PNG).

In case of issues, make sure to run :checkhealth snacks.

📦 Setup

-- lazy.nvim
{
  "folke/snacks.nvim",
  ---@type snacks.Config
  opts = {
    image = {
      -- your image configuration comes here
      -- or leave it empty to use the default settings
      -- refer to the configuration section below
    }
  }
}

⚙️ Config

---@class snacks.image.Config
---@field enabled? boolean enable image viewer
---@field wo? vim.wo|{} options for windows showing the image
---@field bo? vim.bo|{} options for the image buffer
---@field formats? string[]
--- Resolves a reference to an image with src in a file (currently markdown only).
--- Return the absolute path or url to the image.
--- When `nil`, the path is resolved relative to the file.
---@field resolve? fun(file: string, src: string): string?
---@field convert? snacks.image.convert.Config
{
  formats = {
    "png",
    "jpg",
    "jpeg",
    "gif",
    "bmp",
    "webp",
    "tiff",
    "heic",
    "avif",
    "mp4",
    "mov",
    "avi",
    "mkv",
    "webm",
    "pdf",
  },
  force = false, -- try displaying the image, even if the terminal does not support it
  doc = {
    -- enable image viewer for documents
    -- a treesitter parser must be available for the enabled languages.
    enabled = true,
    -- render the image inline in the buffer
    -- if your env doesn't support unicode placeholders, this will be disabled
    -- takes precedence over `opts.float` on supported terminals
    inline = true,
    -- render the image in a floating window
    -- only used if `opts.inline` is disabled
    float = true,
    max_width = 80,
    max_height = 40,
    -- Set to `true`, to conceal the image text when rendering inline.
    -- (experimental)
    ---@param lang string tree-sitter language
    ---@param type snacks.image.Type image type
    conceal = function(lang, type)
      -- only conceal math expressions
      return type == "math"
    end,
  },
  img_dirs = { "img", "images", "assets", "static", "public", "media", "attachments" },
  -- window options applied to windows displaying image buffers
  -- an image buffer is a buffer with `filetype=image`
  wo = {
    wrap = false,
    number = false,
    relativenumber = false,
    cursorcolumn = false,
    signcolumn = "no",
    foldcolumn = "0",
    list = false,
    spell = false,
    statuscolumn = "",
  },
  cache = vim.fn.stdpath("cache") .. "/snacks/image",
  debug = {
    request = false,
    convert = false,
    placement = false,
  },
  env = {},
  -- icons used to show where an inline image is located that is
  -- rendered below the text.
  icons = {
    math = "󰪚 ",
    chart = "󰄧 ",
    image = "",
  },
  ---@class snacks.image.convert.Config
  convert = {
    notify = true, -- show a notification on error
    ---@type snacks.image.args
    mermaid = function()
      local theme = vim.o.background == "light" and "neutral" or "dark"
      return { "-i", "{src}", "-o", "{file}", "-b", "transparent", "-t", theme, "-s", "{scale}" }
    end,
    ---@type table<string,snacks.image.args>
    magick = {
      default = { "{src}[0]", "-scale", "1920x1080>" }, -- default for raster images
      vector = { "-density", 192, "{src}[0]" }, -- used by vector images like svg
      math = { "-density", 192, "{src}[0]", "-trim" },
      pdf = { "-density", 192, "{src}[0]", "-background", "white", "-alpha", "remove", "-trim" },
    },
  },
  math = {
    enabled = true, -- enable math expression rendering
    -- in the templates below, `${header}` comes from any section in your document,
    -- between a start/end header comment. Comment syntax is language-specific.
    -- * start comment: `// snacks: header start`
    -- * end comment:   `// snacks: header end`
    typst = {
      tpl = [[
        #set page(width: auto, height: auto, margin: (x: 2pt, y: 2pt))
        #show math.equation.where(block: false): set text(top-edge: "bounds", bottom-edge: "bounds")
        #set text(size: 12pt, fill: rgb("${color}"))
        ${header}
        ${content}]],
    },
    latex = {
      font_size = "Large", -- see https://www.sascha-frank.com/latex-font-size.html
      -- for latex documents, the doc packages are included automatically,
      -- but you can add more packages here. Useful for markdown documents.
      packages = { "amsmath", "amssymb", "amsfonts", "amscd", "mathtools" },
      tpl = [[
        \documentclass[preview,border=0pt,varwidth,12pt]{standalone}
        \usepackage{${packages}}
        \begin{document}
        ${header}
        { \${font_size} \selectfont
          \color[HTML]{${color}}
        ${content}}
        \end{document}]],
    },
  },
}

🎨 Styles

Check the styles docs for more information on how to customize these styles

snacks_image

{
  relative = "cursor",
  border = "rounded",
  focusable = false,
  backdrop = false,
  row = 1,
  col = 1,
  -- width/height are automatically set by the image size unless specified below
}

📚 Types

---@alias snacks.image.Size {width: number, height: number}
---@alias snacks.image.Pos {[1]: number, [2]: number}
---@alias snacks.image.Loc snacks.image.Pos|snacks.image.Size|{zindex?: number}
---@alias snacks.image.Type "image"|"math"|"chart"
---@class snacks.image.Env
---@field name string
---@field env table<string, string|true>
---@field supported? boolean default: false
---@field placeholders? boolean default: false
---@field setup? fun(): boolean?
---@field transform? fun(data: string): string
---@field detected? boolean
---@field remote? boolean this is a remote client, so full transfer of the image data is required
---@class snacks.image.Opts
---@field pos? snacks.image.Pos (row, col) (1,0)-indexed. defaults to the top-left corner
---@field range? Range4
---@field conceal? boolean
---@field inline? boolean render the image inline in the buffer
---@field width? number
---@field min_width? number
---@field max_width? number
---@field height? number
---@field min_height? number
---@field max_height? number
---@field on_update? fun(placement: snacks.image.Placement)
---@field on_update_pre? fun(placement: snacks.image.Placement)
---@field type? snacks.image.Type
---@field auto_resize? boolean

📦 Module

---@class snacks.image
---@field terminal snacks.image.terminal
---@field image snacks.Image
---@field placement snacks.image.Placement
---@field util snacks.image.util
---@field buf snacks.image.buf
---@field doc snacks.image.doc
---@field convert snacks.image.convert
---@field inline snacks.image.inline
Snacks.image = {}

Snacks.image.hover()

Show the image at the cursor in a floating window

Snacks.image.hover()

Snacks.image.langs()

---@return string[]
Snacks.image.langs()

Snacks.image.supports()

Check if the file format is supported and the terminal supports the kitty graphics protocol

---@param file string
Snacks.image.supports(file)

Snacks.image.supports_file()

Check if the file format is supported

---@param file string
Snacks.image.supports_file(file)

Snacks.image.supports_terminal()

Check if the terminal supports the kitty graphics protocol

Snacks.image.supports_terminal()