Git Product home page Git Product logo

triptych.nvim's Introduction

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

⚡️ 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
    }
  }
}

Footnotes

  1. These are not currently working on the Windows operating system 2

triptych.nvim's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

triptych.nvim's Issues

Add the ability to toggle

Describe the problem you're having
I would love to use the same keymap to open / close the modal

Proposed solution(s)
change :Triptych behaviour from open to toggle

Oil/mini.file like file rename/mv

I really like the ranger like way of explorer the fs and extention_mapping

One thing I missing is the file rename in bulk like oil or mini.file.

If it's possible to add those functionality?

Different color for folders

Hi, great addon. I was wondering if you could implement different color for folders names, ranger for reference:
image

Also, I was thinking maybe instead of 3 equal columns, triptych could use some kind of golden rule ratio - where last column, with buffer preview, is widest.

Here is triptych for comparison :
image

its bit hard to differentiate folder at first glance (I disabled icons). j

And last issue - triptych is bit slow when jumping through files with j,k keys. maybe instead of loading whole buffer for preview, only first 40lines could speed it up. Or, if lag is caused by loading treesitter highlights, when user spams j,k keys, then syntax highlight could be debounced .

Line numbers for file preview

First of all, amazing plugin! I'm loving it.

I was wondering if there is a way to enable line numbers inside the file preview.

For example, I have this auto command for telescope:

-- Show line numbers in the preview
vim.api.nvim_create_autocmd('User', {
  pattern = 'TelescopePreviewerLoaded',
  group = augroup,
  callback = function()
    vim.opt_local.number = true
  end
})

But I'm not sure what the pattern would be in this case.
Thanks in advance!

Reload window on cwd change?

Describe the problem you're having
Currently, i'm using an extension mapping to trigger a cd into the dir i'm hovering over. This works great, but I have to close and reopen the triptych window to show the updated <cwd> at the top of the window. Is there a way to trigger a refresh of the triptych buffer that i'm missing?

Additional context

        extension_mappings = {
          ['<c-r>'] = {
            mode = 'n',
            fn = function(target)
              vim.cmd('cd ' .. target.dirname)
            end,
          },
        },

Add git signs to neovim highlight groups for coloring

Describe the problem you're having
As title says.

Proposed solution(s)
I'm currently looking into the actual code of the plugin to potentially handle it myself, but my first impression is that this should be placed in either syntax_highlighting.lua or view.lua.

Additional context
N/A.

idea: renaming files with LSP support

Describe the problem you're having
Hi! I don't actually use this plugin but I think it looks great. Wanted to provide an idea that I implemented as an experiment in another project that's kinda similar.

The idea is: when a file is renamed, neovim can notify running LSP servers and they can help the user by providing updated references to the renamed file. I found this not too difficult to do, and at least for simple cases it's working great.

Proposed solution(s)
[Optional] Do you have any ideas for how the feature could be implemented?

I drew a fancy diagram that explains the sequence of things taking place here https://github.com/mikavilpas/yazi.nvim/blob/master/dev-documentation/lsp-renaming.md

I have also copied it here to keep it simpler:

sequenceDiagram

participant lsp
participant neovim
participant yazi

neovim->>yazi: open yazi inside neovim
yazi->>yazi: rename files and close
yazi->>neovim: provide rename events
neovim->>lsp: send rename request (willRenameFiles)
lsp->>neovim: changes to related files
neovim->>neovim: apply changes to related files
neovim->>lsp: send 'renaming finished' notification (didRenameFiles)
neovim->>neovim: user saves changes
Loading

My hope is that this idea can be reproduced in this project in some way, and that way it can benefit more people in the neovim plugin ecosystem 👍🏻

Error when trying to delete file/folder

Bug description
Delete a file/folder in triptych window give the following error, regardless the file being open or not:

Error executing vim.schedule lua callback: ...cal/share/nvim/lazy/triptych.nvim/lua/triptych/float.lua:67: Invalid window id: 1002
stack traceback:
        [C]: in function 'nvim_win_call'
        ...cal/share/nvim/lazy/triptych.nvim/lua/triptych/float.lua:67: in function 'win_set_title'
        ...ocal/share/nvim/lazy/triptych.nvim/lua/triptych/view.lua:264: in function 'set_primary_and_parent_window_targets'
        ...ocal/share/nvim/lazy/triptych.nvim/lua/triptych/view.lua:467: in function 'refresh_view'
        ...ocal/share/nvim/lazy/triptych.nvim/lua/triptych/init.lua:105: in function 'refresh_view'
        ...l/share/nvim/lazy/triptych.nvim/lua/triptych/actions.lua:32: in function ''
        vim/_editor.lua: in function <vim/_editor.lua:0>

