/blink.indent

Performant indent guides for neovim

Primary LanguageLuaMIT LicenseMIT

Blink Indent (blink.indent)

blink.indent provides indent guides with scope on every keystroke (0.1-2ms per render), including on massive files, in ~500 LoC. These indent guides work in the vast majority of valid code and compute quicker (~10x) than via Treesitter. If you want something more feature rich, consider using indent-blankline instead.

Screenshot

code from frizbee

Install

-- lazy.nvim
{
  'saghen/blink.indent',
  --- @module 'blink.indent'
  --- @type blink.indent.Config
  -- opts = {},
}

-- vim.pack
vim.pack.add({ 'saghen/blink.indent' })

Options

Note that calling setup() is optional, as the plugin will automatically initialize with the default configuration.

Disable with vim.g.indent_guide = false (global) or vim.b[bufnr].indent_guide = false (per-buffer). Some filetypes and buftypes are disabled by default, see below. You may also create a keymap to toggle visibility like so:

local indent = require('blink.indent')
vim.keymap.set('n', 'some-key', function() indent.enable(not indent.is_enabled()) end, { desc = 'Toggle indent guides' })

or toggle on a per-buffer basis with indent.enable(not indent.is_enabled({ bufnr = 0 }), { bufnr = 0 }).

require('blink.indent').setup({
  blocked = {
    -- default: 'terminal', 'quickfix', 'nofile', 'prompt'
    buftypes = { include_defaults = true },
    -- default: 'lspinfo', 'packer', 'checkhealth', 'help', 'man', 'gitcommit', 'dashboard', ''
    filetypes = { include_defaults = true },
  },
  static = {
    enabled = true,
    char = '',
    priority = 1,
    -- specify multiple highlights here for rainbow-style indent guides
    -- highlights = { 'BlinkIndentRed', 'BlinkIndentOrange', 'BlinkIndentYellow', 'BlinkIndentGreen', 'BlinkIndentViolet', 'BlinkIndentCyan' },
    highlights = { 'BlinkIndent' },
  },
  scope = {
    enabled = true,
    char = '',
    priority = 1000,
    -- set this to a single highlight, such as 'BlinkIndent' to disable rainbow-style indent guides
    -- highlights = { 'BlinkIndentScope' },
    -- optionally add: 'BlinkIndentRed', 'BlinkIndentCyan', 'BlinkIndentYellow', 'BlinkIndentGreen'
    highlights = { 'BlinkIndentOrange', 'BlinkIndentViolet', 'BlinkIndentBlue' },
    -- enable to show underlines on the line above the current scope
    underline = {
      enabled = false,
      -- optionally add: 'BlinkIndentRedUnderline', 'BlinkIndentCyanUnderline', 'BlinkIndentYellowUnderline', 'BlinkIndentGreenUnderline'
      highlights = { 'BlinkIndentOrangeUnderline', 'BlinkIndentVioletUnderline', 'BlinkIndentBlueUnderline' },
    },
  },
})

Performance

To compare the performance to indent-blankline, I monkey patched the draw/refresh code of both projects, enabling each separately to compare. On my machine, blink.indent took ~0.2ms per render while indent-blankline took ~2-5ms.

local refresh = require('ibl').refresh
require('ibl').refresh = function(...)
  local start_time = vim.loop.hrtime()
  refresh(...)
  local end_time = vim.loop.hrtime()
  print(string.format('indent-blankline.nvim: %.2fms', (end_time - start_time) / 1e6))
end

local draw = require('blink.indent').draw
require('blink.indent').draw = function(...)
  local start_time = vim.loop.hrtime()
  draw(...)
  local end_time = vim.loop.hrtime()
  print(string.format('blink.indent: %.2fms', (end_time - start_time) / 1e6))
end