Skip to content

Commit

Permalink
make d{motion} work more consistent
Browse files Browse the repository at this point in the history
Problem:  d{motion} may work different than expected (also cw
          is special cased by POSIX)
Solution: add new cpo-z flag to make the behaviour configurable

There are two special vi compatible behaviours:

1): cw behaves differently than dw. That is, because cw is special cased
    by Vim and is effectively aliased to ce.

    POSIX behaviour:
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/vi.html#tag_20_152_13_81

2): d{motion} may make the whole delete operation linewise, if the start
    and end of the motion are on different lines and there are only
    blanks before the start and after the end of the motion.
    Did not find a related POSIX link that requires this behaviour.

Both behaviours can be considered inconsistent, but we cannot easily
change it, because it would be a backward incompatible change and also
incompatible to how classic vi behaved.

So let's add the new cpo flag "w", which when not included fixes both
behaviours and make them more consistent to what users would expect.

This has been requested several times:
https://groups.google.com/d/msg/vim_use/aaBqT6ECkA4/ALf4odKzEDgJ
https://groups.google.com/d/msg/vim_dev/Dpn3xtUF16I/T6JcOPKN6usJ
http://www.reddit.com/r/vim/comments/26nut8/why_does_cw_work_like_ce/
https://groups.google.com/d/msg/vim_use/vunNWLFWfQg/MmJh_ZGaAgAJ
vim#4390

So in summary, if you want to have the w motion work more consistent,
remove the 'z' from the cpo settings.

related: vim#4390

Signed-off-by: Christian Brabandt <[email protected]>
  • Loading branch information
chrisbra committed Jul 14, 2024
1 parent 27c5598 commit 681caaf
Show file tree
Hide file tree
Showing 9 changed files with 72 additions and 14 deletions.
8 changes: 4 additions & 4 deletions runtime/doc/change.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
*change.txt* For Vim version 9.1. Last change: 2024 Jun 23
*change.txt* For Vim version 9.1. Last change: 2024 Jul 14


VIM REFERENCE MANUAL by Bram Moolenaar
Expand Down Expand Up @@ -95,13 +95,13 @@ For inserting text see |insert.txt|.
These commands delete text. You can repeat them with the `.` command
(except `:d`) and undo them. Use Visual mode to delete blocks of text. See
|registers| for an explanation of registers.

*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.
force the motion to be characterwise or set |cpo-z|.

Trying to delete an empty region of text (e.g., "d0" in the first column)
is an error when 'cpoptions' includes the 'E' flag.
Expand Down Expand Up @@ -251,7 +251,7 @@ blank; this is probably a bug, because "dw" deletes all the blanks; use the

If you prefer "cw" to include the space after a word, use this mapping: >
:map cw dwi
Or use "caw" (see |aw|).
Alternatively use "caw" (see also |aw| and |cpo-z|).

*:c* *:ch* *:change*
:{range}c[hange][!] Replace lines of text with some different text.
Expand Down
4 changes: 2 additions & 2 deletions runtime/doc/motion.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
*motion.txt* For Vim version 9.1. Last change: 2023 Dec 27
*motion.txt* For Vim version 9.1. Last change: 2024 Jul 14


VIM REFERENCE MANUAL by Bram Moolenaar
Expand Down Expand Up @@ -434,7 +434,7 @@ WORD before the fold.

Special case: "cw" and "cW" are treated like "ce" and "cE" if the cursor is
on a non-blank. This is because "cw" is interpreted as change-word, and a
word does not include the following white space.
word does not include the following white space (see also |cw|).

Another special case: When using the "w" motion in combination with an
operator and the last word moved over is at the end of a line, the end of
Expand Down
5 changes: 4 additions & 1 deletion runtime/doc/options.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
*options.txt* For Vim version 9.1. Last change: 2024 Jul 11
*options.txt* For Vim version 9.1. Last change: 2024 Jul 13


