Coder Social home page Coder Social logo

yop.nvim's Introduction

CI status

YOP (Your OPerator)

Warning This plugin is currently in ALPHA and bindings very well might change! I'll try to indicate breaking changes in the breakin change issue

Installation

Here are some snippets for your plugin manager of choice. These implement only the sorting operator.

Lazy.nvim:

{"zdcthomas/yop.nvim"}

Packer:

use("zdcthomas/yop.nvim")

Vim-Plug:

Plug 'zdcthomas/yop.nvim'

What is this?

This is a plugin that allows you to easily make you some operators for great good!

Wait what's an Operator?

That's a good question! There's not much talk about operators in the plugin community, but you've almost certainly been using them already. An operator is any key that operates over a selection of text, selected either through a motion (ex: iw: in-a-word, ab: around-a-bracket, etc), or through a visual selection.

Some of the most common built in operators are

  • d: delete
  • y: yank
  • c: cut
  • !: run selection through an external program
  • gq: format selection

There're tons of less widely known operators too, and they're definitely worth checking out! Run :h operator to learn more.

Ok but what does this plugin do?

Normally, defining an operator takes a bit of work, you'll have to get the text covered by motion or visual selection, operate on that text, and then replace the text in the buffer. This plugin handles everything for you except the operation, so you can focus on what you really care about.

With YOP, all you need is a function that transforms and returns the selected lines, or does some other super cool thing.

Alright, I'm sold! How do I make my own operator?

Making your own operators

The primary interface for yop.nvim is the op_map function.

require("yop").op_map

This function takes the same arguments as vim.keymap.set, except that the 3rd argument (normally either a function or a string representing a vim command), now has to be a function that looks like:

function (selections, info)
  ...
  return optional_replacement_lines
end

