Skip to content

Latest commit

 

History

History
438 lines (305 loc) · 13.5 KB

File metadata and controls

438 lines (305 loc) · 13.5 KB

nvim-keysitter

A utility plugin for those who write their own neovim config, and want to write some complex textobject related movements.

Features

  • Chain/Pipping - Chain methods to create complex keymaps with minimal boilerplate
  • Convenient defaults - Common textobject patterns (around/inner/next/prev) with out-of-the-box defaults
  • Group prefixes - Organize related motions under a single key prefix
  • Flexible overrides - Override any default on a per-keymap basis

Quick Start

-- 1. Require and create instance with a prefix for grouped keymaps
local keysitter = require 'keysitter'
local tsto = keysitter.new('treesitter-textobjects', { group_prefix = 'o' })

-- 2. Setup autocommand to define keymaps
tsto.setup({ 'FileType', 'BufEnter' }, 'keysitter', function()
  -- 3. Chain methods to create keymaps
  tsto:set('f', 'function'):around():inner():next():prev()
end, { desc = 'Set keysitter keymaps' })

-- Result: vaof, viof, ]of, ]oF, [of, [oF

Usage

This plugin is made to simplify writing complex keymaps for selecting/jumping textobjects, while also perform some checks and simple logical guards. And it's designed to be used in association with other plugins.

Note

Currently, 'nvim-treesitter-textobjects' is the only supported plugin. But if you find it useful and need it to support other plugins then let me know, I'll try my best to add it.

Example

local keysitter = require 'keysitter'
local tsto = keysitter.new('treesitter-textobjects', { group_prefix = 'o' })

-- a setup function for the group, a new group requires a new setup.
tsto.setup({ 'FileType', 'BufEnter' }, 'keysitter', function()
  -- the following will set:
  tsto:set('f', 'function')
    :around() -- `vaof` for visual-select around a function
    :inner()  -- `viof` for visual-select inner function
    :next()   -- `]of` and `]oF` for jumping to the next start & end of a function
    :prev()   -- `[of` and `[oF` for jumping to the previous start & end of a function

  -- notice how all keymaps are _prefixed_ with `o`, and it will continue unless its overridden per method.

  tsto
    :set('=', 'assignment') -- setting new keymaps
    :around() -- `vao=` for visual-select around an assignment
    -- for inner, we want to target the right-hand-side of the assignment
    :inner({ attribute = 'rhs' }) -- `vio=` for visual-select inner (rhs) assignment
    -- next & prev methods are only for convenience, and you can split their functionality
    :next_start({ attribute = 'lhs' })
    :previous_start({ attribute = 'lhs' })
    :next_start({ attribute = 'rhs', key = '-' }, { desc = 'next rhs assignment' })
    :previous_start({ attribute = 'rhs', key = '-' }, { desc = 'previous rhs assignment' })

  -- or some complex mapping
  tsto
    :set('c', 'class')
    :around()  -- `vaoc` for visual-select around a class
    :inner()   -- `vioc` for visual-select inner class
    :next_start({ motion = ']', group_prefix = '', key = ']' })      -- ']]' for next class start
    :next_end({ motion = ']', group_prefix = '', key = '[' })        -- '][' for next class end
    :previous_start({ motion = '[', group_prefix = '', key = '[' })  -- '[[' for prev class start
    :previous_end({ motion = '[', group_prefix= '', key = ']' })     -- '[]' for next class end

end, { desc = 'Set keysitter keymaps for nvim-treesitter-textobjects' })

Steps

  1. Import/require the plugin

  2. Use new function to get a new instance of Keysitter object.

  3. Use setup method to setup the Keysitter instance for keymap setting.

  4. Use the callback within setup method to define a function that sets keymaps.

    1. Use set method to define targeted textobject (e.g., "function", "class") and associated primary key (e.g., "f", "c")
    2. Use methods like around, inner, next, prev, etc.

Requirements

Installation

vim.pack

Requires nvim >= 0.12

vim.pack.add {
  -- make sure you already have those dependencies installed
  { src = 'https://github.com/nvim-treesitter/nvim-treesitter'},
  { src = 'https://github.com/nvim-treesitter/nvim-treesitter-textobjects'},

  { src = 'https://github.com/ABDsheikho/nvim-keysitter' },
}

-- now you can use it as any other plugin/module
local keysitter = require 'keysitter'
local tsto = keysitter.new('treesitter-textobjects', { group_prefix = 'o' })

-- setup function, see [setup](#setup)
tsto.setup({ 'FileType', 'BufEnter' }, 'keysitter', function()
  -- your keymaps go here
  tsto:set('f', 'function'):around():inner():next():prev()

end, { desc = 'Set keysitter keymaps for nvim-treesitter-textobjects' })

lazy.nvim

As a dependency for nvim-treesitter-textobjects

{
  'nvim-treesitter/nvim-treesitter-textobjects',
  branch = 'main',
  dependencies = {
    {
      'ABDsheikho/nvim-keysitter',
      config = function()
        local keysitter = require 'keysitter'
        local tsto = keysitter.new('treesitter-textobjects', { group_prefix = 'o' })

        -- setup function, see [setup](#setup)
        tsto.setup({ 'FileType', 'BufEnter' }, 'keysitter', function()
          -- your keymaps go here
          tsto:set('f', 'function'):around():inner():next():prev()

        end, { desc = 'Set keysitter keymaps for nvim-treesitter-textobjects' })
      end,
    },
  },
  -- the rest of nvim-treesitter-textobject
}

As a standalone plugin

{
  'ABDsheikho/nvim-keysitter',
  dependencies = {
    'nvim-treesitter/nvim-treesitter',
    'nvim-treesitter/nvim-treesitter-textobjects',
  },
  config = function()
    local keysitter = require 'keysitter'
    local tsto = keysitter.new('treesitter-textobjects', { group_prefix = 'o' })

    -- setup function, see [setup](#setup)
    tsto.setup({ 'FileType', 'BufEnter' }, 'keysitter', function()
      -- your keymaps go here
      tsto:set('f', 'function'):around():inner():next():prev()

    end, { desc = 'Set keysitter keymaps for nvim-treesitter-textobjects' })
  end,
}

API: Types

Keysitter

  • key (string): The primary key for keymap
  • object (string): The textobject name (e.g., "function", "class")
  • group_prefix (string): optional Prefix for the keymap group, good for grouping multiple related motions under one key/prefix. (default to "")

GroupOpts

  • group_prefix (string): optional Prefix for the keymap group, good for grouping multiple related motions under one key/prefix. (default to "")

KeymapOpts

  • mode (string|string[]): optional Override the default vim mode(s) for the keymap, see :h vim.keymap.set()
  • motion (string): optional Override the main motion used to target the textobject while visual-selection/jumping (e.g., 'a', 'i', ']', '[' )
  • key (string): optional Override the primary key for the keymap
  • group_prefix (string): optional Override the group prefix for the keymap
  • attribute (keysitter.Attribute): optional Attribute for the textobject node (e.g., "outer", "inner", "rhs", "lhs", etc.)
  • callback (function): optional Optional callback to execute instead of default action

VimKeymapOpts

Alias for vim.keymap.set.Opts see :h vim.keymap.set()

API: Functions

new()

Create a new Keysitter instance for the specified textobject-module.

param:

  • txtobj_module (keysitter.TextObjectModule): The name of the textobject group (e.g., "treesitter-textobjects")
  • opts (keysitter.GroupOpts): optional Optional group-configuration options

return:

  • A Keysitter instance (keysitter.Keysitter)

setup()

Delegates setup to the loaded Keysitter module. Allows modules to configure their own autocommands and callbacks.

param:

  • event (string|string[]): List of Neovim event(s) that will trigger the handler, see :h nvim_create_autocmd()
  • group (string): Name or id of the autocommand group to match against
  • callback (function|string): Callable function for the autocommand
  • opts (keysitter.SetupOpts): optional Module-specific options

Note

Currently (with the only usage of nvim-treesitter-textobject) this function acts as a wrapper for only nvim_create_autocmd & nvim_create_augroup as a simpler form. And it can be replaced by a snippet like: (compare it to example)

vim.api.nvim_create_autocmd({ 'FileType', 'BufEnter' }, {
  desc = 'Set keysitter keymaps for nvim-treesitter-textobjects'
  group = vim.api.nvim_create_augroup('keysitter', { clear = true }),
  callback = function()
    -- this part is where you use Keysitter-instance to define keymaps.
    tsto:set('f', 'function'):around():inner():next():prev()
  end,
})

around()

Create a keymap for selecting the outer textobject, including its boundaries (full scope).

param:

  • opts (keysitter.KeymapOpts): optional User options (overrides defaults)
  • vim_opts (keysitter.VimKeymapOpts): optional options for vim.keymap.set(), see :h vim.keymap.set()

return:

  • A Keysitter instance (keysitter.Keysitter)

inner()

Create a keymap for selecting the inner textobject, excluding its boundaries (inner scope).

param:

  • opts (keysitter.KeymapOpts): optional User options (overrides defaults)
  • vim_opts (keysitter.VimKeymapOpts): optional options for vim.keymap.set(), see :h vim.keymap.set()

return:

  • A Keysitter instance (keysitter.Keysitter)

next()

Create keymaps for moving to both the start and end of the next textobject. Convenient method that chains next_start() and next_end().

param:

  • opts (keysitter.KeymapOpts): optional User options (overrides defaults)
  • vim_opts (keysitter.VimKeymapOpts): optional options for vim.keymap.set(), see :h vim.keymap.set()

return:

  • A Keysitter instance (keysitter.Keysitter)

prev()

Create keymaps for moving to both the start and end of the previous textobject. Convenient method that chains previous_start() and previous_end().

param:

  • opts (keysitter.KeymapOpts): optional User options (overrides defaults)
  • vim_opts (keysitter.VimKeymapOpts): optional options for vim.keymap.set(), see :h vim.keymap.set()

return:

  • A Keysitter instance (keysitter.Keysitter)

goto_start()

Create keymaps for moving to the start of the next and previous textobject. Convenient method that chains next_start() and previous_start().

param:

  • opts (keysitter.KeymapOpts): optional User options (overrides defaults)
  • vim_opts (keysitter.VimKeymapOpts): optional options for vim.keymap.set(), see :h vim.keymap.set()

return:

  • A Keysitter instance (keysitter.Keysitter)

goto_end()

Create keymaps for moving to the end of the next and previous textobject. Convenient method that chains next_end() and previous_end(). Only available if the textobject-module supports end for its textobjects.

param:

  • opts (keysitter.KeymapOpts): optional User options (overrides defaults)
  • vim_opts (keysitter.VimKeymapOpts): optional options for vim.keymap.set(), see :h vim.keymap.set()

return:

  • A Keysitter instance (keysitter.Keysitter)

next_start()

Create a keymap for moving to the start of the next textobject.

param:

  • opts (keysitter.KeymapOpts): optional User options (overrides defaults)
  • vim_opts (keysitter.VimKeymapOpts): optional options for vim.keymap.set(), see :h vim.keymap.set()

return:

  • A Keysitter instance (keysitter.Keysitter)

next_end()

Create a keymap for moving to the end of the next textobject. Only available if the textobject-module supports end for its textobjects.

param:

  • opts (keysitter.KeymapOpts): optional User options (overrides defaults)
  • vim_opts (keysitter.VimKeymapOpts): optional options for vim.keymap.set(), see :h vim.keymap.set()

return:

  • A Keysitter instance (keysitter.Keysitter)

previous_start()

Create a keymap for moving to the start of the previous textobject.

param:

  • opts (keysitter.KeymapOpts): optional User options (overrides defaults)
  • vim_opts (keysitter.VimKeymapOpts): optional options for vim.keymap.set(), see :h vim.keymap.set()

return:

  • A Keysitter instance (keysitter.Keysitter)

previous_end()

Create a keymap for moving to the end of the previous textobject. Only available if the textobject-module supports end for its textobjects.

param:

  • opts (keysitter.KeymapOpts): optional User options (overrides defaults)
  • vim_opts (keysitter.VimKeymapOpts): optional options for vim.keymap.set(), see :h vim.keymap.set()

return:

  • A Keysitter instance (keysitter.Keysitter)

To-dos

  • make swap functionality for nvim-treesitter-textobjects.
  • check for other potential plugins (maybe gitsings?).

Acknowledgment

My main motivation was to write something for nvim-treesitter/nvim-treesitter-textobjects that simplifies my config, which led me to separate it into its own plugin. Thanks to them for their incredible work.


License

Licensed under the Apache License, Version 2.0. See LICENSE for details.