Skip to content

OriginCoderPulse/synapse.nvim

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Synapse.nvim

A modern, lightweight plugin manager for Neovim with a beautiful UI and intelligent dependency management.

đź“– Full Documentation: See :help synapse or doc/synapse.txt for complete documentation.

Features

  • 📦 Configuration-based Management: Manage plugins through simple Lua configuration files
  • đź”— Automatic Dependency Resolution: Automatically install, update, and protect plugin dependencies
  • 🌿 Branch & Tag Support: Clone specific branches or lock to tag versions
  • 🎨 Beautiful UI: Real-time progress display with customizable ASCII art headers
  • ⚡ Smart Updates: Check for updates before applying them
  • đź§ą Auto Cleanup: Remove unused plugins automatically
  • đź”§ Post-Install Commands: Execute build commands after installation/update

Installation

1. Clone to Neovim Default Plugin Directory

Clone the repository to Neovim's default plugin directory:

# Get Neovim data directory and clone
git clone https://github.com/OriginCoderPulse/synapse.nvim \
    "$(nvim --cmd 'echo stdpath("data")' --cmd 'qa')/site/pack/packer/start/synapse.nvim"

Or manually:

# Unix/Linux/macOS
git clone https://github.com/OriginCoderPulse/synapse.nvim \
    ~/.local/share/nvim/site/pack/packer/start/synapse.nvim

# Windows
git clone https://github.com/OriginCoderPulse/synapse.nvim \
    %LOCALAPPDATA%\nvim-data\site\pack\packer\start\synapse.nvim

2. Configure in init.lua

Add the following to your init.lua:

-- Add synapse.nvim to runtimepath (if using custom location)
vim.opt.runtimepath:prepend(os.getenv("HOME") .. "/.nvim-utils/package/synapse.nvim")

-- Setup synapse.nvim
require("synapse").setup()

Note: If you cloned to Neovim's default plugin directory (~/.local/share/nvim/site/pack/packer/start/), you don't need to set runtimepath manually.

3. Commands and Keymaps

Commands:

  • :SynapseDownload - Install missing plugins
  • :SynapseUpgrade - Update all plugins
  • :SynapseRemove - Remove unused plugins
  • :SynapseError - View error messages from failed operations

Default Keymaps:

  • <leader>si - Install plugins (:SynapseDownload)
  • <leader>sr - Remove unused plugins (:SynapseRemove)
  • <leader>su - Update plugins (:SynapseUpgrade)

Configuration

4.1 Custom Plugin Installation Directory

You can specify a custom directory for plugin installation:

require("synapse").setup({
    opts = {
        package_path = os.getenv("HOME") .. "/.nvim-utils/package",
        -- ... other options
    },
})

Important: If using a custom package_path, you must also add it to runtimepath:

-- Add custom package directory to runtimepath
vim.opt.runtimepath:append(os.getenv("HOME") .. "/.nvim-utils/package/*")
vim.opt.runtimepath:append(os.getenv("HOME") .. "/.nvim-utils/package/*/after")

require("synapse").setup({
    opts = {
        package_path = os.getenv("HOME") .. "/.nvim-utils/package",
    },
})

4.2 Custom Configuration Directory

Files ending with .config.lua in the specified directory will be automatically loaded:

require("synapse").setup({
    opts = {
        -- Directory to scan for .config.lua files (recursive)
        load_config = vim.fn.stdpath("config") .. "/lua",
        
        -- Directory to scan for plugin installation configs (.lua files)
        config_path = vim.fn.stdpath("config") .. "/lua/plugins",
    },
})

Example: Create ~/.config/nvim/lua/plugins/example.config.lua:

-- Method 1: config as table (automatically calls plugin.setup(config))
return {
    repo = "username/plugin-name",
    config = {
        -- Configuration options will be passed to plugin.setup()
        option1 = "value1",
        option2 = "value2",
    },
}
    
