/shiki.nvim

Generate syntax-highlighted HTML code snippets straight from Neovim

Primary LanguageLuaMIT LicenseMIT

shiki.nvim

Use :Shiki to effortlessly get a syntax-highlighted HTML code snippet of a selected text or a provided range.

Powered by Shiki.

Important

The HTML snippet requires an additional CSS code to work.

Demo

demo.webm

Requirements

  • node

Setup

shiki.nvim has a default plugin spec (see lazy.lua). It lazy loads by default!

---@module "freeze"
---@type LazySpec
{
  "TymekDev/shiki.nvim"
}

Tip

Annotations above are optional. Use lazydev.nvim to get completions based on them.

Usage

Shiki Command

  • :Shiki command works either on a selection or on a range
  • :Shiki has a single optional argument—a language to highlight
    • For example, run :Shiki css inside an HTML file to get CSS properly highlighted
    • If the language argument is not specified, then filetype is passed to Shiki1
  • Use :%Shiki to generate a snippet from an entire file
  • Use :Shiki to generate a snippet from the current line
  • Use :Shiki with an active selection to generate a snippet from the selection

Lua

-- List supported languages
require("shiki").langs()

-- List supported themes
require("shiki").themes()

-- Rebuild Node a shiki.nvim's internal directory
require("shiki").setup({ install = { rebuild = true } })

-- Execute JS code in the shiki.nvim's internal directory
requie("shiki.node").exec('import { bundledThemes } from "shiki/themes"; console.log(bundledThemes)')

Configuration

---@type shiki.Config
{
  -- Create Shiki command?
  cmd = true,
  highlight = {
    -- Shiki configuration (passed to `codeToHTML`)
    shiki = {
      defaultColor = false,
      themes = {
        dark = "github-dark",
        light = "github-light",
      },
    },
  },
  install = {
    -- Node package manager to install with
    cmd = "npm",
    -- Addtional arguments to the package manager
    args = { "install", "--save-dev" },
    -- Shiki version
    version = "1.12.0",
    -- Remove and reinitialize a shiki.nvim's internal directory?
    rebuild = false,
  },
}

Important

If you want to change Shiki version, then run setup() with rebuild = true once or run require("shiki.node").purge().

Motivation

Recently, I have switched to writing blog posts directly in HTML (see A New Post Layout). I wanted to keep code snippets with syntax highlighting, though. That's how I came up with a script to create syntax-highlighted code snippets using Shiki:

// Usage:
//    node highlight.js FILE [LANG] | pbcopy
import { readFileSync } from "node:fs";
import { codeToHtml } from "shiki";

const fileName = process.argv[2];
const lang = process.argv[3] ?? "text";
const code = readFileSync(fileName, { encoding: "utf-8" }).replace(/\n$/, "");

const result = await codeToHtml(code, {
  lang: lang,
  themes: {
    light: "github-light",
    dark: "github-dark",
  },
  defaultColor: false,
});

console.log(result);

You can read more about it in my HTML Code Snippets with Syntax Highlighting post.

This script is not ideal. It requires the code to be in a file and it does not detect a language. I realized that for the most part, the code I want to share lives in my editor.

Why should it be any more effort than selecting the relevant part and running a single command?—I asked myself.

...and that's how shiki.nvim came to be.

Footnotes

  1. This won't always work. There might be filetypes that don't translate to Shiki's lang argument. If you find one, then please raise an issue.