Skip to content

PsychoLlama/alternaut.nvim

Repository files navigation

alternaut.nvim

Jump between related files

Overview

Alternaut jumps between sources files and "alternate" files, such as tests, styles, headers, templates, or any co-located file with a predictable naming convention.

Note

This plugin used to be written in Vimscript. Since v0.6.0 the VimL implementation is deprecated and will be removed in a future release.

Example

Say you're working in a python project with pytest. Your structure looks like this:

project/
  __init__.py
  fibonacci.py
  tests/
    __init__.py
    test_fibonacci.py

Tests are usually prefixed test_ and placed in a tests/ directory. They could also live in the same directory.

Tell Alternaut about these naming conventions by defining a provider:

require('alternaut').setup({
  modes = {
    test = {
      -- naming conventions for Pytest
      pytest = {
        patterns = { 'test_{name}.{ext}' },
        directories = { 'tests', '.' },
        extensions = { '.py' },
      },
    },
  },
})

When you're editing project/fibonacci.py and you run alternaut.toggle('test'), alternaut will look for these paths:

  • project/tests/test_fibonacci.py
  • project/test_fibonacci.py

It opens the test file. Toggle again and you're back in fibonacci.py.

That's the gist of it. See :help alternaut for details and specific examples.

Non-Goals

Alternaut focuses on co-located files. If your conventions put files in wildly different parts of the file system, this plugin won't help you. An example is a project that puts all tests in a $REPO/test/ directory and all sources under $REPO/src/.

Installation

lazy.nvim
{
  "PsychoLlama/alternaut.nvim",
  version = false,
  lazy = false, -- Already optimized for lazy loading
  config = function()
    require('alternaut').setup({
      -- ...
    })
  end,
}
mini.deps
add({ source = 'PsychoLlama/alternaut.nvim' })
vim-plug
Plug 'PsychoLlama/alternaut.nvim'
home-manager

Alternaut is available as a flake:

# flake.nix
{
  inputs.alternaut-nvim.url = "github:PsychoLlama/alternaut.nvim";
}
# home-configuration.nix
programs.neovim = {
  plugins = [
    {
      plugin = flake-inputs.alternaut-nvim.packages.${pkgs.system}.default;
      type = "lua";
      config = ''
        require('alternaut').setup({
          -- ...
        })
      '';
    }
  ];
};

Keybindings

No keybindings are included by default. Personally I like Alt-number keys but this is up to you.

-- Alt-0 to toggle between tests
vim.keymap.set('n', '<A-0>', function()
  require('alternaut').toggle('test')
end)

-- Alt-9 to toggle between styles
vim.keymap.set('n', '<A-9>', function()
  require('alternaut').toggle('style')
end)

The way of our people is help files.

:help alternaut

Recipes

These are some common configurations:

require('alternaut').setup({
  modes = {
    test = {
      vitest = {
        patterns = { '{name}.test.{ext}' },
        directories = { '__tests__' },
        extensions = { 'ts', 'tsx', 'js', 'jsx' },
      },

      pytest = {
        patterns = { 'test_{name}.{ext}', '{name}_test.{ext}' },
        directories = { 'tests', '.' },
        extensions = { 'py' },
      },

      rust = {
        patterns = { '{name}_test.{ext}', '{name}.{ext}' },
        directories = { 'tests', '.' },
        extensions = { 'rs' },
      },

      go = {
        patterns = { '{name}_test.{ext}' },
        directories = { '.' },
        extensions = { 'go' },
      },

      busted = {
        patterns = { '{name}_spec.{ext}' },
        directories = { '.', 'spec' },
        extensions = { 'lua' },
      },

      vader = {
        patterns = { '{name}.{ext}' },
        directories = { 'tests', '.' },
        extensions = {
          target = { 'vader' },
          origin = { 'vim' },
        },
      },
    },

    style = {
      css = {
        patterns = { '{name}.{ext}' },
        extensions = {
          target = { 'css', 'less', 'scss' },
          origin = { 'tsx', 'jsx', 'ts', 'js', 'html' },
        },
      },

      vanilla_extract = {
        patterns = { '{name}.css.{ext}' },
        extensions = {
          target = { 'ts', },
          origin = { 'tsx', 'ts' },
        },
      },
    },

    template = {
      vue = {
        patterns = { '{name}.vue' },
        extensions = {
          target = { 'vue' },
          origin = { 'ts', 'js' },
        },
      },

      svelte = {
        patterns = { '{name}.svelte' },
        extensions = {
          target = { 'svelte' },
          origin = { 'ts', 'js' },
        },
      },

      html = {
        patterns = { '{name}.html' },
        extensions = {
          target = { 'html' },
          origin = { 'ts', 'js' },
        },
      },
    },

    header = {
      c = {
        patterns = { '{name}.{ext}' },
        extensions = {
          target = { 'h', 'hpp', 'hh' },
          origin = { 'c', 'cpp', 'cc', 'm', 'mm' },
        },
      },
    },
  },
})

Pull requests are welcome for more examples.