-- Method 2: config as function (manual setup)
return {
    repo = "username/plugin-name",
    config = function()
        local status, plugin = pcall(require, "plugin-name")
        if not status then
            vim.notify("plugin-name is not found ...", vim.log.levels.ERROR, { title = "Nvim" })
            return
        end
        plugin.setup({
            -- Your configuration
        })
    end,
}

Note: When config is a table, Synapse will automatically:

  1. Extract the plugin name from the repo field (or use primary if specified)
  2. Try to require the plugin
  3. Call plugin.setup(config_table) if the plugin has a setup function

Additional Configuration Options

primary field: Specify the actual require name if it differs from the extracted name:

return {
    repo = "username/plugin-name",
    primary = "custom-plugin-name",  -- Use this as require name
    config = {
        option1 = "value1",
    },
}

initialization field: Execute a function before plugin setup. The function receives a package wrapper that allows accessing plugin submodules:

return {
    repo = "username/plugin-name",
    initialization = function(package)
        -- package is a wrapper that allows accessing plugin submodules
        -- Access submodules using: package({ "submodule", "path" })
        -- Or using method calls: package.submodule()
        -- This runs before plugin.setup() is called
    end,
    config = {
        option1 = "value1",
    },
}

4.3 Plugin Installation Configuration Format

Create .lua files in your config_path directory to define which plugins to install:

Basic Format (config_path/example.lua):

return {
    -- Repository URL (required)
    repo = "username/plugin-name",
    
    -- Dependencies (optional)
    depend = {
        -- String format (simple dependency)
        "username/dependency-plugin",
        
        -- Table format with opt configuration
        {
            "username/another-dependency",
            opt = {
                -- Configuration options for the dependency
                option1 = "value1",
                option2 = "value2",
            }
        },
        
        -- Table format with primary and opt (same level)
        {
            "username/third-dependency",
            primary = "custom-dep-name",  -- Specify require name
            opt = {
                -- Configuration options for the dependency
                option1 = "value1",
                option2 = "value2",
            }
        },
    },
    
    -- Tag version (optional, takes precedence over branch)
    tag = "v1.0.0",
    
    -- Branch (optional, only if no tag specified)
    clone_conf = {
        branch = "main",
    },
    
    -- Post-install/update commands (optional)
    execute = {
        "make",
        "cargo build --release",
    },  -- Or use a single string: execute = "make"
    
    -- Primary plugin name (optional)
    -- Use this if the require name differs from the extracted name
    primary = "custom-plugin-name",
    
    -- Plugin configuration (optional)
    -- Method 1: config as table (automatically calls plugin.setup(config))
    config = {
        option1 = "value1",
        option2 = "value2",
    },
    
    -- Method 2: config as function (manual setup)
    -- config = function()
    --     require("plugin-name").setup({})
    -- end,
    
    -- Initialization function (optional)
    -- Executed before plugin.setup() is called
    -- initialization = function(package)
    --     -- package is a wrapper for accessing plugin submodules
    -- end,
}

Examples:

-- config_path/mason.lua
return {
    repo = "williamboman/mason.nvim",
    depend = {
        {
            "williamboman/mason-lspconfig.nvim",
            opt = {
                ensure_installed = { "lua_ls", "pyright" },
                automatic_installation = true,
            }
        },
    },
}
-- config_path/lualine.lua (using table config)
return {
    repo = "nvim-lualine/lualine.nvim",
    config = {
        options = {
            theme = "auto",
            icons_enabled = true,
        },
    },
}
-- config_path/versioned.lua
return {
    repo = "username/plugin-name",
    tag = "v1.2.3",  -- Lock to specific tag version
}
-- config_path/compiled.lua
return {
    repo = "username/compiled-plugin",
    execute = {
        "make",
        "cargo build --release",
    },
}
-- config_path/custom-name.lua (using primary field)
return {
    repo = "username/plugin-name",
    primary = "custom-plugin-name",  -- Use this as require name
    config = {
        option1 = "value1",
    },
}
-- config_path/with-init.lua (using initialization function)
return {
    repo = "username/plugin-name",
    initialization = function(package)
        -- Access plugin submodules before setup
        local install = package({ "install" })
        -- Or: local install = package.install()
    end,
    config = {
        option1 = "value1",
    },
}
-- config_path/mason.lua (dependency with primary field)
return {
    repo = "williamboman/mason.nvim",
    depend = {
        {
            "williamboman/mason-lspconfig.nvim",
            primary = "mason-lspconfig",  -- Specify require name
            opt = {
                ensure_installed = { "lua_ls", "pyright" },
                automatic_installation = true,
            }
        },
    },
}

