Giter VIP home page Giter VIP logo

spooky.nvim's Introduction

spooky.nvim ๐Ÿ‘ป

Spooky is a Neovim plugin that defines "remote" text objects: that is, it exposes atomic bundles of jumps and selection commands. It's not just the number of keystrokes that matter here, but the potentially more intuitive workflow achieved through these higher abstractions, that are nevertheless obvious extensions of Vim's grammar. The aim, as usual, is to sharpen the saw: there are no big list of new commands to learn, except for a single affix that can be added to all existing text objects. carb[jump] ("change a remote block [marked by jump]") in no time will be just as natural as targets.vim's canb ("change a[round] next block").

Spooky uses Leap as the default jump engine, but in fact the plugin is jumper-agnostic - you can use or define any custom function you want.

Usage

The jump function is automatically invoked once the text object is specified; after e.g. yarw, select the target as you would usually do, to define the point of reference for the selection. The difference is that instead of jumping there, the word will be yanked.

What are some fun things you can do with this?

  • Delete/fold/comment/etc. paragraphs without leaving your position (zfarp[jump]).
  • Clone text objects in the blink of an eye, even from another window (yarp[jump]).
  • Do the above stunt in Insert mode (...<C-o>yarW[jump]...).
  • Fix a typo with a short, atomic command sequence (cirw[jump][correction]).
  • Operate on distant lines: daa[jump].
  • Use count: e.g. y3aa[jump] yanks 3 lines, just as 3yy would do.

Status

WIP - everything is experimental, no stability guarantees yet.

Requirements

Setup

Basic setup

-- `setup` will create remote text objects from all native ones, by
-- inserting `r` into the middle (e.g. `ip` -> `irp`), using Leap as the
-- targeting engine (searching in all windows).
require('spooky').setup()

-- Set "boomerang" behavior and automatic paste after yanking:
vim.api.nvim_create_augroup('SpookyUser', {})
vim.api.nvim_create_autocmd('User', {
  pattern = 'SpookyOperationDone',
  group = 'SpookyUser',
  callback = function (event)
    local op = vim.v.operator
    -- Restore cursor position (except after change operation).
    if op ~= 'c' then event.data.restore_cursor() end
    -- (Auto)paste after yanking and restoring the cursor, if the
    -- unnamed register was used.
    if op == 'y' and event.data.register == '"' then vim.cmd('normal! p') end
  end
})

Customization and extension

Text objects

setup is just a wrapper over the lower-level method create_text_object({mapping}, {jumper}, {selector}, {opts}).

  • jumper: a callback that moves the cursor to the reference point.

  • selector: a callback that visually selects a range.

  • opts: Dictionary with the following optional fields:

    • event_data: dict to send back arbitrary data on SpookyOperationDone. It will be accessed via the data field of the event. By default, data is filled with:
      • restore_cursor: callback to restore the window and the cursor position
      • register: value of vim.v.register at the time of the operation
      • mapping: mapping used
do
  local spooky = require('spooky')

  -- The default jumper used by Spooky.
  local leap_anywhere = function ()
    require('leap').leap {
      opts = { safe_labels = {} },  -- disable autojump
      target_windows = vim.tbl_filter(
        function (win) return vim.api.nvim_win_get_config(win).focusable end,
        vim.api.nvim_tabpage_list_wins(0)
      ),
    }
  end

  -- If you already have a predefined (native or custom) text object,
  -- `selector()` can return a selector that propagates forced motions
  -- properly.
  -- E.g. this is what `setup()` does by default:
  for _, tobj in ipairs(spooky.default_text_objects) do
    local mapping = tobj:sub(1,1) .. 'r' .. tobj:sub(2)
    spooky.create_text_object(mapping, leap_anywhere, spooky.selector(tobj))
  end


  -- The special `range` and `lines` selectors are implemented by
  -- default.

  -- `range` is specified by two consecutive jumps (end-inclusive -
  -- use `v` to make it exclusive).
  spooky.create_text_object('arr', leap_anywhere, spooky.selectors.range)
  -- Line-range.
  -- A `state` table is automatically passed to selector functions as
  -- a first argument, containing the saved values of `vim.fn.mode(true)`
  -- and `vim.v.count1` (the jumper function can mess with those). Make
  -- sure to pass it on if you're wrapping the call.
  spooky.create_text_object('arR', leap_anywhere, function (state)
    spooky.selectors.range(state)
    vim.cmd('normal! V')
  end)
  -- Custom second jumper (default is Leap in current window).
  spooky.create_text_object('arr', leap_anywhere, function (state)
    spooky.selectors.range(state, { jumper = leap_anywhere })
  end)

  -- `lines` is equivalent to `V{op}`, or, if count > 1 is given,
  -- `V[count-1]j{op}` at the given position.
  spooky.create_text_object('aa', leap_anywhere, spooky.selectors.lines)


  -- "Inner remote line" object, with custom selector function.
  spooky.create_text_object('ii', leap_anywhere, function()
    local mode = vim.fn.mode(true)
    -- Exit Visual mode if already in it.
    if not mode:match('o') then vim.cmd('normal! ' .. mode:sub(1,1)) end
    vim.cmd('normal! _vg_')
  end)
end

Autocommands

More complex autocommand examples:

vim.api.nvim_create_augroup('SpookyUser', {})
vim.api.nvim_create_autocmd('User', {
  pattern = 'SpookyOperationDone',
  group = 'SpookyUser',
  callback = function (event)
    local op = vim.v.operator
    local mapping = event.data.mapping

    -- Just pattern match on your mappings here if you want
    -- restore/no-restore pairs of text objects. E.g. if you use
    -- the affix `R` for "no-restore":
    if not mapping:match('[ai]R') then
      event.data.restore_cursor()
    end

    -- You can also define default behaviors for operations, like above,
    -- but _invert_ it with `R`:

    -- if ((op ~= 'c' and mapping:match('[ai]R')) or
    --     (op == 'c' and not mapping:match'[ai]R'))
    -- then
    --   event.data.restore_cursor()
    -- end

    -- Besides autopaste on remote yanking, you can implement any other
    -- features here, like automatically reformatting a section after
    -- delete, etc.
  end
})

spooky.nvim's People

Contributors

ggandor avatar

Stargazers

 avatar Aura avatar Hajime Suzuki avatar chiddy avatar Anton Kriese avatar Will Hopkins avatar kuator avatar Yuta Katayama avatar Flo Wolfe avatar  avatar Khalid H. Ahmed avatar Artur Kenzhaev avatar  avatar  avatar  avatar Tim Tyrrell avatar EGmux99 avatar

Watchers

 avatar  avatar

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.