VIM REFERENCE MANUAL by Bram Moolenaar
Expand Down Expand Up @@ -2486,6 +2486,9 @@ A jump table for the options with a short description can be found at |Q_op|.
*cpo-Z*
Z When using "w!" while the 'readonly' option is set,
don't reset 'readonly'.
*cpo-z*
z Special casing the motion for "cw" and "dw"
(see |cw| and |d-special|).
*cpo-!*
! When redoing a filter command, use the last used
external command, whatever it was. Otherwise the last
Expand Down
2 changes: 2 additions & 0 deletions runtime/doc/tags
Original file line number Diff line number Diff line change
Expand Up @@ -6671,6 +6671,7 @@ cpo-v options.txt /*cpo-v*
cpo-w options.txt /*cpo-w*
cpo-x options.txt /*cpo-x*
cpo-y options.txt /*cpo-y*
cpo-z options.txt /*cpo-z*
cpo-{ options.txt /*cpo-{*
cpp.vim syntax.txt /*cpp.vim*
crash-recovery recover.txt /*crash-recovery*
Expand Down Expand Up @@ -6733,6 +6734,7 @@ cw change.txt /*cw*
cweb.vim syntax.txt /*cweb.vim*
cynlib.vim syntax.txt /*cynlib.vim*
d change.txt /*d*
d-special change.txt /*d-special*
daB motion.txt /*daB*
daW motion.txt /*daW*
dab motion.txt /*dab*
Expand Down
8 changes: 6 additions & 2 deletions src/normal.c
Original file line number Diff line number Diff line change
Expand Up @@ -6598,8 +6598,12 @@ nv_wordcmd(cmdarg_T *cap)
// "ce" will change until the end of the next word, but "cw"
// will change only one character! This is done by setting
// flag.
cap->oap->inclusive = TRUE;
word_end = TRUE;
// This can be configured using :set cpo-z
if (vim_strchr(p_cpo, CPO_WORD) != NULL)
{
cap->oap->inclusive = TRUE;
word_end = TRUE;
}
flag = TRUE;
}
}
Expand Down
1 change: 1 addition & 0 deletions src/ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,7 @@ op_delete(oparg_T *oap)
&& !oap->block_mode
&& oap->line_count > 1
&& oap->motion_force == NUL
&& (vim_strchr(p_cpo, CPO_WORD) != NULL)
&& oap->op_type == OP_DELETE)
{
ptr = ml_get(oap->end.lnum) + oap->end.col;
Expand Down
7 changes: 4 additions & 3 deletions src/option.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ typedef enum {
#define CPO_REPLCNT 'X' // "R" with a count only deletes chars once
#define CPO_YANK 'y'
#define CPO_KEEPRO 'Z' // don't reset 'readonly' on ":w!"
#define CPO_WORD 'z' // do not special-case word motions cw and dw
#define CPO_DOLLAR '$'
#define CPO_FILTER '!'
#define CPO_MATCH '%'
Expand All @@ -231,9 +232,9 @@ typedef enum {
#define CPO_SCOLON ';' // using "," and ";" will skip over char if
// cursor would not move
// default values for Vim, Vi and POSIX
#define CPO_VIM "aABceFs"
#define CPO_VI "aAbBcCdDeEfFgHiIjJkKlLmMnoOpPqrRsStuvwWxXyZ$!%*-+<>;"
#define CPO_ALL "aAbBcCdDeEfFgHiIjJkKlLmMnoOpPqrRsStuvwWxXyZ$!%*-+<>#{|&/\\.;"
#define CPO_VIM "aABceFsz"
#define CPO_VI "aAbBcCdDeEfFgHiIjJkKlLmMnoOpPqrRsStuvwWxXyZz$!%*-+<>;"
#define CPO_ALL "aAbBcCdDeEfFgHiIjJkKlLmMnoOpPqrRsStuvwWxXyZz$!%*-+<>#{|&/\\.;"

// characters for p_ww option:
#define WW_ALL "bshl<>[]~"
Expand Down
5 changes: 3 additions & 2 deletions src/testdir/test_codestyle.vim
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ def Test_test_files()
&& fname !~ 'test_listchars.vim'
&& fname !~ 'test_visual.vim'
cursor(1, 1)
var lnum = search(fname =~ "test_regexp_latin" ? '[^á] \t' : ' \t')
var skip = 'getline(".") =~ "codestyle: ignore"'
var lnum = search(fname =~ "test_regexp_latin" ? '[^á] \t' : ' \t', 'W', 0, 0, skip)
ReportError('testdir/' .. fname, lnum, 'space before Tab')
endif

Expand Down Expand Up @@ -155,4 +156,4 @@ def Test_help_files()
enddef


" vim: shiftwidth=2 sts=2 expandtab
" vim: shiftwidth=2 sts=2 expandtab nofoldenable
46 changes: 46 additions & 0 deletions src/testdir/test_cpoptions.vim
Original file line number Diff line number Diff line change
Expand Up @@ -912,4 +912,50 @@ func Test_cpo_dot()
let &cpo = save_cpo
endfunc

" Test for the 'z' flag in 'cpo' (make cw and dw work similar and avoid
" inconsistencies, see :h cpo-z)
" modified)
func Test_cpo_z()
let save_cpo = &cpo
new
" Test 1: dw behaves differently from cw
call setline(1, ['foo bar baz', 'one two three'])
call cursor(1, 1)
" dw does not delete the whitespace after the word
norm! wcwanother
set cpo-=z
" dw deletes the whitespace after the word
call cursor(2, 1)
norm! wcwfour
call assert_equal(['foo another baz', 'one fourthree'], getline(1, '$'))
" Test 2: d{motion} becomes linewise :h d-special
%d
call setline(1, ['one ', ' bar', ' e ', 'zwei'])
call cursor(2, 1)
set cpo+=z
" delete operation becomes linewise
call feedkeys("fbd/e\\zs\<cr>", 'tnx')
call assert_equal(['one ', 'zwei'], getline(1, '$'))
%d
call setline(1, ['one ', ' bar', ' e ', 'zwei'])
call cursor(2, 1)
call feedkeys("fbd2w", 'tnx')
call assert_equal(['one ', 'zwei'], getline(1, '$'))

" delete operation does not become line wise
set cpo-=z
call setline(1, ['one ', ' bar', ' e ', 'zwei'])
call cursor(2, 1)
call feedkeys("fbd/e\\zs\<cr>", 'tnx')
call assert_equal(['one ', ' ', 'zwei'], getline(1, '$')) " codestyle: ignore
%d
call setline(1, ['one ', ' bar', ' e ', 'zwei'])
call cursor(2, 1)
call feedkeys("fbd2w", 'tnx')
call assert_equal(['one ', ' ', 'zwei'], getline(1, '$'))

" clean up
bw!
let &cpo = save_cpo
endfunc
" vim: shiftwidth=2 sts=2 expandtab

0 comments on commit 681caaf

Please sign in to comment.