Skip to content

dfdezmonteiro/tree-zip.nvim

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

tree-zip.nvim

tree-zip.nvim is a small Neovim plugin that adds zip and unzip actions to file explorers such as neo-tree.nvim and oil.nvim.

It lets you compress files and directories from your file explorer, and extract .zip files directly from Neovim.

Features

  • Compress one file or directory from Neo-tree or Oil.
  • Compress multiple selected files/directories from Neo-tree visual selection.
  • Compress multiple selected files/directories from Oil visual selection.
  • Extract .zip files from Neo-tree or Oil.
  • Extract one selected .zip file from Neo-tree or Oil visual selection.
  • Prompt for zip output name or path.
  • Prompt for extraction destination folder name or path.
  • Automatically appends .zip when compressing.
  • Supports relative and absolute paths.
  • Asks before replacing existing zip files or extraction folders.
  • Shows notifications when operations start and finish.
  • Automatically registers Oil keymaps from setup().
  • Automatically refreshes Oil after successful zip/unzip operations.
  • Uses native tools:
    • Windows: Compress-Archive / Expand-Archive
    • Linux/macOS: zip / unzip

Requirements

Platform requirements:

Platform Status Required command
Windows Supported PowerShell tools
macOS Supported zip / unzip
Linux Unverified zip / unzip
  • Currently tested on Windows and macOS.
  • Support for Linux is not fully verified.
  • Linux/macOS require zip and unzip to be installed.

Installation

lazy.nvim

{
  "dfdezmonteiro/tree-zip.nvim",
  lazy = false,
  config = function()
    require("tree-zip").setup()
  end,
}

With custom options:

{
  "dfdezmonteiro/tree-zip.nvim",
  lazy = false,
  config = function()
    require("tree-zip").setup({
      overwrite = true,
      notify = true,

      integrations = {
        oil = true,
        refresh_oil = true,
      },

      keymaps = {
        zip = "<leader>Z",
        extract = "<leader>X",
      },
    })
  end,
}

Configuration

Default configuration:

require("tree-zip").setup({
  overwrite = true,
  notify = true,

  integrations = {
    oil = true,
    refresh_oil = true,
  },

  keymaps = {
    zip = "<leader>Z",
    extract = "<leader>X",
  },
})

Options:

Option Type Default Description
overwrite boolean true Allows underlying zip/unzip commands to overwrite existing content after confirmation.
notify boolean true Enables Neovim notifications.
integrations.oil boolean true Automatically registers Oil buffer-local keymaps.
integrations.refresh_oil boolean true Refreshes the active Oil view after successful zip/unzip operations.
keymaps.zip string <leader>Z Keymap used to compress files/directories in Oil.
keymaps.extract string <leader>X Keymap used to extract .zip files in Oil.

To disable automatic Oil keymaps:

require("tree-zip").setup({
  integrations = {
    oil = false,
  },
})

To disable automatic Oil refresh:

require("tree-zip").setup({
  integrations = {
    refresh_oil = false,
  },
})

Neo-tree integration

Neo-tree integration is configured manually because Neo-tree passes its internal state and visual selected_nodes through its own command system.

Add the custom commands and mappings to your Neo-tree configuration.

Example:

return {
  "nvim-neo-tree/neo-tree.nvim",
  opts = function(_, opts)
    opts.filesystem = opts.filesystem or {}
    opts.filesystem.commands = opts.filesystem.commands or {}
    opts.filesystem.window = opts.filesystem.window or {}
    opts.filesystem.window.mappings = opts.filesystem.window.mappings or {}

    opts.filesystem.commands.zip_selected = function(state, selected_nodes)
      if selected_nodes and #selected_nodes > 0 then
        require("tree-zip").neo_tree_zip_visual(state, selected_nodes)
      else
        require("tree-zip").neo_tree_zip(state)
      end
    end

    opts.filesystem.commands.extract_selected = function(state, selected_nodes)
      if selected_nodes and #selected_nodes > 0 then
        require("tree-zip").neo_tree_extract_visual(state, selected_nodes)
      else
        require("tree-zip").neo_tree_extract(state)
      end
    end

    opts.filesystem.window.mappings["<leader>Z"] = "zip_selected"
    opts.filesystem.window.mappings["<leader>X"] = "extract_selected"

    return opts
  end,
}

