pogyomo / submode.nvim

Create your own submode
MIT License
41 stars 0 forks source link
keymapping lua neovim neovim-plugin

:wrench: submode.nvim

This plugin provide apis to create a submode and manipulate it.

These apis can be used on-the-fly: no need to call config that other plugin need.

:warning: Warning

This plugin is in development stage and breaking changes may occure to apis. We recommend you to pin version for prevent unexpected change.

:clipboard: Requirements

:notebook: Introduction

This plugin allow users to create submode, which has almost same keymaps as the parent mode like normal, insert, etc, but some keymaps is changed and is defined by user.

:rocket: Create a submode

For example, when we try to move around windows, we need to press <C-w>h, <C-w>j, <C-w>k and <C-w>l multiple times. Therefore, it would be useful to be able to press <C-w> and then hjkl to move the window.

Fortunately, you can define such submode as follow.

local submode = require("submode")
submode.create("WinMove", {
    mode = "n",
    enter = "<C-w>",
    leave = { "q", "<ESC>" },
    default = function(register)
        register("h", "<C-w>h")
        register("j", "<C-w>j")
        register("k", "<C-w>k")
        register("l", "<C-w>l")
    end
})

This submode has default mappings hjkl for moving around windows, and you can enter this submode by pressing <C-w> when in normal mode. Once you enter this submode, you can use hjkl. You can leave from this submode by pressing q or escape, and after that hjkl cannot be used to move windows anymore.

:mag: Extend exists submode

Next, sometimes you may want to add a mappings to exist submode to extend the behavior of the submode. Is it possible in this plugin? The answer is yes.

For example, you have a submode defined as follow.

local submode = require("submode")
submode.create("test", {
    mode = "n",
    enter = "]",
    leave = { "q", "<ESC>" },
    default = function(register)
        register("1", function() vim.notify("1") end)
    end,
})

If you want to add 2 to notify 2, you can achieve it with the following code.

submode.set("test", "2", function() vim.notify("2") end)

This interface is compatible with vim.keymap.set, so you can easily define mappings the way you are used to.

Just as neovim provides vim.keymap.del, this plugin provides its compatible interface: submode.del. You can use it like as vim.keymap.set.

submode.del("test", "2")

One additional notable point is that default mappings created by submode.create doesn't change even if submode.set and submode.del is called in the order.

For example, if we call submode.set("test", "1", ""), this disable the behavior of 1 in test, but if we call submode.del("test", "1") after that, pressing 1 will notify 1.

:pinching_hand: Use different of submode.create and submode.set

We introduced two type of mappings: default mappings defined by submode.create and mappings defined by submode.set. So, how to use different?

The first is intended to provide a default mappings to user by submode creator, and second intended that user extend exist submode provided by someone.

As far as personal use, you can use either of way freely.

For example, the submode WinMove also can be defined as follow:

local submode = require("submode")
submode.create("WinMove", {
    mode = "n",
    enter = "<C-w>",
    leave = { "q", "<ESC>" },
})
submode.set("WinMove", "h", "<C-w>h")
submode.set("WinMove", "j", "<C-w>j")
submode.set("WinMove", "k", "<C-w>k")
submode.set("WinMove", "l", "<C-w>l")

If you created a plugin and want to provide a submode using this, it is preferred submode.create to define mappings as it allow user to override default mappings or remove overrided mappings to restore default mappings.

:inbox_tray: Installation

With lazy.nvim

return {
    "pogyomo/submode.nvim",
    lazy = true,
    -- (recommended) specify version to prevent unexpected change.
    -- version = "6.0.0",
}

:bulb: Examples

local submode = require("submode")

submode.create("LspOperator", {
    mode = "n",
    enter = "<Space>l",
    leave = { "q", "<ESC>" },
    default = function(register)
        register("d", vim.lsp.buf.definition)
        register("D", vim.lsp.buf.declaration)
        register("H", vim.lsp.buf.hover)
        register("i", vim.lsp.buf.implementation)
        register("r", vim.lsp.buf.references)
    end,
})
local submode = require("submode")

submode.create("DocReader", {
    mode = "n",
    default = function(register)
        register("<Enter>", "<C-]>")
        register("u", "<cmd>po<cr>")
        register("r", "<cmd>ta<cr>")
        register("U", "<cmd>ta<cr>")
        register("q", "<cmd>q<cr>")
    end,
})

vim.api.nvim_create_augroup("DocReaderAugroup", {})
vim.api.nvim_create_autocmd("BufEnter", {
    group = "DocReaderAugroup",
    callback = function()
        if vim.opt.ft:get() == "help" and not vim.bo.modifiable then
            submode.enter("DocReader")
        end
    end,
})
vim.api.nvim_create_autocmd({ "BufLeave", "CmdwinEnter" }, {
    group = "DocReaderAugroup",
    callback = function()
        if submode.mode() == "DocReader" then
            submode.leave()
        end
    end,
})

:date: User Events

The following user events will be triggered.

:desktop_computer: APIS