4.4 Custom Keymaps

You can customize the keymaps:

require("synapse").setup({
    keys = {
        download = "<leader>i",  -- Install plugins
        remove = "<leader>r",    -- Remove unused plugins
        upgrade = "<leader>u",   -- Update plugins
    },
})

Complete Configuration Example

-- Add synapse.nvim to runtimepath (if using custom location)
vim.opt.runtimepath:prepend(os.getenv("HOME") .. "/.nvim-utils/package/synapse.nvim")

require("synapse").setup({
    -- Git clone method: "ssh" or "https"
    method = "https",
    
    opts = {
        -- Custom plugin installation directory
        package_path = os.getenv("HOME") .. "/.nvim-utils/package",
        
        -- Directory for plugin installation configs (.lua files)
        config_path = os.getenv("HOME") .. "/.config/nvim/lua/plugins",
        
        -- Directory for plugin load configs (.config.lua files, auto-loaded)
        load_config = os.getenv("HOME") .. "/.config/nvim/lua",
        
        -- UI customization
        ui = {
            style = "float",
        },
    },
    
    -- Custom keymaps
    keys = {
        download = "<leader>i",
        remove = "<leader>r",
        upgrade = "<leader>u",
    },
})

Note: If using custom package_path, don't forget to add it to runtimepath:

vim.opt.runtimepath:append(os.getenv("HOME") .. "/.nvim-utils/package/*")
vim.opt.runtimepath:append(os.getenv("HOME") .. "/.nvim-utils/package/*/after")

Dependency Management

Synapse automatically handles plugin dependencies:

  1. Auto-install: Dependencies are installed automatically
  2. Deduplication: Shared dependencies are installed only once
  3. Priority: If a dependency is also a main plugin, its configuration takes precedence
  4. Protection: Dependencies are protected during removal unless unused
  5. Configuration with opt: Dependencies can be configured using the opt field

Loading Order:

  1. All .config.lua files are loaded first (main plugins are set up)
  2. Then dependencies with opt are configured (ensuring proper initialization order)

This ensures that if plugin-a depends on plugin-b, and both have configurations, plugin-b will be set up before plugin-a's dependency configuration is applied.

Plugin Name Resolution:

Synapse automatically extracts plugin names from the repo field, but you can override this using the primary field. The resolution order is:

  1. primary field (if specified) - highest priority
  2. Extract from repo field (e.g., "user/plugin-name" -> "plugin-name")
  3. Extract from module name (e.g., "pkgs.plugin.config" -> "plugin")
  4. Extract from file path

If primary is not specified, Synapse will try multiple variations when requiring the plugin:

  • Original extracted name
  • Lowercase version (if contains uppercase)
  • Without "-nvim" or ".nvim" suffix

This helps handle different plugin naming conventions automatically.

Troubleshooting

Plugins Not Recognized

  • Ensure installation configuration files (.lua) are in config_path (supports subdirectories)
  • Check that files return a table with a repo field
  • Verify repo field is not empty

Keymaps Not Working

  • Ensure leader key is set before synapse.setup() is called
  • Check that keymaps are not overridden by other configurations

Dependencies Not Installed

  • Check depend field format (array of strings or tables)
  • Verify repository URLs are correct
  • Check network connectivity

License

MIT License

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages