aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/index.txt1
-rw-r--r--runtime/doc/motion.txt6
-rw-r--r--runtime/doc/quickref.txt1
-rw-r--r--runtime/doc/usr_25.txt9
-rwxr-xr-xscripts/update_version_stamp.lua7
-rw-r--r--src/nvim/ex_cmds.c5
-rw-r--r--src/nvim/normal.c16
-rw-r--r--src/nvim/ops.c1
-rw-r--r--src/nvim/quickfix.c4
-rw-r--r--src/nvim/syntax.c12
-rw-r--r--src/nvim/testdir/test_normal.vim24
-rw-r--r--src/nvim/testdir/test_substitute.vim10
-rw-r--r--src/nvim/testdir/test_virtualedit.vim9
13 files changed, 90 insertions, 15 deletions
diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt
index be9e25113a..9fd68144bc 100644
--- a/runtime/doc/index.txt
+++ b/runtime/doc/index.txt
@@ -767,6 +767,7 @@ tag char note action in Normal mode ~
|gn| gn 1,2 find the next match with the last used
search pattern and Visually select it
|gm| gm 1 go to character at middle of the screenline
+|gM| gM 1 go to character at middle of the text line
|go| go 1 cursor to byte N in the buffer
|gp| ["x]gp 2 put the text [from register x] after the
cursor N times, leave the cursor after it
diff --git a/runtime/doc/motion.txt b/runtime/doc/motion.txt
index 97c7d1cc43..9e24ee0320 100644
--- a/runtime/doc/motion.txt
+++ b/runtime/doc/motion.txt
@@ -219,6 +219,12 @@ g^ When lines wrap ('wrap' on): To the first non-blank
gm Like "g0", but half a screenwidth to the right (or as
much as possible).
+ *gM*
+gM Like "g0", but to halfway the text of the line.
+ With a count: to this percentage of text in the line.
+ Thus "10gM" is near the start of the text and "90gM"
+ is near the end of the text.
+
*g$* *g<End>*
g$ or g<End> When lines wrap ('wrap' on): To the last character of
the screen line and [count - 1] screen lines downward
diff --git a/runtime/doc/quickref.txt b/runtime/doc/quickref.txt
index 87cb9b54f5..dfa7218bdf 100644
--- a/runtime/doc/quickref.txt
+++ b/runtime/doc/quickref.txt
@@ -47,6 +47,7 @@ N is used to indicate an optional count that can be given before the command.
|g$| N g$ to last character in screen line (differs from "$"
when lines wrap)
|gm| gm to middle of the screen line
+|gM| gM to middle of the line
|bar| N | to column N (default: 1)
|f| N f{char} to the Nth occurrence of {char} to the right
|F| N F{char} to the Nth occurrence of {char} to the left
diff --git a/runtime/doc/usr_25.txt b/runtime/doc/usr_25.txt
index 3a58af6412..2efb67e55f 100644
--- a/runtime/doc/usr_25.txt
+++ b/runtime/doc/usr_25.txt
@@ -346,12 +346,13 @@ scroll:
g0 to first visible character in this line
g^ to first non-blank visible character in this line
- gm to middle of this line
+ gm to middle of screen line
+ gM to middle of the text in this line
g$ to last visible character in this line
- |<-- window -->|
- some long text, part of which is visible ~
- g0 g^ gm g$
+ |<-- window -->|
+ some long text, part of which is visible in one line ~
+ g0 g^ gm gM g$
BREAKING AT WORDS *edit-no-break*
diff --git a/scripts/update_version_stamp.lua b/scripts/update_version_stamp.lua
index 394c4f7694..11b521fab6 100755
--- a/scripts/update_version_stamp.lua
+++ b/scripts/update_version_stamp.lua
@@ -13,6 +13,10 @@ local function die(msg)
os.exit(0)
end
+local function iswin()
+ return package.config:sub(1,1) == '\\'
+end
+
if #arg ~= 2 then
die(string.format("Expected two args, got %d", #arg))
end
@@ -20,7 +24,8 @@ end
local versiondeffile = arg[1]
local prefix = arg[2]
-local described = io.popen('git describe --first-parent --dirty 2>/dev/null'):read('*l')
+local dev_null = iswin() and 'NUL' or '/dev/null'
+local described = io.popen('git describe --first-parent --dirty 2>'..dev_null):read('*l')
if not described then
described = io.popen('git describe --first-parent --tags --always --dirty'):read('*l')
end
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 2e8bd79c81..04aa8f7ef6 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -3524,6 +3524,11 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
// Note: If not first match on a line, column can't be known here
current_match.start.lnum = sub_firstlnum;
+ // Match might be after the last line for "\n\zs" matching at
+ // the end of the last line.
+ if (lnum > curbuf->b_ml.ml_line_count) {
+ break;
+ }
if (sub_firstline == NULL) {
sub_firstline = vim_strsave(ml_get(sub_firstlnum));
}
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index d1c6362931..2ef2c3101f 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -6749,6 +6749,22 @@ static void nv_g_cmd(cmdarg_T *cap)
curwin->w_set_curswant = true;
break;
+ case 'M':
+ {
+ const char_u *const ptr = get_cursor_line_ptr();
+
+ oap->motion_type = kMTCharWise;
+ oap->inclusive = false;
+ i = (int)mb_string2cells_len(ptr, STRLEN(ptr));
+ if (cap->count0 > 0 && cap->count0 <= 100) {
+ coladvance((colnr_T)(i * cap->count0 / 100));
+ } else {
+ coladvance((colnr_T)(i / 2));
+ }
+ curwin->w_set_curswant = true;
+ }
+ break;
+
case '_':
/* "g_": to the last non-blank character in the line or <count> lines
* downward. */
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 030782cbcc..fbbdfdcd82 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -1562,6 +1562,7 @@ int op_delete(oparg_T *oap)
oap->end = curwin->w_cursor;
curwin->w_cursor = oap->start;
}
+ mb_adjust_opend(oap);
}
if (oap->line_count == 1) { /* delete characters within one line */
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 4ca9ca2a3e..a9e0c22a76 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -1693,9 +1693,7 @@ static int copy_loclist(const qf_list_T *from_qfl,
}
if (from_qfl->qf_ctx != NULL) {
to_qfl->qf_ctx = xcalloc(1, sizeof(*to_qfl->qf_ctx));
- if (to_qfl->qf_ctx != NULL) {
- tv_copy(from_qfl->qf_ctx, to_qfl->qf_ctx);
- }
+ tv_copy(from_qfl->qf_ctx, to_qfl->qf_ctx);
} else {
to_qfl->qf_ctx = NULL;
}
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index ac8ace9fff..bdbc09a87a 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -2460,11 +2460,8 @@ update_si_end(
int force /* when TRUE overrule a previous end */
)
{
- lpos_T startpos;
- lpos_T endpos;
lpos_T hl_endpos;
lpos_T end_endpos;
- int end_idx;
/* return quickly for a keyword */
if (sip->si_idx < 0)
@@ -2480,9 +2477,12 @@ update_si_end(
* We need to find the end of the region. It may continue in the next
* line.
*/
- end_idx = 0;
- startpos.lnum = current_lnum;
- startpos.col = startcol;
+ int end_idx = 0;
+ lpos_T startpos = {
+ .lnum = current_lnum,
+ .col = startcol,
+ };
+ lpos_T endpos = { 0 };
find_endpos(sip->si_idx, &startpos, &endpos, &hl_endpos,
&(sip->si_flags), &end_endpos, &end_idx, sip->si_extmatch);
diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim
index 07d250cace..eab638d19a 100644
--- a/src/nvim/testdir/test_normal.vim
+++ b/src/nvim/testdir/test_normal.vim
@@ -1895,6 +1895,7 @@ fun! Test_normal33_g_cmd2()
set wrap listchars= sbr=
let lineA='abcdefghijklmnopqrstuvwxyz'
let lineB='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ let lineC='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
$put =lineA
$put =lineB
@@ -1928,9 +1929,30 @@ fun! Test_normal33_g_cmd2()
call assert_equal(15, col('.'))
call assert_equal('l', getreg(0))
+ norm! 2ggdd
+ $put =lineC
+
+ " Test for gM
+ norm! gMyl
+ call assert_equal(73, col('.'))
+ call assert_equal('0', getreg(0))
+ " Test for 20gM
+ norm! 20gMyl
+ call assert_equal(29, col('.'))
+ call assert_equal('S', getreg(0))
+ " Test for 60gM
+ norm! 60gMyl
+ call assert_equal(87, col('.'))
+ call assert_equal('E', getreg(0))
+
+ " Test for g Ctrl-G
+ set ff=unix
+ let a=execute(":norm! g\<c-g>")
+ call assert_match('Col 87 of 144; Line 2 of 2; Word 1 of 1; Byte 88 of 146', a)
+
" Test for gI
norm! gIfoo
- call assert_equal(['', 'fooabcdefghijk lmno0123456789AMNOPQRSTUVWXYZ'], getline(1,'$'))
+ call assert_equal(['', 'foo0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'], getline(1,'$'))
" Test for gi
wincmd c
diff --git a/src/nvim/testdir/test_substitute.vim b/src/nvim/testdir/test_substitute.vim
index b29b678129..e209310a05 100644
--- a/src/nvim/testdir/test_substitute.vim
+++ b/src/nvim/testdir/test_substitute.vim
@@ -149,6 +149,7 @@ func Run_SubCmd_Tests(tests)
for t in a:tests
let start = line('.') + 1
let end = start + len(t[2]) - 1
+ " TODO: why is there a one second delay the first time we get here?
exe "normal o" . t[0]
call cursor(start, 1)
exe t[1]
@@ -717,3 +718,12 @@ one two
close!
endfunc
+
+func Test_sub_beyond_end()
+ new
+ call setline(1, '#')
+ let @/ = '^#\n\zs'
+ s///e
+ call assert_equal('#', getline(1))
+ bwipe!
+endfunc
diff --git a/src/nvim/testdir/test_virtualedit.vim b/src/nvim/testdir/test_virtualedit.vim
index 67adede8d7..1e6b26a057 100644
--- a/src/nvim/testdir/test_virtualedit.vim
+++ b/src/nvim/testdir/test_virtualedit.vim
@@ -73,3 +73,12 @@ func Test_edit_CTRL_G()
bwipe!
set virtualedit=
endfunc
+
+func Test_edit_change()
+ new
+ set virtualedit=all
+ call setline(1, "\t⒌")
+ normal Cx
+ call assert_equal('x', getline(1))
+ bwipe!
+endfunc