Steps to reproduce

  • Open triptych
  • Delete a file or folder by pressing d

Setup

  • Operating system: Ubuntu 24.04
  • Nvim version: 0.10.0
  • Triptych config
return {
	"simonmclean/triptych.nvim",
	dependencies = {
		"nvim-lua/plenary.nvim",
		"nvim-tree/nvim-web-devicons",
	},
	config = function()
		require("triptych").setup({
			mappings = {
				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 = {
				["<C-f>"] = {
					mode = "n",
					fn = function(target, _)
						require("telescope.builtin").live_grep({ search_dirs = { target.path } })
					end,
				},
			},
		})

		vim.keymap.set("n", "<leader>t", "<cmd>Triptych<CR>", { desc = "Toggle Triptych", silent = true })
	end,
}

Opening and moving inside new windows from inside triptych still moves triptych cursor

Bug description
When opening a window inside triptych, the cursor position from within the window is still used to navigate inside triptych, which is evidenced by the file preview changing. You would expect that the triptych window movements would only register when the cursor is inside the triptych window.

I first became aware of this issue when trying to override the vim.ui.select() method with a nui menu, rather than the text-based input I found before. That minimal init is also included below.

I would propose to make the tritych cursor only move when the neovim cursor is inside the buffer, just as an added layer of protection as well.

Steps to reproduce
Here is the minimal lazy config of the nui menu:

return {
    "MunifTanjim/nui.nvim",
    config = function()
        local Menu = require("nui.menu")

        vim.ui.select = function(items, opts, on_choice)
            vim.validate({
                items = { items, 'table', false },
                opts = { opts, 'table', true },
                on_choice = { on_choice, 'function', false },
            })
            opts = opts or {}
            local format_item = opts.format_item or tostring

            Menu({
                relative = "cursor",
                position = {
                    row = 2,
                    col = 0,
                },
                size = {
                    width = 40,
                },
                zindex = 1000,
                border = {
                    style = "rounded",
                    text = {
                        top = opts.prompt or "Select an item",
                        top_align = "center",
                    },
                },
            }, {
                lines = (function()
                    ---@type NuiTree.Node[]
                    local selections = {}

                    for _, item in ipairs(items) do
                        if type(item) == "string" then
                            table.insert(selections, Menu.item(item))
                        elseif type(item) == "table" then
                            table.insert(selections, Menu.item(format_item(item), item))
                        end
                    end

                    return selections
                end)(),

                on_close = function()
                    print("Closed")
                end,
                on_submit = function(selected)
                    on_choice(selected)
                end,
            }):mount()
        end

        vim.keymap.set("n", "<leader><leader>", function()
            vim.ui.select({ 'One', 'Two', 'Three' }, {}, function(selected)
                print("Selected: " .. selected)
            end)
        end)
    end,
}

By opening Triptych with this config added, the delete action's dialog is overridden, and that method is the easiest way to reproduce the bug because of the yes/no delete menu.

Setup

  • macOS Sonoma 14.4.1
  • Nvim version: 0.9.5 (release)
return {
    "simonmclean/triptych.nvim",
    event = "VeryLazy",
    dependencies = {
        "nvim-lua/plenary.nvim",
        "nvim-tree/nvim-web-devicons",
        "mhinz/vim-signify",
    },
    config = function()
        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)
            },
            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 = { text = "+", texthl = "SignifySignAdd" },
                    modify = { text = "~", texthl = "SignifySignChange" },
                    rename = { text = "r", texthl = "SignifySignChange" },
                    untracked = { text = "?", texthl = "SignifySignDelete" },
                },
            },
            diagnostic_signs = {
                enabled = true,
            }
        })

        vim.keymap.set("n", "<leader>pv", vim.cmd.Triptych, { silent = true })
    end,
}

Switch from manual buffer reading and highlighting to netrw preview

Describe the problem you're having
I've noticed that sometimes, triptych can lag significantly when previewing a large file or nested directory, to the point of requiring me to restart my terminal. It happens somewhat sporadically, but often enough that I remember what's causing it. I've looked at netrw, because it also has a preview feature which applies syntax highlighting, and I noticed that it doesn't cause any lag when I preview a file.

Proposed solution(s)
I was thinking that the backend for triptych's previewer could become netrw, rather than manually reading and applying syntax highlighting, with the ui being a float with netrw's contents. This would also be more accurate, as netrw's previewer also applies syntax highlighting by the LSP, and not just treesitter. However, I recognize that this would be a rather large refactor, and I'm not familiar with netrw and any possible API to make use of it.

Additional context
To see previews in netrw, you simply type "p" on the file you want to preview. Note that it will get mad at you if you try to preview a directory, so that functionality could probably remain handled by triptych.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.