where:

  • selections: A list with the selected lines or parts of lines.

  • info: a table with extra info about the motion. (Most of the time you won't need this and can just pass in a 1-arity function)

    {
      position = {
        first = {row_number, column_number},
        last = {row_number, column_number},
      },
      type = motion_callback_type
    }

    Row_number and column_number are 1-indexed integers, motion_callback_type is one of line|char|block

  • optional_replacement_lines: The function can optionally return a table of lines, which will replace the selected region in the buffer.

Note Remember, in Lua, you can ignore extra arguments by simply not listing them in the declaration. This means that you can pass in a 0-arity, 1-arity, or 2-arity function and all will work!

For some example transformation functions, see the examples section

Putting it all together

A full (but useless) example might look like:

require("yop").op_map({"n", "v"}, "<leader>b", function(lines, info)
  return { "bread" }
end)

This example simply replaces the entire selected area with the text bread. On a buffer that looks like

1 2 3
4 5 6
7 8 9

With your cursor on 4 type in <leader>bw. Now { "4 5"} will be passed in as the first argument to the function you passed in. We could also type vw<leader>b, and since we told op_map that we'd also like this mapping to exist in visual mode, it will behave identically.

Afterward, the buffer will look like:

1 2 3
bread 6
7 8 9

If instead, you type <leader>bk, then lines will be {"1 2 3", "4 5 6"} because k is a line wise motion. This is the same as if you entered visual line mode with V and selected the top two lines before hitting <leader>b. The buffer will then become

bread
7 8 9

Warning The following api is very likely to change.

A version of the same function that operates on the whole line can also be created by includinglinewise = true in the third argument opts. This has to be a differentmapping, since this includes a motion along with the operator. It also must be in normal mode

For example:

require("yop").op_map("n", "<leader>bb", function(lines, info)
  return { "bread" }
end, {linewise = true})

This allows you to run <leader>bb on the first line in this example buffer, and change it to:

bread
4 5 6
7 8 9

Examples

Here's a cool little example of a sorting operator, inspired heavily by the sort motion plugin, but with the added feature of asking the user for a delimiter to split the line on.

Sortin!

function(lines, opts)
  -- We don't care about anything non alphanumeric here
  local sort_without_leading_space = function(a, b)
    -- true = a then b
    -- false = b then a
    local pattern = [[^%W*]]
    return string.gsub(a, pattern, "") < string.gsub(b, pattern, "")
  end
  if #lines == 1 then
    -- If only looking at 1 line, sort that line split by some char gotten from input
    local delimeter = utils.get_input("Delimeter: ")
    local split = vim.split(lines[1], delimeter, { trimempty = true })
    -- Remember! `table.sort` mutates the table itself
    table.sort(split, sort_without_leading_space)
    return { utils.join(split, delimeter) }
  else
    -- If there are many lines, sort the lines themselves
    table.sort(lines, sort_without_leading_space)
    return lines
  end
end

Searchin!

Note This requires Telescope to be installed

Here's a real small little guy that'll search in telescope for the text passed over in a motion, or selected visually.

function(lines)
  -- Multiple lines can't be searched for
  if #lines > 1 then
    return
  end
  require("telescope.builtin").grep_string({ search = lines[1] })
end

Contributing! (Thank you!)

Please feel free to contribute!

Testing

This uses busted, luassert (both through plenary.nvim) and matcher_combinators to define tests in test/spec/ directory.

To run all tests just execute

$ make test

GitHub actions

On each PR and on Main, a GitHub Action will run all the tests, and the linter. Tests will be run using stable and nightly versions of Neovim.

What's in a name

It's a great plugin, but I really hate that name! Yop!? I mean, come on! How do you even pronounce it?

Well, first off, it's YAWP, and second, here's a list of other names that were considered that you hopefully hate a bit more!

  • PSYOP
  • MYOPIC
  • MYOP
  • YOUROP
  • OPPENHEIMER
  • YOPTIMUS PRIME
  • OPTIMUS PRIME
  • YOPOLOPOLIS
  • POP

yop.nvim's People

Contributors

zdcthomas avatar fbearoff avatar

Stargazers

Evan Purkhiser avatar  avatar Ha Pham avatar Olivia Kinnear avatar Martin Kinoo avatar Tyler Wardhaugh avatar Saúl Nogueras avatar Lucas Pütz avatar camel_case avatar Steve Vermeulen avatar  avatar Jovyn Tan avatar Bailey Bjornstad avatar Cristobal Rodriguez avatar Steven Butler avatar Bence Czufor avatar Saiful Islam avatar Nick Mahe avatar Tom Moulard avatar  avatar  avatar Aquib Javed avatar  avatar Viv Sedov avatar David Josephs avatar Will Hopkins avatar Jim M. R. Teichgräber avatar kohane27 avatar Vinson Chuong avatar  avatar Ibrahim Abdelkareem avatar K avatar Hongbo Liu avatar Soniccat avatar  avatar Vincent Perrollaz avatar Huỳnh Minh Khang avatar Yangyang Li avatar Nizamuddin Sulieman avatar  avatar  avatar Chaz avatar Hakan Erduman avatar Hans avatar Jeff Hertzler avatar  avatar  avatar Vianney GREMMEL avatar Aryabhatta Dey avatar Oskar Grunning avatar Marc Jakobi avatar Ofir Gal avatar Erich Gubler avatar Cameron avatar Maksym Shevchenko avatar Xavier avatar Thomas Frans avatar  avatar chiddy avatar Riley van Hengstum avatar  avatar Alex Tylor avatar Conor Sinclair avatar Khalid H. Ahmed avatar Ratheesh(ರತೀಶ್) avatar Andy Shevchenko avatar Dan Phillips avatar Horace Williams avatar Patryk Kielar avatar Robert Audi avatar Yuta Katayama avatar  avatar

Watchers

 avatar James Cloos avatar  avatar  avatar

yop.nvim's Issues

Thank you!

I have been using this little plugin for a while and it has worked very well! Today I needed to get the start and end lines to pass to an external command, and not having to worry about handling all the different modes was a bliss. Really made everything much simpler.

Cheers.

Visual Feedback Feature

Hello,

Thanks for this awesome plugin. I was wondering if there's a command to provide visual feedback
or a plan to implement this as an option {{highlight = true, time = 1000}}.

I understand this code acomplishes the same thing as bellow:

vim.keymap.set("n", "gc", '"+y', "Yank Clipboard")

This is an example in which I would like to get visual feed back of what I am yanking.

{
    "zdcthomas/yop.nvim",
    enabled = true,
    keys = {{"g9"}},
    opts = {
      {
        { "n", "v" },
        "g9",
        function(lines)
         vim.fn.setreg("+", table.concat(lines,'\n'))
        end,
      },
    },
    config = function(_, opts)
      local yop = require("yop")
      for _, op in ipairs(opts) do
        yop.op_map(op[1], op[2], op[3])
      end
    end,
  },

Error: `replacement string item contains newlines`

I have a configuration that can easily add custom surround before and after a motion/text object.

However, when I change the join character from a space to a \n, it throws an error in the case of multiple lines.

local function surround_cword(keymap, left, right)
  local function surround(lines)
    local str = vim.iter(lines):join(" ")
    return { left .. str .. right }
  end
  op_map("v", keymap, surround)
  vim.keymap.set("n", keymap, function()
    return require("yop").operate(surround) .. "iw"
  end, { expr = true, remap = true })
end
surround_cword("8d", "--", "")
surround_cword("8v", "var(--", ")")
surround_cword("8c", "calc(", ")")
surround_cword("8x", "${", "}")
surround_cword("8s", "{ condition ? ", " : null }")
local str = vim.iter(lines):join("\n")  -- error on multiple lines

Record:
ezgif-7-692021a06d

image

[BUG] When the lines parameter is { "" }, it doesn't work as expected.

Hi, I found that it doesn't work as expected when motion or textobj is an empty string.

Here is my configuration, it simply replacing textobj/motion with the specified text.

-- replace text
local function replace_to_lorem_text(lines)
  return {
    "Replaced!!",
  }
end
require("yop").op_map({ "n", "v" }, "<leader>jp", replace_to_lorem_text)
"text"      -- works
" "         -- works, 1 space inside.
""          -- doesn't works,  lines parameter is { "" }

How to pass motion to the operator?

Hello, I wrote an operator myself, and it works fine.
Then I realized that I mostly use <leader>siw, so I map it directly.

-- say it operator
local function say_it(lines)
  vim.loop.spawn("say", {
    args = { join(lines, "\n") },
  })
end
op_map({ "n", "v" }, "<leader>s", say_it) -- this works fine.

vim.keymap.set("n", "<leader><leader>s", "<leader>siw")  -- this mapping doesn't work

But the mapping not working. Did I do something wrong?

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.