triptych.nvim icon indicating copy to clipboard operation
triptych.nvim copied to clipboard

Directory browser plugin for Neovim, inspired by Ranger

Triptych.nvim

Directory browser for Neovim, inspired by Ranger

Triptych screenshot

CI

The UI consists of 3 floating windows. In the center is the currently focused directory. On the left is the parent directory. The right window contains either a child directory, or a file preview.

With default bindings use j and k (or any other motions like G, gg, / etc) to navigate within the current directory. Use h and l to switch to the parent or child directories respectively. If the buffer on the right is a file, then pressing l will close Triptych and open that file in the buffer you were just in. You only ever control or focus the middle window.

✨ Features

  • Rapid, intuitive directory browsing
  • File preview
  • Devicons support
  • Git signs
  • Diagnostic signs
  • Perform common actions on the filesystem
    • Rename
    • Delete (including bulk)
    • Copy 'n' paste (including bulk) [^1]
    • Cut 'n' paste (including bulk) [^1]
  • Extensible

[^1]: These are not currently working on the Windows operating system

⚡️ Requirements

📦 Installation

Example using Lazy.

{
  'simonmclean/triptych.nvim',
  event = 'VeryLazy',
  dependencies = {
    'nvim-lua/plenary.nvim', -- required
    'nvim-tree/nvim-web-devicons', -- optional
  }
}

Then call the setup function somewhere in your Neovim config to initialise it with the default options.

require 'triptych'.setup()

Launch using the :Triptych command, which will toggle Triptych open/closed. You may want to create a binding for this.

vim.keymap.set('n', '<leader>-', ':Triptych<CR>', { silent = true })

⚙️ Configuration

Below is the default configuration. Feel free to override any of these.

Key mappings can either be a string, or a table of strings if you want multiple bindings.

require 'triptych'.setup {
  mappings = {
    -- Everything below is buffer-local, meaning it will only apply to Triptych windows
    show_help = 'g?',
    jump_to_cwd = '.',  -- Pressing again will toggle back
    nav_left = 'h',
    nav_right = { 'l', '<CR>' }, -- If target is a file, opens the file in-place
    open_hsplit = { '-' },
    open_vsplit = { '|' },
    open_tab = { '<C-t>' },
    cd = '<leader>cd',
    delete = 'd',
    add = 'a',
    copy = 'c',
    rename = 'r',
    cut = 'x',
    paste = 'p',
    quit = 'q',
    toggle_hidden = '<leader>.',
  },
  extension_mappings = {},
  options = {
    dirs_first = true,
    show_hidden = false,
    line_numbers = {
      enabled = true,
      relative = false,
    },
    file_icons = {
      enabled = true,
      directory_icon = '',
      fallback_file_icon = ''
    },
    responsive_column_widths = {
      -- Keys are breakpoints, values are column widths
      -- A breakpoint means "when vim.o.columns >= x, use these column widths"
      -- Columns widths must add up to 1 after rounding to 2 decimal places
      -- Parent or child windows can be hidden by setting a width of 0
      ['0'] = { 0, 0.5, 0.5 },
      ['120'] = { 0.2, 0.3, 0.5 },
      ['200'] = { 0.25, 0.25, 0.5 },
    },
    highlights = { -- Highlight groups to use. See `:highlight` or `:h highlight`
      file_names = 'NONE',
      directory_names = 'NONE',
    },
    syntax_highlighting = { -- Applies to file previews
      enabled = true,
      debounce_ms = 100,
    },
    backdrop = 60 -- Backdrop opacity. 0 is fully opaque, 100 is fully transparent (disables the feature)
    border = 'single' -- See :h nvim_open_win for border options
  },
  git_signs = {
    enabled = true,
    signs = {
      -- The value can be either a string or a table.
      -- If a string, will be basic text. If a table, will be passed as the {dict} argument to vim.fn.sign_define
      -- If you want to add color, you can specify a highlight group in the table.
      add = '+',
      modify = '~',
      rename = 'r',
      untracked = '?',
    },
  },
  diagnostic_signs = {
    enabled = true,
  }
}

Extending functionality

The extension_mappings property allows you add any arbitrary functionality based on the current cursor target. You simply provide a key mapping, a vim mode, and a function. When the mapped keys are pressed, the function is invoked and is passed two arguments: A table describing the current cursor "target", and a function which refreshes the view. The target table looks as follows:

{
  dirname, -- e.g. /User/Name/foo
  display_name -- e.g. 'bar.js'
  filetype, -- e.g. 'javascript'
  is_dir, -- boolean indicating whether this is a directory
  path, -- e.g. /User/Name/foo/bar.js
}

Examples

Telescope integration

If you want to make <c-f> search the file or directory under the cursor using Telescope try something like:

{
  extension_mappings = {
    ['<c-f>'] = {
      mode = 'n',
      fn = function(target, _)
        require 'telescope.builtin'.live_grep {
          search_dirs = { target.path }
        }
      end
    }
  }
}