Mappings in Neo-tree, if configured as above:

<leader>Z   zip file/directory under cursor or visual selection
<leader>X   extract selected .zip file

Neo-tree visual selection supports compressing multiple files/directories.

Neo-tree visual extraction currently supports one .zip file at a time.

Oil integration

Oil keymaps are registered automatically by setup().

Default mappings:

<leader>Z   zip file/directory under cursor or visual selection
<leader>X   extract selected .zip file

Normal mode:

<leader>Z   zip file/directory under cursor
<leader>X   extract .zip file under cursor

Visual mode:

<leader>Z   zip selected files/directories
<leader>X   extract selected .zip file

Oil visual selection supports compressing multiple selected files/directories.

Oil visual extraction currently supports one .zip file at a time.

Oil buffers are refreshed automatically after successful zip/unzip operations when integrations.refresh_oil is enabled.

Custom Oil keymaps

Change the keymaps through setup():

require("tree-zip").setup({
  keymaps = {
    zip = "<leader>Z",
    extract = "<leader>X",
  },
})

Manual Oil configuration

If you prefer to manage Oil keymaps yourself, disable the automatic integration:

require("tree-zip").setup({
  integrations = {
    oil = false,
  },
})

Then configure Oil manually:

require("oil").setup({
  keymaps = {
    ["<leader>Z"] = {
      desc = "Zip selected file/directory",
      callback = function()
        require("tree-zip").oil_zip()
      end,
    },

    ["<leader>X"] = {
      desc = "Extract selected .zip",
      callback = function()
        require("tree-zip").oil_extract()
      end,
    },
  },
})

For visual mode, use buffer-local mappings:

vim.api.nvim_create_autocmd("FileType", {
  pattern = "oil",
  callback = function(event)
    vim.keymap.set("x", "<leader>Z", function()
      require("tree-zip").oil_zip_visual()
    end, {
      buffer = event.buf,
      desc = "Zip Oil visual selection",
    })

    vim.keymap.set("x", "<leader>X", function()
      require("tree-zip").oil_extract_visual()
    end, {
      buffer = event.buf,
      desc = "Extract Oil visual selection",
    })
  end,
})

Usage

Compress one file or directory

In Neo-tree or Oil, place the cursor over a file or directory and press:

<leader>Z

You will be prompted:

Zip name or path:

Examples:

backup

creates:

backup.zip
backup.zip

creates:

backup.zip
dist/backup

creates:

dist/backup.zip
C:\Users\david\Desktop\backup

creates:

C:\Users\david\Desktop\backup.zip

The .zip extension is added automatically if omitted.

Compress multiple files/directories from Neo-tree

In Neo-tree:

Shift+V
j/k to expand the visual selection
<leader>Z

Then enter the zip name or path.

All selected files/directories are compressed into one .zip.

Compress multiple files/directories from Oil

In Oil:

V
j/k to expand the visual selection
<leader>Z

Then enter the zip name or path.

All selected files/directories are compressed into one .zip.

The selected Oil entries are compressed relative to the current Oil directory, so the archive does not include unnecessary parent folders.

Extract a zip file

In Neo-tree or Oil, place the cursor over a .zip file and press:

<leader>X

You will be prompted:

Destination folder name or path:

If you leave it empty, the plugin extracts into a folder with the same name as the zip file.

Example:

archive.zip

empty destination:

Destination folder name or path:

extracts to:

archive/

If you enter:

test

it extracts to:

test/

If you enter:

../test

it extracts relative to the zip file location.

Absolute paths are also supported.

Extract from visual selection

In Neo-tree or Oil visual selection, extraction currently supports one .zip file at a time.

If more than one .zip file is selected, the operation is cancelled.

Replace confirmation

If the target zip file already exists, the plugin asks:

Path already exists. Replace? (y/n):

If the extraction destination already exists, the plugin also asks:

Path already exists. Replace? (y/n):

Accepted answers:

y
yes

Any other answer cancels the operation.

Pressing Esc cancels the prompt.

Behavior

Compressing from Neo-tree normal mode

