neovim / neovim

Vim-fork focused on extensibility and usability
https://neovim.io
Other
82.58k stars 5.66k forks source link

Most recently used text-object, `v:motion` #19426

Open kylechui opened 2 years ago

kylechui commented 2 years ago

Feature description

As an author of a surround plugin, I think would be quite useful to get the most recently used text-object, for preserving dot-repeat. It can be thought of as being analogous to v:operator. For example, if I were to surround a word (g@iw), then I can't use any other operator in that time frame, otherwise destroying dot-repeatability (e.g. formatting the motion via =). This is because I have no way of resetting the operatorfunc with the correct motion. Allowing users to read the most recently used motion in addition to the most recently used operator would allow for much more complex dot-repeatable actions. Thanks for taking the time to read this, and for your hard work on Neovim!

Edit: For clarification, this feature (I think) would open up nearly endless ways for plugin authors to manipulate dot-repeats without compromising on plugin functionality. In other words, it would make dot-repeating work for the plugin author, instead of the other way around. As it is right now, plugin authors have to be very careful with how they wish to program their functions in order to ensure that the dot-repeated action is not overwritten/lost.

For example, consider a function that uses operatorfunc to perform some action, e.g. via setting vim.go.operatorfunc = "v:lua.callback_function". The idea is that the plugin author can then "reset" both the operatorfunc and motion at the end of some function call to "force" what the next dot-repeat action will do.

_G.noop = function() end

_G.main_function = function(args)
    if not args then
        vim.go.operatorfunc = "v:lua.callback_function"
        return "g@"
    end
    local motion = vim.v.motion -- MRU motion here
    -- Do *anything* here: format some text, call opfunc a few times to get some text-object locations, etc.

    -- Force dot-repeat to call the same function, as if you had retyped the command
    vim.go.operatorfunc = "v:lua.noop"
    vim.cmd("normal g@" .. motion)
    vim.go.operatorfunc = "v:lua.callback_function"
end

_G.callback_function = function(mode)
    -- Do something, perhaps set some variables in a table args
    local args = ...
    main_function(args)
end
kylechui commented 2 years ago

This would also be useful for "trimming whitespace" associated with certain motions. For example, g@a" (or any quote, for that matter) by default selects extra whitespace around the quotes. To trim this whitespace, I wrote a function that moves the [ and ] marks when they are residing on a whitespace character. Having v:motion could let me differentiate between g@i" and g@a", only "trimming whitespace" in the latter.

asmodeus812 commented 3 months ago

Hitting this issue as well, would be also cool if we could modify the last used operator, v:operator variable, to allow us to do/chain normal! {operator}{motion} calls then revert back the v:operator to g@.