Skip to content

Conversation

@tuurep
Copy link

@tuurep tuurep commented Nov 4, 2025

Resolves: #69
Resolves: #84

It looks quite trivial to add support for:

Doing that next on a separate commit

@tuurep
Copy link
Author

tuurep commented Nov 4, 2025

This is now completed

@tuurep
Copy link
Author

tuurep commented Nov 5, 2025

a82ad9a: nonfunctional change but makes it much easier to understand the code.

Resolves chaoren#84
Resolves half of chaoren#69

Additionally, when cursor is at a "space-like", such as the underscore
in a snake case word:

    foo_bar
       ^

Fixes that it should only remove the underscore and not the word after.
Resolves the rest of chaoren#69

To have `cw` work similarly to `dw` and delete the spaces after a word,
set this option:

    set cpoptions-=z (Vim)
    set cpoptions-=_ (Neovim)
When cpo-z was not supported, we called it l:cw and did it
unconditionally on cw command. Now we call it l:cw_special_case to
differentiate, and only have to check if cursor is on whitespace in one
place.
@tuurep tuurep force-pushed the fix-cw-edge-cases branch from 3e8c270 to a82ad9a Compare November 5, 2025 19:45
@tuurep
Copy link
Author

tuurep commented Nov 5, 2025

Small change on comment:

Made it clearer that what was previously a dw edge case is in fact an edge case for operator-pending w in general

Now there's nothing I want to add further

let l:cw_special_case = 0

if l:cpo_z != -1 && a:mode == 'o' && v:operator == 'c' && l:flags == ''
let l:cursor_on_s = matchstr(getline('.'), '\%' . col('.') . 'c' . l:s) != ''
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the most important line to look at here,

Is there a better way to detect whether the cursor is on a part considered 'space' by vim-wordmotion, including _ or - delimiters in words?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you use the s:s regex? I believe there's a regex anchor for the cursor position, so you might be able to use those together.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks I'll see soon if I can simplify this

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A much more understandable version on d81a78b

Btw just for clarity on l:s as it's not visible here and I worded the question a little confusingly:

let l:s = a:uppercase ? s:us : s:s

@tuurep
Copy link
Author

tuurep commented Nov 6, 2025

I've learned now that removing cpo-z in Vim also gets rid of some special case called d-special,

in vim's helpfiles:

:h cpo-z

                                                                *cpo-z*
                z       Special casing the "cw" and "d" command (see |cw| and
                        |d-special|).

:h d-special

                                                        *d-special*
An exception for the d{motion} command: If the motion is not linewise, the
start and end of the motion are not in the same line, and there are only
blanks before the start and there are no non-blanks after the end of the
motion, the delete becomes linewise.  This means that the delete also removes
the line of blanks that you might expect to remain. Use the |o_v| operator to
force the motion to be characterwise or remove the "z" flag from 'cpoptions'
(see |cpo-z|) to disable this peculiarity.

Trying to delete an empty region of text (e.g., "d0" in the first column)
is an error when 'cpoptions' includes the 'E' flag.

Neovim has completely removed the d-special "peculiarity" (corrected: #85 (comment)), and also all "POSIX flags" from cpoptions, from nvim's :h nvim-removed:

- 'cpoptions' (gjpkHw<*- and all POSIX flags were removed)

I'll have to investigate:

  • How to test d-special for Vim, and if it's even something relevant to vim-wordmotion
  • How to skip cpo-w and cpo-< tests in Vader if `has('nvim')

By the way, hope it's okay to add these (very minimal) nvim compatibility checks: the few cpo flags seems all that is necessary, most of them just to tests.

@tuurep
Copy link
Author

tuurep commented Nov 6, 2025

Regarding skipping cpo-w and cpo-< tests if has('nvim'):

Looks like Vader has no mechanism to conditionally skip tests

junegunn/vader.vim#201

So I don't know, maybe just let them fail on Neovim, at least there's no guessing for the reason they fail:

image

@tuurep
Copy link
Author

tuurep commented Nov 6, 2025

To reproduce d-special on Vim:

foo
bar
baz

d2ep (cursor on line 1, col 1)

With cpo-z (default), or in nvim (corrected: #85 (comment)):

baz
foo
bar

Without cpo-z, or in nvim (corrected: #85 (comment)):

foo
bar
baz

Tested with vim-wordmotion plugin installed on Vim, the d-special peculiarity is not reproduced in vim-wordmotion to begin with, and I think that's a good thing. Too complex just to replicate some strange Vi bug that no one has been missing.

(I don't oppose replicating it for Vim to be absolutely faithful to the source, but at least not in the scope of this PR)

I'd say this PR is finished.

@chaoren
Copy link
Owner

chaoren commented Nov 8, 2025

Thanks for the PR! Apologies for the delay. I don't have access to my PC at the moment, so I can't review or test this in detail right now. Thank you so much for the detailed research and testing!

I only added the cw behavior because people asked for it. I'm not going to bother with that special d behavior since no one ever asked.

@tuurep
Copy link
Author

tuurep commented Nov 8, 2025

Great to know you're interested in this!

No hurry at all

Thank you so much for the detailed research and testing!

It started off simple but ended with a whole rabbit hole 😄 like usual

I only added the cw behavior because people asked for it. I'm not going to bother with that special d behavior since no one ever asked.

Yeah sounds good, also related to this plugin the cpo options for the cw special case are very new (added about a year ago), I think the choice to be as close to native as possible was nice but now we can reasonably have both!

@tuurep
Copy link
Author

tuurep commented Nov 14, 2025

Correction on d-special not being in nvim:

Actually it's the opposite: there is only d-special in nvim, just the help tag has been removed. This is surprising, but I've confirmed it: at first I thought the docs were wrong and considered sending a PR to neovim, but that's not the case.

Meaning, this section is still in nvim :h deleting, and it's still accurate:

An exception for the d{motion} command: If the motion is not linewise, the
start and end of the motion are not in the same line, and there are only
blanks before the start and there are no non-blanks after the end of the
motion, the delete becomes linewise.  This means that the delete also removes
the line of blanks that you might expect to remain. Use the |o_v| operator to
force the motion to be charwise.

ref: #85 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

EOL edge case handled for dw needs to be handled for all other operators cw

2 participants