Neo-tree cursor entry
→ <leader>Z
→ prompt for zip name/path
→ append .zip if needed
→ create parent output directory if needed
→ ask before replacing existing zip
→ create zip

Compressing from Neo-tree visual selection

Neo-tree visual selection
→ <leader>Z
→ prompt for zip name/path
→ append .zip if needed
→ create parent output directory if needed
→ ask before replacing existing zip
→ create zip with all selected files/directories

Compressing from Oil normal mode

Oil cursor entry
→ <leader>Z
→ prompt for zip name/path
→ append .zip if needed
→ create parent output directory if needed
→ ask before replacing existing zip
→ create zip
→ refresh Oil view

Compressing from Oil visual selection

Oil visual selection
→ <leader>Z
→ resolve selected Oil buffer lines to filesystem paths
→ use current Oil directory as archive root
→ prompt for zip name/path
→ append .zip if needed
→ create parent output directory if needed
→ ask before replacing existing zip
→ create zip with all selected files/directories
→ refresh Oil view

Extracting from Neo-tree normal mode

Neo-tree .zip cursor entry
→ <leader>X
→ prompt for destination folder/path
→ empty input uses default folder name
→ ask before extracting into existing folder
→ extract zip

Extracting from Neo-tree visual selection

Neo-tree visual selection
→ <leader>X
→ require one selected .zip file
→ prompt for destination folder/path
→ empty input uses default folder name
→ ask before extracting into existing folder
→ extract zip

Extracting from Oil normal mode

Oil .zip cursor entry
→ <leader>X
→ prompt for destination folder/path
→ empty input uses default folder name
→ ask before extracting into existing folder
→ extract zip
→ refresh Oil view

Extracting from Oil visual selection

Oil visual selection
→ <leader>X
→ require one selected .zip file
→ prompt for destination folder/path
→ empty input uses default folder name
→ ask before extracting into existing folder
→ extract zip
→ refresh Oil view

Lua API

Generic API:

require("tree-zip").zip_paths(paths, opts)
require("tree-zip").extract_zip(zip_path)

zip_paths() accepts a list of filesystem paths:

require("tree-zip").zip_paths({
  "/path/to/file.txt",
  "/path/to/directory",
})

It also accepts an optional base_dir used as the archive root:

require("tree-zip").zip_paths({
  "/project/src/a.lua",
  "/project/src/b.lua",
}, {
  base_dir = "/project/src",
})

With base_dir, the archive stores:

a.lua
b.lua

instead of:

project/src/a.lua
project/src/b.lua

Neo-tree helpers:

require("tree-zip").neo_tree_zip(state)
require("tree-zip").neo_tree_zip_visual(state, selected_nodes)

require("tree-zip").neo_tree_extract(state)
require("tree-zip").neo_tree_extract_visual(state, selected_nodes)

Oil helpers:

require("tree-zip").oil_zip()
require("tree-zip").oil_zip_visual()

require("tree-zip").oil_extract()
require("tree-zip").oil_extract_visual()

Oil keymap registration:

require("tree-zip").register_oil_keymaps()

Project structure

tree-zip.nvim/
├── README.md
├── LICENSE
├── stylua.toml
└── lua/
    └── tree-zip/
        └── init.lua

Limitations

  • This plugin is currently focused on .zip files only.
  • Neo-tree integration requires manual command/mapping registration.
  • Oil keymaps are registered automatically by setup() unless disabled.
  • Neo-tree visual selection supports compressing multiple files/directories.
  • Oil visual selection supports compressing multiple files/directories.
  • Visual extraction supports one .zip file at a time.
  • Linux/macOS require zip and unzip to be installed.
  • Windows behavior depends on PowerShell archive commands.
  • Linux/macOS support is not fully verified.

Roadmap

Possible future improvements:

  • support for .tar, .tar.gz, .7z
  • optional Neo-tree auto-registration
  • progress indicator for long-running operations
  • better error reporting from stderr
  • support extracting multiple zip files
  • support choosing destination through vim.ui.select
  • healthcheck support

Contributing

Contributions are welcome.

License

MIT

About

Neovim plugin to zip and unzip files directly from Neo-tree and Oil

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages