aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml2
-rw-r--r--runtime/doc/api.txt3
-rw-r--r--runtime/lua/vim/_meta/api.lua1
-rw-r--r--runtime/lua/vim/filetype.lua2
-rw-r--r--runtime/lua/vim/lsp/util.lua42
-rw-r--r--runtime/syntax/masm.vim187
-rw-r--r--runtime/syntax/mojo.vim316
-rw-r--r--runtime/syntax/scala.vim2
-rw-r--r--src/nvim/api/buffer.c85
-rw-r--r--src/nvim/mouse.c14
-rw-r--r--test/functional/api/buffer_spec.lua704
-rw-r--r--test/functional/api/server_notifications_spec.lua3
-rw-r--r--test/functional/plugin/lsp_spec.lua2
-rw-r--r--test/functional/ui/statuscolumn_spec.lua18
-rw-r--r--test/old/testdir/check.vim8
-rw-r--r--test/old/testdir/test_filetype.vim1
-rw-r--r--test/old/testdir/test_functions.vim3
17 files changed, 1336 insertions, 57 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 20e5f0ad76..ab4bead7fb 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -6,7 +6,7 @@ freebsd_task:
name: FreeBSD
only_if: $BRANCH != "master"
freebsd_instance:
- image_family: freebsd-13-1
+ image_family: freebsd-13-2
timeout_in: 30m
install_script:
- pkg install -y cmake gmake ninja unzip wget gettext python git
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index 7dd760b6a5..c0bea52513 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -2438,6 +2438,8 @@ nvim_buf_set_text({buffer}, {start_row}, {start_col}, {end_row}, {end_col},
Prefer |nvim_buf_set_lines()| if you are only adding or deleting entire
lines.
+ Prefer |nvim_put()| if you want to insert text at the cursor position.
+
Attributes: ~
not allowed when |textlock| is active
@@ -2451,6 +2453,7 @@ nvim_buf_set_text({buffer}, {start_row}, {start_col}, {end_row}, {end_col},
See also: ~
• |nvim_buf_set_lines()|
+ • |nvim_put()|
nvim_buf_set_var({buffer}, {name}, {value}) *nvim_buf_set_var()*
Sets a buffer-scoped (b:) variable
diff --git a/runtime/lua/vim/_meta/api.lua b/runtime/lua/vim/_meta/api.lua
index c46b604b90..6c4e6c04d9 100644
--- a/runtime/lua/vim/_meta/api.lua
+++ b/runtime/lua/vim/_meta/api.lua
@@ -621,6 +621,7 @@ function vim.api.nvim_buf_set_option(buffer, name, value) end
--- range, use `replacement = {}`.
--- Prefer `nvim_buf_set_lines()` if you are only adding or deleting entire
--- lines.
+--- Prefer `nvim_put()` if you want to insert text at the cursor position.
---
--- @param buffer integer Buffer handle, or 0 for current buffer
--- @param start_row integer First line index
diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index 0e8ecf1b07..6fb6f475bc 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -669,6 +669,8 @@ local extension = {
m2 = 'modula2',
mi = 'modula2',
lm3 = 'modula3',
+ mojo = 'mojo',
+ ['🔥'] = 'mojo', -- 🙄
ssc = 'monk',
monk = 'monk',
tsc = 'monk',
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index e76fd15612..54721865b7 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -454,23 +454,6 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
end
end)
- -- Some LSP servers are depending on the VSCode behavior.
- -- The VSCode will re-locate the cursor position after applying TextEdit so we also do it.
- local is_current_buf = api.nvim_get_current_buf() == bufnr or bufnr == 0
- local cursor = (function()
- if not is_current_buf then
- return {
- row = -1,
- col = -1,
- }
- end
- local cursor = api.nvim_win_get_cursor(0)
- return {
- row = cursor[1] - 1,
- col = cursor[2],
- }
- end)()
-
-- save and restore local marks since they get deleted by nvim_buf_set_lines
local marks = {}
for _, m in pairs(vim.fn.getmarklist(bufnr or vim.api.nvim_get_current_buf())) do
@@ -480,7 +463,6 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
end
-- Apply text edits.
- local is_cursor_fixed = false
local has_eol_text_edit = false
for _, text_edit in ipairs(text_edits) do
-- Normalize line ending
@@ -527,20 +509,6 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
e.end_col = math.min(last_line_len, e.end_col)
api.nvim_buf_set_text(bufnr, e.start_row, e.start_col, e.end_row, e.end_col, e.text)
-
- -- Fix cursor position.
- local row_count = (e.end_row - e.start_row) + 1
- if e.end_row < cursor.row then
- cursor.row = cursor.row + (#e.text - row_count)
- is_cursor_fixed = true
- elseif e.end_row == cursor.row and e.end_col <= cursor.col then
- cursor.row = cursor.row + (#e.text - row_count)
- cursor.col = #e.text[#e.text] + (cursor.col - e.end_col)
- if #e.text == 1 then
- cursor.col = cursor.col + e.start_col
- end
- is_cursor_fixed = true
- end
end
end
@@ -560,16 +528,6 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
end
end
- -- Apply fixed cursor position.
- if is_cursor_fixed then
- local is_valid_cursor = true
- is_valid_cursor = is_valid_cursor and cursor.row < max
- is_valid_cursor = is_valid_cursor and cursor.col <= #(get_line(bufnr, cursor.row) or '')
- if is_valid_cursor then
- api.nvim_win_set_cursor(0, { cursor.row + 1, cursor.col })
- end
- end
-
-- Remove final line if needed
local fix_eol = has_eol_text_edit
fix_eol = fix_eol and (vim.bo[bufnr].eol or (vim.bo[bufnr].fixeol and not vim.bo[bufnr].binary))
diff --git a/runtime/syntax/masm.vim b/runtime/syntax/masm.vim
index 3be0fd45d1..85e457106d 100644
--- a/runtime/syntax/masm.vim
+++ b/runtime/syntax/masm.vim
@@ -2,7 +2,7 @@
" Language: Microsoft Macro Assembler (80x86)
" Orig Author: Rob Brady <robb@datatone.com>
" Maintainer: Wu Yongwei <wuyongwei@gmail.com>
-" Last Change: 2022-04-24 20:07:04 +0800
+" Last Change: 2023-09-09 20:48:26 +0800
" Quit when a syntax file was already loaded
if exists("b:current_syntax")
@@ -194,8 +194,8 @@ syn keyword masmRegister R8W R9W R10W R11W R12W R13W R14W R15W
syn keyword masmRegister R8B R9B R10B R11B R12B R13B R14B R15B
" SSE/AVX registers
-syn match masmRegister "\(X\|Y\)MM[0-9]\>"
-syn match masmRegister "\(X\|Y\)MM1[0-5]\>"
+syn match masmRegister "\(X\|Y\|Z\)MM[12]\?[0-9]\>"
+syn match masmRegister "\(X\|Y\|Z\)MM3[01]\>"
" Instruction prefixes
syn keyword masmOpcode LOCK REP REPE REPNE REPNZ REPZ
@@ -338,11 +338,192 @@ syn keyword masmOpcode VINSERTF128 VEXTRACTF128 VMASKMOVPS VMASKMOVPD
syn keyword masmOpcode VPERMILPS VPERMILPD VPERM2F128
syn keyword masmOpcode VZEROALL VZEROUPPER
+" AVX-2 (Haswell and later)
+syn keyword masmOpcode VPBROADCASTB VPBROADCASTW VPBROADCASTD
+syn keyword masmOpcode VPBROADCASTQ VBROADCASTI128
+syn keyword masmOpcode VINSERTI128 VEXTRACTI128
+syn keyword masmOpcode VGATHERDPD VGATHERQPD VGATHERDPS VGATHERQPS
+syn keyword masmOpcode VPGATHERDD VPGATHERDQ VPGATHERQD VPGATHERQQ
+syn keyword masmOpcode VPMASKMOVD VPMASKMOVQ
+syn keyword masmOpcode PERMPS VPERMD VPERMPD VPERMQ VPERM2I128
+syn keyword masmOpcode VPBLENDD VPSLLVD VPSLLVQ VPSRLVD VPSRLVQ
+syn keyword masmOpcode VPSRAVD
+
+" AVX-512 (Knights Landing/Skylake-X and later)
+syn keyword masmOpcode KAND KANDN KMOV KUNPCK KNOT KOR KORTEST
+syn keyword masmOpcode KSHIFTL KSHIFTR KXNOR KXOR KADD KTEST
+syn keyword masmOpcode VBLENDMPD VBLENDMPS
+syn keyword masmOpcode VPBLENDMD VPBLENDMQ VPBLENDMB VPBLENDMW
+syn keyword masmOpcode VPCMPD VPCMPUD VPCMPQ VPCMPUQ
+syn keyword masmOpcode VPCMPB VPCMPUB VPCMPW VPCMPUW
+syn keyword masmOpcode VPTESTMD VPTESTMQ VPTESTNMD VPTESTNMQ
+syn keyword masmOpcode VPTESTMB VPTESTMW VPTESTNMB VPTESTNMW
+syn keyword masmOpcode VCOMPRESSPD VCOMPRESSPS VPCOMPRESSD VPCOMPRESSQ
+syn keyword masmOpcode VEXPANDPD VEXPANDPS VPEXPANDD VPEXPANDQ
+syn keyword masmOpcode VPERMB VPERMW VPERMT2B VPERMT2W VPERMI2PD
+syn keyword masmOpcode VPERMI2PS VPERMI2D VPERMI2Q VPERMI2B VPERMI2W
+syn keyword masmOpcode VPERMT2PS VPERMT2PD VPERMT2D VPERMT2Q
+syn keyword masmOpcode VSHUFF32x4 VSHUFF64x2 VSHUFI32x4 VSHUFI64x2
+syn keyword masmOpcode VPMULTISHIFTQB VPTERNLOGD VPTERNLOGQ
+syn keyword masmOpcode VPMOVQD VPMOVSQD VPMOVUSQD VPMOVQW VPMOVSQW
+syn keyword masmOpcode VPMOVUSQW VPMOVQB VPMOVSQB VPMOVUSQB VPMOVDW
+syn keyword masmOpcode VPMOVSDW VPMOVUSDW VPMOVDB VPMOVSDB VPMOVUSDB
+syn keyword masmOpcode VPMOVWB VPMOVSWB VPMOVUSWB
+syn keyword masmOpcode VCVTPS2UDQ VCVTPD2UDQ VCVTTPS2UDQ VCVTTPD2UDQ
+syn keyword masmOpcode VCVTSS2USI VCVTSD2USI VCVTTSS2USI VCVTTSD2USI
+syn keyword masmOpcode VCVTPS2QQ VCVTPD2QQ VCVTPS2UQQ VCVTPD2UQQ
+syn keyword masmOpcode VCVTTPS2QQ VCVTTPD2QQ VCVTTPS2UQQ VCVTTPD2UQQ
+syn keyword masmOpcode VCVTUDQ2PS VCVTUDQ2PD VCVTUSI2PS VCVTUSI2PD
+syn keyword masmOpcode VCVTUSI2SD VCVTUSI2SS VCVTUQQ2PS VCVTUQQ2PD
+syn keyword masmOpcode VCVTQQ2PD VCVTQQ2PS VGETEXPPD
+syn keyword masmOpcode VGETEXPPS VGETEXPSD VGETEXPSS
+syn keyword masmOpcode VGETMANTPD VGETMANTPS VGETMANTSD VGETMANTSS
+syn keyword masmOpcode VFIXUPIMMPD VFIXUPIMMPS VFIXUPIMMSD VFIXUPIMMSS
+syn keyword masmOpcode VRCP14PD VRCP14PS VRCP14SD VRCP14SS
+syn keyword masmOpcode VRNDSCALEPS VRNDSCALEPD VRNDSCALESS VRNDSCALESD
+syn keyword masmOpcode VRSQRT14PD VRSQRT14PS VRSQRT14SD VRSQRT14SS
+syn keyword masmOpcode VSCALEFPS VSCALEFPD VSCALEFSS VSCALEFSD
+syn keyword masmOpcode VBROADCASTI32X2 VBROADCASTI32X4 VBROADCASTI32X8
+syn keyword masmOpcode VBROADCASTI64X2 VBROADCASTI64X4
+syn keyword masmOpcode VALIGND VALIGNQ VDBPSADBW VPABSQ VPMAXSQ
+syn keyword masmOpcode VPMAXUQ VPMINSQ VPMINUQ VPROLD VPROLVD VPROLQ
+syn keyword masmOpcode VPROLVQ VPRORD VPRORVD VPRORQ VPRORVQ
+syn keyword masmOpcode VPSCATTERDD VPSCATTERDQ VPSCATTERQD VPSCATTERQQ
+syn keyword masmOpcode VSCATTERDPS VSCATTERDPD VSCATTERQPS VSCATTERQPD
+syn keyword masmOpcode VPCONFLICTD VPCONFLICTQ VPLZCNTD VPLZCNTQ
+syn keyword masmOpcode VPBROADCASTMB2Q VPBROADCASTMW2D
+syn keyword masmOpcode VEXP2PD VEXP2PS
+syn keyword masmOpcode VRCP28PD VRCP28PS VRCP28SD VRCP28SS
+syn keyword masmOpcode VRSQRT28PD VRSQRT28PS VRSQRT28SD VRSQRT28SS
+syn keyword masmOpcode VGATHERPF0DPS VGATHERPF0QPS VGATHERPF0DPD
+syn keyword masmOpcode VGATHERPF0QPD VGATHERPF1DPS VGATHERPF1QPS
+syn keyword masmOpcode VGATHERPF1DPD VGATHERPF1QPD VSCATTERPF0DPS
+syn keyword masmOpcode VSCATTERPF0QPS VSCATTERPF0DPD VSCATTERPF0QPD
+syn keyword masmOpcode VSCATTERPF1DPS VSCATTERPF1QPS VSCATTERPF1DPD
+syn keyword masmOpcode VSCATTERPF1QPD
+syn keyword masmOpcode V4FMADDPS V4FMADDSS V4FNMADDPS V4FNMADDSS
+syn keyword masmOpcode VP4DPWSSD VP4DPWSSDS
+syn keyword masmOpcode VFPCLASSPS VFPCLASSPD VFPCLASSSS VFPCLASSSD
+syn keyword masmOpcode VRANGEPS VRANGEPD VRANGESS VRANGESD
+syn keyword masmOpcode VREDUCEPS VREDUCEPD VREDUCESS VREDUCESD
+syn keyword masmOpcode VPMOVM2D VPMOVM2Q VPMOVM2B VPMOVM2W VPMOVD2M
+syn keyword masmOpcode VPMOVQ2M VPMOVB2M VPMOVW2M VPMULLQ
+syn keyword masmOpcode VPCOMPRESSB VPCOMPRESSW VPEXPANDB VPEXPANDW
+syn keyword masmOpcode VPSHLD VPSHLDV VPSHRD VPSHRDV
+syn keyword masmOpcode VPDPBUSD VPDPBUSDS VPDPWSSD VPDPWSSDS
+syn keyword masmOpcode VPMADD52LUQ VPMADD52HUQ
+syn keyword masmOpcode VPOPCNTD VPOPCNTQ VPOPCNTB VPOPCNTW
+syn keyword masmOpcode VPSHUFBITQMB VP2INTERSECTD VP2INTERSECTQ
+syn keyword masmOpcode VGF2P8AFFINEINVQB VGF2P8AFFINEQB
+syn keyword masmOpcode VGF2P8MULB VPCLMULQDQ
+syn keyword masmOpcode VAESDEC VAESDECLAST VAESENC VAESENCLAST
+syn keyword masmOpcode VCVTNE2PS2BF16 VCVTNEPS2BF16 VDPBF16PS
+syn keyword masmOpcode VADDPH VADDSH VSUBPH VSUBSH VMULPH VMULSH
+syn keyword masmOpcode VDIVPH VDIVSH VSQRTPH VSQRTSH
+syn keyword masmOpcode VFMADD132PH VFMADD213PH VFMADD231PH
+syn keyword masmOpcode VFMADD132SH VFMADD213SH VFMADD231SH
+syn keyword masmOpcode VFNMADD132PH VFNMADD213PH VFNMADD231PH
+syn keyword masmOpcode VFNMADD132SH VFNMADD213SH VFNMADD231SH
+syn keyword masmOpcode VFMSUB132PH VFMSUB213PH VFMSUB231PH
+syn keyword masmOpcode VFMSUB132SH VFMSUB213SH VFMSUB231SH
+syn keyword masmOpcode VFNMSUB132PH VFNMSUB213PH VFNMSUB231PH
+syn keyword masmOpcode VFNMSUB132SH VFNMSUB213SH VFNMSUB231SH
+syn keyword masmOpcode VFMADDSUB132PH VFMADDSUB213PH VFMADDSUB231PH
+syn keyword masmOpcode VFMSUBADD132PH VFMSUBADD213PH VFMSUBADD231PH
+syn keyword masmOpcode VREDUCEPH VREDUCESH VRNDSCALEPH VRNDSCALESH
+syn keyword masmOpcode VSCALEFPH VSCALEFSH VFMULCPH VFMULCSH VFCMULCPH
+syn keyword masmOpcode VFCMULCSH VFMADDCPH VFMADDCSH VFCMADDCPH
+syn keyword masmOpcode VFCMADDCSH VRCPPH VRCPSH VRSQRTPH VRSQRTSH
+syn keyword masmOpcode VCMPPH VCMPSH VCOMISH VUCOMISH VMAXPH VMAXSH
+syn keyword masmOpcode VMINPH VMINSH VFPCLASSPH VFPCLASSSH
+syn keyword masmOpcode VCVTW2PH VCVTUW2PH VCVTDQ2PH VCVTUDQ2PH
+syn keyword masmOpcode VCVTQQ2PH VCVTUQQ2PH VCVTPS2PHX VCVTPD2PH
+syn keyword masmOpcode VCVTSI2SH VCVTUSI2SH VCVTSS2SH VCVTSD2SH
+syn keyword masmOpcode VCVTPH2W VCVTTPH2W VCVTPH2UW VCVTTPH2UW
+syn keyword masmOpcode VCVTPH2DQ VCVTTPH2DQ VCVTPH2UDQ VCVTTPH2UDQ
+syn keyword masmOpcode VCVTPH2QQ VCVTTPH2QQ VCVTPH2UQQ VCVTTPH2UQQ
+syn keyword masmOpcode VCVTPH2PSX VCVTPH2PD VCVTSH2SI VCVTTSH2SI
+syn keyword masmOpcode VCVTSH2USI VCVTTSH2USI VCVTSH2SS VCVTSH2SD
+syn keyword masmOpcode VGETEXPPH VGETEXPSH VGETMANTPH VGETMANTSH
+syn keyword masmOpcode VMOVSH VMOVW VADDPD VADDPS VADDSD VADDSS
+syn keyword masmOpcode VANDPD VANDPS VANDNPD VANDNPS
+syn keyword masmOpcode VCMPPD VCMPPS VCMPSD VCMPSS
+syn keyword masmOpcode VCOMISD VCOMISS VDIVPD VDIVPS VDIVSD VDIVSS
+syn keyword masmOpcode VCVTDQ2PD VCVTDQ2PS VCVTPD2DQ VCVTPD2PS
+syn keyword masmOpcode VCVTPH2PS VCVTPS2PH VCVTPS2DQ VCVTPS2PD
+syn keyword masmOpcode VCVTSD2SI VCVTSD2SS VCVTSI2SD VCVTSI2SS
+syn keyword masmOpcode VCVTSS2SD VCVTSS2SI VCVTTPD2DQ VCVTTPS2DQ
+syn keyword masmOpcode VCVTTSD2SI VCVTTSS2SI VMAXPD VMAXPS
+syn keyword masmOpcode VMAXSD VMAXSS VMINPD VMINPS VMINSD VMINSS
+syn keyword masmOpcode VMOVAPD VMOVAPS VMOVD VMOVQ VMOVDDUP
+syn keyword masmOpcode VMOVHLPS VMOVHPD VMOVHPS VMOVLHPS VMOVLPD
+syn keyword masmOpcode VMOVLPS VMOVNTDQA VMOVNTDQ VMOVNTPD VMOVNTPS
+syn keyword masmOpcode VMOVSD VMOVSHDUP VMOVSLDUP VMOVSS VMOVUPD
+syn keyword masmOpcode VMOVUPS VMOVDQA32 VMOVDQA64 VMOVDQU8
+syn keyword masmOpcode VMOVDQU16 VMOVDQU32 VMOVDQU64 VMULPD VMULPS
+syn keyword masmOpcode VMULSD VMULSS VORPD VORPS VSQRTPD VSQRTPS
+syn keyword masmOpcode VSQRTSD VSQRTSS VSUBPD VSUBPS VSUBSD VSUBSS
+syn keyword masmOpcode VUCOMISD VUCOMISS VUNPCKHPD VUNPCKHPS VUNPCKLPD
+syn keyword masmOpcode VUNPCKLPS VXORPD VXORPS VEXTRACTPS VINSERTPS
+syn keyword masmOpcode VPEXTRB VPEXTRW VPEXTRD VPEXTRQ VPINSRB VPINSRW
+syn keyword masmOpcode VPINSRD VPINSRQ VPACKSSWB VPACKSSDW VPACKUSDW
+syn keyword masmOpcode VPACKUSWB VPADDB VPADDW VPADDD VPADDQ VPADDSB
+syn keyword masmOpcode VPADDSW VPADDUSB VPADDUSW VPANDD VPANDQ VPANDND
+syn keyword masmOpcode VPANDNQ VPAVGB VPAVGW VPCMPEQB VPCMPEQW
+syn keyword masmOpcode VPCMPEQD VPCMPEQQ VPCMPGTB VPCMPGTW VPCMPGTD
+syn keyword masmOpcode VPCMPGTQ VPMAXSB VPMAXSW VPMAXSD VPMAXSQ
+syn keyword masmOpcode VPMAXUB VPMAXUW VPMAXUD VPMAXUQ VPMINSB VPMINSW
+syn keyword masmOpcode VPMINSD VPMINSQ VPMINUB VPMINUW VPMINUD VPMINUQ
+syn keyword masmOpcode VPMOVSXBW VPMOVSXBD VPMOVSXBQ VPMOVSXWD
+syn keyword masmOpcode VPMOVSXWQ VPMOVSXDQ VPMOVZXBW VPMOVZXBD
+syn keyword masmOpcode VPMOVZXBQ VPMOVZXWD VPMOVZXWQ VPMOVZXDQ VPMULDQ
+syn keyword masmOpcode VPMULUDQ VPMULHRSW VPMULHUW VPMULHW VPMULLD
+syn keyword masmOpcode VPMULLQ VPMULLW VPORD VPORQ VPSUBB VPSUBW
+syn keyword masmOpcode VPSUBD VPSUBQ VPSUBSB VPSUBSW VPSUBUSB VPSUBUSW
+syn keyword masmOpcode VPUNPCKHBW VPUNPCKHWD VPUNPCKHDQ VPUNPCKHQDQ
+syn keyword masmOpcode VPUNPCKLBW VPUNPCKLWD VPUNPCKLDQ VPUNPCKLQDQ
+syn keyword masmOpcode VPXORD VPXORQ VPSADBW VPSHUFB VPSHUFHW VPSHUFLW
+syn keyword masmOpcode VPSHUFD VPSLLDQ VPSLLW VPSLLD VPSLLQ VPSRAW
+syn keyword masmOpcode VPSRAD VPSRAQ VPSRLDQ VPSRLW VPSRLD VPSRLQ
+syn keyword masmOpcode VPSLLVW VPSRLVW VPSHUFPD VPSHUFPS VEXTRACTF32X4
+syn keyword masmOpcode VEXTRACTF64X2 VEXTRACTF32X8 VEXTRACTF64X4
+syn keyword masmOpcode VEXTRACTI32X4 VEXTRACTI64X2 VEXTRACTI32X8
+syn keyword masmOpcode VEXTRACTI64X4 VINSERTF32x4 VINSERTF64X2
+syn keyword masmOpcode VINSERTF32X8 VINSERTF64x4 VINSERTI32X4
+syn keyword masmOpcode VINSERTI64X2 VINSERTI32X8 VINSERTI64X4
+syn keyword masmOpcode VPABSB VPABSW VPABSD VPABSQ VPALIGNR
+syn keyword masmOpcode VPMADDUBSW VPMADDWD
+syn keyword masmOpcode VFMADD132PD VFMADD213PD VFMADD231PD
+syn keyword masmOpcode VFMADD132PS VFMADD213PS VFMADD231PS
+syn keyword masmOpcode VFMADD132SD VFMADD213SD VFMADD231SD
+syn keyword masmOpcode VFMADD132SS VFMADD213SS VFMADD231SS
+syn keyword masmOpcode VFMADDSUB132PD VFMADDSUB213PD VFMADDSUB231PD
+syn keyword masmOpcode VFMADDSUB132PS VFMADDSUB213PS VFMADDSUB231PS
+syn keyword masmOpcode VFMSUBADD132PD VFMSUBADD213PD VFMSUBADD231PD
+syn keyword masmOpcode VFMSUBADD132PS VFMSUBADD213PS VFMSUBADD231PS
+syn keyword masmOpcode VFMSUB132PD VFMSUB213PD VFMSUB231PD
+syn keyword masmOpcode VFMSUB132PS VFMSUB213PS VFMSUB231PS
+syn keyword masmOpcode VFMSUB132SD VFMSUB213SD VFMSUB231SD
+syn keyword masmOpcode VFMSUB132SS VFMSUB213SS VFMSUB231SS
+syn keyword masmOpcode VFNMADD132PD VFNMADD213PD VFNMADD231PD
+syn keyword masmOpcode VFNMADD132PS VFNMADD213PS VFNMADD231PS
+syn keyword masmOpcode VFNMADD132SD VFNMADD213SD VFNMADD231SD
+syn keyword masmOpcode VFNMADD132SS VFNMADD213SS VFNMADD231SS
+syn keyword masmOpcode VFNMSUB132PD VFNMSUB213PD VFNMSUB231PD
+syn keyword masmOpcode VFNMSUB132PS VFNMSUB213PS VFNMSUB231PS
+syn keyword masmOpcode VFNMSUB132SD VFNMSUB213SD VFNMSUB231SD
+syn keyword masmOpcode VFNMSUB132SS VFNMSUB213SS VFNMSUB231SS
+syn keyword masmOpcode VPSRAVW VPSRAVQ
+
" Other opcodes in Pentium and later processors
syn keyword masmOpcode CMPXCHG8B CPUID UD2
syn keyword masmOpcode RSM RDMSR WRMSR RDPMC RDTSC SYSENTER SYSEXIT
syn match masmOpcode "CMOV\(P[EO]\|\(N\?\([ABGL]E\?\|[CEOPSZ]\)\)\)\>"
+" Not really used by MASM, but useful for viewing GCC-generated assembly code
+" in Intel syntax
+syn match masmHexadecimal "[-+]\?0[Xx]\x*"
+syn keyword masmOpcode MOVABS
" The default highlighting
hi def link masmLabel PreProc
diff --git a/runtime/syntax/mojo.vim b/runtime/syntax/mojo.vim
new file mode 100644
index 0000000000..b7dae24a15
--- /dev/null
+++ b/runtime/syntax/mojo.vim
@@ -0,0 +1,316 @@
+" Vim syntax file
+" Language: Mojo
+" Maintainer: Mahmoud Abduljawad <me@mahmoudajawad.com>
+" Last Change: 2023 Sep 09
+" Credits: Mahmoud Abduljawad <me@mahmoudajawad.com>
+" Neil Schemenauer <nas@python.ca>
+" Dmitry Vasiliev
+"
+" This is based on Vim Python highlighting
+"
+" - introduced highlighting of doctests
+" - updated keywords, built-ins, and exceptions
+" - corrected regular expressions for
+"
+" * functions
+" * decorators
+" * strings
+" * escapes
+" * numbers
+" * space error
+"
+" - corrected synchronization
+" - more highlighting is ON by default, except
+" - space error highlighting is OFF by default
+"
+" Optional highlighting can be controlled using these variables.
+"
+" let mojo_no_builtin_highlight = 1
+" let mojo_no_doctest_code_highlight = 1
+" let mojo_no_doctest_highlight = 1
+" let mojo_no_exception_highlight = 1
+" let mojo_no_number_highlight = 1
+" let mojo_space_error_highlight = 1
+"
+" All the options above can be switched on together.
+"
+" let mojo_highlight_all = 1
+"
+" The use of Python 2 compatible syntax highlighting can be enforced.
+" The straddling code (Python 2 and 3 compatible), up to Python 3.5,
+" will be also supported.
+"
+" let mojo_use_python2_syntax = 1
+"
+" This option will exclude all modern Python 3.6 or higher features.
+"
+
+" quit when a syntax file was already loaded.
+if exists("b:current_syntax")
+ finish
+endif
+
+" We need nocompatible mode in order to continue lines with backslashes.
+" Original setting will be restored.
+let s:cpo_save = &cpo
+set cpo&vim
+
+if exists("mojo_no_doctest_highlight")
+ let mojo_no_doctest_code_highlight = 1
+endif
+
+if exists("mojo_highlight_all")
+ if exists("mojo_no_builtin_highlight")
+ unlet mojo_no_builtin_highlight
+ endif
+ if exists("mojo_no_doctest_code_highlight")
+ unlet mojo_no_doctest_code_highlight
+ endif
+ if exists("mojo_no_doctest_highlight")
+ unlet mojo_no_doctest_highlight
+ endif
+ if exists("mojo_no_exception_highlight")
+ unlet mojo_no_exception_highlight
+ endif
+ if exists("mojo_no_number_highlight")
+ unlet mojo_no_number_highlight
+ endif
+ let mojo_space_error_highlight = 1
+endif
+
+" These keywords are based on Python syntax highlight, and adds to it struct,
+" fn, alias, var, let
+"
+syn keyword mojoStatement False None True
+syn keyword mojoStatement as assert break continue del global
+syn keyword mojoStatement lambda nonlocal pass return with yield
+syn keyword mojoStatement class def nextgroup=mojoFunction skipwhite
+syn keyword mojoStatement struct fn nextgroup=mojoFunction skipwhite
+syn keyword mojoStatement alias var let
+syn keyword mojoConditional elif else if
+syn keyword mojoRepeat for while
+syn keyword mojoOperator and in is not or
+syn keyword mojoException except finally raise try
+syn keyword mojoInclude from import
+syn keyword mojoAsync async await
+
+" Soft keywords
+" These keywords do not mean anything unless used in the right context.
+" See https://docs.python.org/3/reference/lexical_analysis.html#soft-keywords
+" for more on this.
+syn match mojoConditional "^\s*\zscase\%(\s\+.*:.*$\)\@="
+syn match mojoConditional "^\s*\zsmatch\%(\s\+.*:\s*\%(#.*\)\=$\)\@="
+
+" Decorators
+" A dot must be allowed because of @MyClass.myfunc decorators.
+syn match mojoDecorator "@" display contained
+syn match mojoDecoratorName "@\s*\h\%(\w\|\.\)*" display contains=pythonDecorator
+
+" Python 3.5 introduced the use of the same symbol for matrix multiplication:
+" https://www.python.org/dev/peps/pep-0465/. We now have to exclude the
+" symbol from highlighting when used in that context.
+" Single line multiplication.
+syn match mojoMatrixMultiply
+ \ "\%(\w\|[])]\)\s*@"
+ \ contains=ALLBUT,mojoDecoratorName,mojoDecorator,mojoFunction,mojoDoctestValue
+ \ transparent
+" Multiplication continued on the next line after backslash.
+syn match mojoMatrixMultiply
+ \ "[^\\]\\\s*\n\%(\s*\.\.\.\s\)\=\s\+@"
+ \ contains=ALLBUT,mojoDecoratorName,mojoDecorator,mojoFunction,mojoDoctestValue
+ \ transparent
+" Multiplication in a parenthesized expression over multiple lines with @ at
+" the start of each continued line; very similar to decorators and complex.
+syn match mojoMatrixMultiply
+ \ "^\s*\%(\%(>>>\|\.\.\.\)\s\+\)\=\zs\%(\h\|\%(\h\|[[(]\).\{-}\%(\w\|[])]\)\)\s*\n\%(\s*\.\.\.\s\)\=\s\+@\%(.\{-}\n\%(\s*\.\.\.\s\)\=\s\+@\)*"
+ \ contains=ALLBUT,mojoDecoratorName,mojoDecorator,mojoFunction,mojoDoctestValue
+ \ transparent
+
+syn match mojoFunction "\h\w*" display contained
+
+syn match mojoComment "#.*$" contains=mojoTodo,@Spell
+syn keyword mojoTodo FIXME NOTE NOTES TODO XXX contained
+
+" Triple-quoted strings can contain doctests.
+syn region mojoString matchgroup=mojoQuotes
+ \ start=+[uU]\=\z(['"]\)+ end="\z1" skip="\\\\\|\\\z1"
+ \ contains=mojoEscape,@Spell
+syn region mojoString matchgroup=mojoTripleQuotes
+ \ start=+[uU]\=\z('''\|"""\)+ end="\z1" keepend
+ \ contains=mojoEscape,mojoSpaceError,mojoDoctest,@Spell
+syn region mojoRawString matchgroup=mojoQuotes
+ \ start=+[uU]\=[rR]\z(['"]\)+ end="\z1" skip="\\\\\|\\\z1"
+ \ contains=@Spell
+syn region mojoRawString matchgroup=pythonTripleQuotes
+ \ start=+[uU]\=[rR]\z('''\|"""\)+ end="\z1" keepend
+ \ contains=pythonSpaceError,mojoDoctest,@Spell
+
+syn match mojoEscape +\\[abfnrtv'"\\]+ contained
+syn match mojoEscape "\\\o\{1,3}" contained
+syn match mojoEscape "\\x\x\{2}" contained
+syn match mojoEscape "\%(\\u\x\{4}\|\\U\x\{8}\)" contained
+" Python allows case-insensitive Unicode IDs: http://www.unicode.org/charts/
+syn match mojoEscape "\\N{\a\+\%(\s\a\+\)*}" contained
+syn match mojoEscape "\\$"
+
+" It is very important to understand all details before changing the
+" regular expressions below or their order.
+" The word boundaries are *not* the floating-point number boundaries
+" because of a possible leading or trailing decimal point.
+" The expressions below ensure that all valid number literals are
+" highlighted, and invalid number literals are not. For example,
+"
+" - a decimal point in '4.' at the end of a line is highlighted,
+" - a second dot in 1.0.0 is not highlighted,
+" - 08 is not highlighted,
+" - 08e0 or 08j are highlighted,
+"
+" and so on, as specified in the 'Python Language Reference'.
+" https://docs.python.org/reference/lexical_analysis.html#numeric-literals
+if !exists("mojo_no_number_highlight")
+ " numbers (including complex)
+ syn match mojoNumber "\<0[oO]\%(_\=\o\)\+\>"
+ syn match mojoNumber "\<0[xX]\%(_\=\x\)\+\>"
+ syn match mojoNumber "\<0[bB]\%(_\=[01]\)\+\>"
+ syn match mojoNumber "\<\%([1-9]\%(_\=\d\)*\|0\+\%(_\=0\)*\)\>"
+ syn match mojoNumber "\<\d\%(_\=\d\)*[jJ]\>"
+ syn match mojoNumber "\<\d\%(_\=\d\)*[eE][+-]\=\d\%(_\=\d\)*[jJ]\=\>"
+ syn match mojoNumber
+ \ "\<\d\%(_\=\d\)*\.\%([eE][+-]\=\d\%(_\=\d\)*\)\=[jJ]\=\%(\W\|$\)\@="
+ syn match mojoNumber
+ \ "\%(^\|\W\)\zs\%(\d\%(_\=\d\)*\)\=\.\d\%(_\=\d\)*\%([eE][+-]\=\d\%(_\=\d\)*\)\=[jJ]\=\>"
+endif
+
+" The built-ins are added in the same order of appearance in Mojo stdlib docs
+" https://docs.modular.com/mojo/lib.html
+"
+if !exists("mojo_no_builtin_highlight")
+ " Built-in functions
+ syn keyword mojoBuiltin slice constrained debug_assert put_new_line print
+ syn keyword mojoBuiltin print_no_newline len range rebind element_type
+ syn keyword mojoBuiltin ord chr atol isdigit index address string
+ " Built-in types
+ syn keyword mojoType Byte ListLiteral CoroutineContext Coroutine DType
+ syn keyword mojoType dtype type invalid bool int8 si8 unit8 ui8 int16
+ syn keyword mojoType si16 unit16 ui16 int32 si32 uint32 ui32 int64
+ syn keyword mojoType si64 uint64 ui64 bfloat16 bf16 float16 f16 float32
+ syn keyword mojoType f32 float64 f64 Error FloatLiteral Int Attr SIMD
+ syn keyword mojoType Int8 UInt8 Int16 UInt16 Int32 UInt32 Int64 UInt64
+ syn keyword mojoType Float16 Float32 Float64 element_type _65x13_type
+ syn keyword mojoType String StringLiteral StringRef Tuple AnyType
+ syn keyword mojoType NoneType None Lifetime
+ " avoid highlighting attributes as builtins
+ syn match mojoAttribute /\.\h\w*/hs=s+1
+ \ contains=ALLBUT,mojoBuiltin,mojoFunction,mojoAsync
+ \ transparent
+endif
+
+" From the 'Python Library Reference' class hierarchy at the bottom.
+" http://docs.python.org/library/exceptions.html
+if !exists("mojo_no_exception_highlight")
+ " builtin base exceptions (used mostly as base classes for other exceptions)
+ syn keyword mojoExceptions BaseException Exception
+ syn keyword mojoExceptions ArithmeticError BufferError LookupError
+ " builtin exceptions (actually raised)
+ syn keyword mojoExceptions AssertionError AttributeError EOFError
+ syn keyword mojoExceptions FloatingPointError GeneratorExit ImportError
+ syn keyword mojoExceptions IndentationError IndexError KeyError
+ syn keyword mojoExceptions KeyboardInterrupt MemoryError
+ syn keyword mojoExceptions ModuleNotFoundError NameError
+ syn keyword mojoExceptions NotImplementedError OSError OverflowError
+ syn keyword mojoExceptions RecursionError ReferenceError RuntimeError
+ syn keyword mojoExceptions StopAsyncIteration StopIteration SyntaxError
+ syn keyword mojoExceptions SystemError SystemExit TabError TypeError
+ syn keyword mojoExceptions UnboundLocalError UnicodeDecodeError
+ syn keyword mojoExceptions UnicodeEncodeError UnicodeError
+ syn keyword mojoExceptions UnicodeTranslateError ValueError
+ syn keyword mojoExceptions ZeroDivisionError
+ " builtin exception aliases for OSError
+ syn keyword mojoExceptions EnvironmentError IOError WindowsError
+ " builtin OS exceptions in Python 3
+ syn keyword mojoExceptions BlockingIOError BrokenPipeError
+ syn keyword mojoExceptions ChildProcessError ConnectionAbortedError
+ syn keyword mojoExceptions ConnectionError ConnectionRefusedError
+ syn keyword mojoExceptions ConnectionResetError FileExistsError
+ syn keyword mojoExceptions FileNotFoundError InterruptedError
+ syn keyword mojoExceptions IsADirectoryError NotADirectoryError
+ syn keyword mojoExceptions PermissionError ProcessLookupError TimeoutError
+ " builtin warnings
+ syn keyword mojoExceptions BytesWarning DeprecationWarning FutureWarning
+ syn keyword mojoExceptions ImportWarning PendingDeprecationWarning
+ syn keyword mojoExceptions ResourceWarning RuntimeWarning
+ syn keyword mojoExceptions SyntaxWarning UnicodeWarning
+ syn keyword mojoExceptions UserWarning Warning
+endif
+
+if exists("mojo_space_error_highlight")
+ " trailing whitespace
+ syn match mojoSpaceError display excludenl "\s\+$"
+ " mixed tabs and spaces
+ syn match mojoSpaceError display " \+\t"
+ syn match mojoSpaceError display "\t\+ "
+endif
+
+" Do not spell doctests inside strings.
+" Notice that the end of a string, either ''', or """, will end the contained
+" doctest too. Thus, we do *not* need to have it as an end pattern.
+if !exists("mojo_no_doctest_highlight")
+ if !exists("mojo_no_doctest_code_highlight")
+ syn region mojoDoctest
+ \ start="^\s*>>>\s" end="^\s*$"
+ \ contained contains=ALLBUT,mojoDoctest,mojoFunction,@Spell
+ syn region mojoDoctestValue
+ \ start=+^\s*\%(>>>\s\|\.\.\.\s\|"""\|'''\)\@!\S\++ end="$"
+ \ contained
+ else
+ syn region mojoDoctest
+ \ start="^\s*>>>" end="^\s*$"
+ \ contained contains=@NoSpell
+ endif
+endif
+
+" Sync at the beginning of class, function, or method definition.
+syn sync match mojoSync grouphere NONE "^\%(def\|class\)\s\+\h\w*\s*[(:]"
+
+" The default highlight links. Can be overridden later.
+hi def link mojoStatement Statement
+hi def link mojoConditional Conditional
+hi def link mojoRepeat Repeat
+hi def link mojoOperator Operator
+hi def link mojoException Exception
+hi def link mojoInclude Include
+hi def link mojoAsync Statement
+hi def link mojoDecorator Define
+hi def link mojoDecoratorName Function
+hi def link mojoFunction Function
+hi def link mojoComment Comment
+hi def link mojoTodo Todo
+hi def link mojoString String
+hi def link mojoRawString String
+hi def link mojoQuotes String
+hi def link mojoTripleQuotes mojoQuotes
+hi def link mojoEscape Special
+if !exists("mojo_no_number_highlight")
+ hi def link mojoNumber Number
+endif
+if !exists("mojo_no_builtin_highlight")
+ hi def link mojoBuiltin Function
+ hi def link mojoType Type
+endif
+if !exists("mojo_no_exception_highlight")
+ hi def link mojoExceptions Structure
+endif
+if exists("mojo_space_error_highlight")
+ hi def link mojoSpaceError Error
+endif
+if !exists("mojo_no_doctest_highlight")
+ hi def link mojoDoctest Special
+ hi def link mojoDoctestValue Define
+endif
+
+let b:current_syntax = "mojo"
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
+
+" vim:set sw=2 sts=2 ts=8 noet:
diff --git a/runtime/syntax/scala.vim b/runtime/syntax/scala.vim
index c08e60e55a..cc098ce017 100644
--- a/runtime/syntax/scala.vim
+++ b/runtime/syntax/scala.vim
@@ -180,7 +180,7 @@ hi def link scalaNumber Number
syn region scalaRoundBrackets start="(" end=")" skipwhite contained contains=scalaTypeDeclaration,scalaSquareBrackets,scalaRoundBrackets
-syn region scalaSquareBrackets matchgroup=scalaSquareBracketsBrackets start="\[" end="\]" skipwhite nextgroup=scalaTypeExtension contains=scalaTypeDeclaration,scalaSquareBrackets,scalaTypeOperator,scalaTypeAnnotationParameter
+syn region scalaSquareBrackets matchgroup=scalaSquareBracketsBrackets start="\[" end="\]" skipwhite nextgroup=scalaTypeExtension contains=scalaTypeDeclaration,scalaSquareBrackets,scalaTypeOperator,scalaTypeAnnotationParameter,scalaString
syn match scalaTypeOperator /[-+=:<>]\+/ contained
syn match scalaTypeAnnotationParameter /@\<[`_A-Za-z0-9$]\+\>/ contained
hi def link scalaSquareBracketsBrackets Type
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index b8cb09ceb3..baac694848 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -504,7 +504,10 @@ end:
///
/// Prefer |nvim_buf_set_lines()| if you are only adding or deleting entire lines.
///
+/// Prefer |nvim_put()| if you want to insert text at the cursor position.
+///
/// @see |nvim_buf_set_lines()|
+/// @see |nvim_put()|
///
/// @param channel_id
/// @param buffer Buffer handle, or 0 for current buffer
@@ -725,11 +728,12 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In
FOR_ALL_TAB_WINDOWS(tp, win) {
if (win->w_buffer == buf) {
- // adjust cursor like an extmark ( i e it was inside last_part_len)
- if (win->w_cursor.lnum == end_row && win->w_cursor.col > end_col) {
- win->w_cursor.col -= col_extent - (colnr_T)last_item.size;
+ if (win->w_cursor.lnum >= start_row && win->w_cursor.lnum <= end_row) {
+ fix_cursor_cols(win, (linenr_T)start_row, (colnr_T)start_col, (linenr_T)end_row,
+ (colnr_T)end_col, (linenr_T)new_len, (colnr_T)last_item.size);
+ } else {
+ fix_cursor(win, (linenr_T)start_row, (linenr_T)end_row, (linenr_T)extra);
}
- fix_cursor(win, (linenr_T)start_row, (linenr_T)end_row, (linenr_T)extra);
}
}
@@ -1339,6 +1343,79 @@ static void fix_cursor(win_T *win, linenr_T lo, linenr_T hi, linenr_T extra)
invalidate_botline(win);
}
+/// Fix cursor position after replacing text
+/// between (start_row, start_col) and (end_row, end_col).
+///
+/// win->w_cursor.lnum is assumed to be >= start_row and <= end_row.
+static void fix_cursor_cols(win_T *win, linenr_T start_row, colnr_T start_col, linenr_T end_row,
+ colnr_T end_col, linenr_T new_rows, colnr_T new_cols_at_end_row)
+{
+ colnr_T mode_col_adj = win == curwin && (State & MODE_INSERT) ? 0 : 1;
+
+ colnr_T end_row_change_start = new_rows == 1 ? start_col : 0;
+ colnr_T end_row_change_end = end_row_change_start + new_cols_at_end_row;
+
+ // check if cursor is after replaced range or not
+ if (win->w_cursor.lnum == end_row && win->w_cursor.col + mode_col_adj > end_col) {
+ // if cursor is after replaced range, it's shifted
+ // to keep it's position the same, relative to end_col
+
+ linenr_T old_rows = end_row - start_row + 1;
+ win->w_cursor.lnum += new_rows - old_rows;
+ win->w_cursor.col += end_row_change_end - end_col;
+ } else {
+ // if cursor is inside replaced range
+ // and the new range got smaller,
+ // it's shifted to keep it inside the new range
+ //
+ // if cursor is before range or range did not
+ // got smaller, position is not changed
+
+ colnr_T old_coladd = win->w_cursor.coladd;
+
+ // it's easier to work with a single value here.
+ // col and coladd are fixed by a later call
+ // to check_cursor_col_win when necessary
+ win->w_cursor.col += win->w_cursor.coladd;
+ win->w_cursor.coladd = 0;
+
+ linenr_T new_end_row = start_row + new_rows - 1;
+
+ // make sure cursor row is in the new row range
+ if (win->w_cursor.lnum > new_end_row) {
+ win->w_cursor.lnum = new_end_row;
+
+ // don't simply move cursor up, but to the end
+ // of new_end_row, if it's not at or after
+ // it already (in case virtualedit is active)
+ // column might be additionally adjusted below
+ // to keep it inside col range if needed
+ colnr_T len = (colnr_T)strlen(ml_get_buf(win->w_buffer, new_end_row));
+ if (win->w_cursor.col < len) {
+ win->w_cursor.col = len;
+ }
+ }
+
+ // if cursor is at the last row and
+ // it wasn't after eol before, move it exactly
+ // to end_row_change_end
+ if (win->w_cursor.lnum == new_end_row
+ && win->w_cursor.col > end_row_change_end && old_coladd == 0) {
+ win->w_cursor.col = end_row_change_end;
+
+ // make sure cursor is inside range, not after it,
+ // except when doing so would move it before new range
+ if (win->w_cursor.col - mode_col_adj >= end_row_change_start) {
+ win->w_cursor.col -= mode_col_adj;
+ }
+ }
+ }
+
+ check_cursor_col_win(win);
+ changed_cline_bef_curs(win);
+ invalidate_botline(win);
+}
+
/// Initialise a string array either:
/// - on the Lua stack (as a table) (if lstate is not NULL)
/// - as an API array object (if lstate is NULL).
diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c
index 76ac191a68..b8c80cadf5 100644
--- a/src/nvim/mouse.c
+++ b/src/nvim/mouse.c
@@ -220,7 +220,10 @@ static int get_fpos_of_mouse(pos_T *mpos)
// compute the position in the buffer line from the posn on the screen
bool below_buffer = mouse_comp_pos(wp, &row, &col, &mpos->lnum);
- if (!below_buffer && *wp->w_p_stc != NUL && mouse_col < win_col_off(wp)) {
+ if (!below_buffer && *wp->w_p_stc != NUL
+ && (wp->w_p_rl
+ ? wincol >= wp->w_width_inner - win_col_off(wp)
+ : wincol < win_col_off(wp))) {
return MOUSE_STATUSCOL;
}
@@ -675,6 +678,10 @@ popupexit:
click_col = mouse_col;
}
+ if (in_statuscol && wp->w_p_rl) {
+ click_col = wp->w_width_inner - click_col - 1;
+ }
+
if (click_defs != NULL) {
switch (click_defs[click_col].type) {
case kStlClickDisabled:
@@ -1254,7 +1261,10 @@ retnomove:
on_sep_line = grid == DEFAULT_GRID_HANDLE && col >= wp->w_width && col - wp->w_width + 1 == 1;
on_winbar = row == -1 && wp->w_winbar_height != 0;
on_statuscol = !below_window && !on_status_line && !on_sep_line && !on_winbar
- && *wp->w_p_stc != NUL && col < win_col_off(wp);
+ && *wp->w_p_stc != NUL
+ && (wp->w_p_rl
+ ? col >= wp->w_width_inner - win_col_off(wp)
+ : col < win_col_off(wp));
// The rightmost character of the status line might be a vertical
// separator character if there is no connecting window to the right.
diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua
index 292e5a2d56..9833ebee4c 100644
--- a/test/functional/api/buffer_spec.lua
+++ b/test/functional/api/buffer_spec.lua
@@ -848,6 +848,710 @@ describe('api/buf', function()
eq({1, 4}, meths.win_get_cursor(win2))
end)
+ describe('when text is being added right at cursor position #22526', function()
+ it('updates the cursor position in NORMAL mode', function()
+ insert([[
+ abcd]])
+
+ -- position the cursor on 'c'
+ curwin('set_cursor', {1, 2})
+ -- add 'xxx' before 'c'
+ set_text(0, 2, 0, 2, {'xxx'})
+ eq({'abxxxcd'}, get_lines(0, -1, true))
+ -- cursor should be on 'c'
+ eq({1, 5}, curwin('get_cursor'))
+ end)
+
+ it('updates the cursor position only in non-current window when in INSERT mode', function()
+ insert([[
+ abcd]])
+
+ -- position the cursor on 'c'
+ curwin('set_cursor', {1, 2})
+ -- open vertical split
+ feed('<c-w>v')
+ -- get into INSERT mode to treat cursor
+ -- as being after 'b', not on 'c'
+ feed('i')
+ -- add 'xxx' between 'b' and 'c'
+ set_text(0, 2, 0, 2, {'xxx'})
+ eq({'abxxxcd'}, get_lines(0, -1, true))
+ -- in the current window cursor should stay after 'b'
+ eq({1, 2}, curwin('get_cursor'))
+ -- quit INSERT mode
+ feed('<esc>')
+ -- close current window
+ feed('<c-w>c')
+ -- in another window cursor should be on 'c'
+ eq({1, 5}, curwin('get_cursor'))
+ end)
+ end)
+
+ describe('when text is being deleted right at cursor position', function()
+ it('leaves cursor at the same position in NORMAL mode', function()
+ insert([[
+ abcd]])
+
+ -- position the cursor on 'b'
+ curwin('set_cursor', {1, 1})
+ -- delete 'b'
+ set_text(0, 1, 0, 2, {})
+ eq({'acd'}, get_lines(0, -1, true))
+ -- cursor is now on 'c'
+ eq({1, 1}, curwin('get_cursor'))
+ end)
+
+ it('leaves cursor at the same position in INSERT mode in current and non-current window', function()
+ insert([[
+ abcd]])
+
+ -- position the cursor on 'b'
+ curwin('set_cursor', {1, 1})
+ -- open vertical split
+ feed('<c-w>v')
+ -- get into INSERT mode to treat cursor
+ -- as being after 'a', not on 'b'
+ feed('i')
+ -- delete 'b'
+ set_text(0, 1, 0, 2, {})
+ eq({'acd'}, get_lines(0, -1, true))
+ -- cursor in the current window should stay after 'a'
+ eq({1, 1}, curwin('get_cursor'))
+ -- quit INSERT mode
+ feed('<esc>')
+ -- close current window
+ feed('<c-w>c')
+ -- cursor in non-current window should stay on 'c'
+ eq({1, 1}, curwin('get_cursor'))
+ end)
+ end)
+
+ describe('when cursor is inside replaced row range', function()
+ it('keeps cursor at the same position if cursor is at start_row, but before start_col', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position the cursor on ' ' before 'first'
+ curwin('set_cursor', {1, 14})
+
+ set_text(0, 15, 2, 11, {
+ 'the line we do not want',
+ 'but hopefully',
+ })
+
+ eq({
+ 'This should be the line we do not want',
+ 'but hopefully the last one',
+ }, get_lines(0, -1, true))
+ -- cursor should stay at the same position
+ eq({1, 14}, curwin('get_cursor'))
+ end)
+
+ it('keeps cursor at the same position if cursor is at start_row and column is still valid', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position the cursor on 'f' in 'first'
+ curwin('set_cursor', {1, 15})
+
+ set_text(0, 15, 2, 11, {
+ 'the line we do not want',
+ 'but hopefully',
+ })
+
+ eq({
+ 'This should be the line we do not want',
+ 'but hopefully the last one',
+ }, get_lines(0, -1, true))
+ -- cursor should stay at the same position
+ eq({1, 15}, curwin('get_cursor'))
+ end)
+
+ it('adjusts cursor column to keep it valid if start_row got smaller', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position the cursor on 't' in 'first'
+ curwin('set_cursor', {1, 19})
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 15, 2, 24, {'last'})
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({ 'This should be last' }, get_lines(0, -1, true))
+ -- cursor should end up on 't' in 'last'
+ eq({1, 18}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({1, 18}, cursor)
+ end)
+
+ it('adjusts cursor column to keep it valid if start_row got smaller in INSERT mode', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position the cursor on 't' in 'first'
+ curwin('set_cursor', {1, 19})
+ -- enter INSERT mode to treat cursor as being after 't'
+ feed('a')
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 15, 2, 24, {'last'})
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({ 'This should be last' }, get_lines(0, -1, true))
+ -- cursor should end up after 't' in 'last'
+ eq({1, 19}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({1, 19}, cursor)
+ end)
+
+ it('adjusts cursor column to keep it valid in a row after start_row if it got smaller', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position the cursor on 'w' in 'want'
+ curwin('set_cursor', {2, 31})
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 15, 2, 11, {
+ '1',
+ 'then 2',
+ 'and then',
+ })
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({
+ 'This should be 1',
+ 'then 2',
+ 'and then the last one',
+ }, get_lines(0, -1, true))
+ -- cursor column should end up at the end of a row
+ eq({2, 5}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({2, 5}, cursor)
+ end)
+
+ it('adjusts cursor column to keep it valid in a row after start_row if it got smaller in INSERT mode', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position the cursor on 'w' in 'want'
+ curwin('set_cursor', {2, 31})
+ -- enter INSERT mode
+ feed('a')
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 15, 2, 11, {
+ '1',
+ 'then 2',
+ 'and then',
+ })
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({
+ 'This should be 1',
+ 'then 2',
+ 'and then the last one',
+ }, get_lines(0, -1, true))
+ -- cursor column should end up at the end of a row
+ eq({2, 6}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({2, 6}, cursor)
+ end)
+
+ it('adjusts cursor line and column to keep it inside replacement range', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position the cursor on 'n' in 'finally'
+ curwin('set_cursor', {3, 6})
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 15, 2, 11, {
+ 'the line we do not want',
+ 'but hopefully',
+ })
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({
+ 'This should be the line we do not want',
+ 'but hopefully the last one',
+ }, get_lines(0, -1, true))
+ -- cursor should end up on 'y' in 'hopefully'
+ -- to stay in the range, because it got smaller
+ eq({2, 12}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({2, 12}, cursor)
+ end)
+
+ it('adjusts cursor line and column if replacement is empty', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position the cursor on 'r' in 'there'
+ curwin('set_cursor', {2, 8})
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 15, 2, 12, {})
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({ 'This should be the last one' }, get_lines(0, -1, true))
+ -- cursor should end up on the next column after deleted range
+ eq({1, 15}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({1, 15}, cursor)
+ end)
+
+ it('adjusts cursor line and column if replacement is empty and start_col == 0', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position the cursor on 'r' in 'there'
+ curwin('set_cursor', {2, 8})
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 0, 2, 4, {})
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({ 'finally the last one' }, get_lines(0, -1, true))
+ -- cursor should end up in column 0
+ eq({1, 0}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({1, 0}, cursor)
+ end)
+
+ it('adjusts cursor column if replacement ends at cursor row, after cursor column', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position the cursor on 'y' in 'finally'
+ curwin('set_cursor', {3, 10})
+ set_text(0, 15, 2, 11, { '1', 'this 2', 'and then' })
+
+ eq({
+ 'This should be 1',
+ 'this 2',
+ 'and then the last one',
+ }, get_lines(0, -1, true))
+ -- cursor should end up on 'n' in 'then'
+ eq({3, 7}, curwin('get_cursor'))
+ end)
+
+ it('adjusts cursor column if replacement ends at cursor row, at cursor column in INSERT mode', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position the cursor on 'y' at 'finally'
+ curwin('set_cursor', {3, 10})
+ -- enter INSERT mode to treat cursor as being between 'l' and 'y'
+ feed('i')
+ set_text(0, 15, 2, 11, { '1', 'this 2', 'and then' })
+
+ eq({
+ 'This should be 1',
+ 'this 2',
+ 'and then the last one',
+ }, get_lines(0, -1, true))
+ -- cursor should end up after 'n' in 'then'
+ eq({3, 8}, curwin('get_cursor'))
+ end)
+
+ it('adjusts cursor column if replacement is inside of a single line', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position the cursor on 'y' in 'finally'
+ curwin('set_cursor', {3, 10})
+ set_text(2, 4, 2, 11, { 'then' })
+
+ eq({
+ 'This should be first',
+ 'then there is a line we do not want',
+ 'and then the last one',
+ }, get_lines(0, -1, true))
+ -- cursor should end up on 'n' in 'then'
+ eq({3, 7}, curwin('get_cursor'))
+ end)
+
+ it('does not move cursor column after end of a line', function()
+ insert([[
+ This should be the only line here
+ !!!]])
+
+ -- position cursor on the last '1'
+ curwin('set_cursor', {2, 2})
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 33, 1, 3, {})
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({ 'This should be the only line here' }, get_lines(0, -1, true))
+ -- cursor should end up on '!'
+ eq({1, 32}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({1, 32}, cursor)
+ end)
+
+ it('does not move cursor column before start of a line', function()
+ insert('\n!!!')
+
+ -- position cursor on the last '1'
+ curwin('set_cursor', {2, 2})
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 0, 1, 3, {})
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({ '' }, get_lines(0, -1, true))
+ -- cursor should end up on '!'
+ eq({1, 0}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({1, 0}, cursor)
+ end)
+
+ describe('with virtualedit', function()
+ it('adjusts cursor line and column to keep it inside replacement range if cursor is not after eol', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position cursor on 't' in 'want'
+ curwin('set_cursor', {2, 34})
+ -- turn on virtualedit
+ command('set virtualedit=all')
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 15, 2, 11, {
+ 'the line we do not want',
+ 'but hopefully',
+ })
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({
+ 'This should be the line we do not want',
+ 'but hopefully the last one',
+ }, get_lines(0, -1, true))
+ -- cursor should end up on 'y' in 'hopefully'
+ -- to stay in the range
+ eq({2, 12}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({2, 12}, cursor)
+ -- coladd should be 0
+ eq(0, exec_lua([[
+ return vim.fn.winsaveview().coladd
+ ]]))
+ end)
+
+ it('does not change cursor screen column when cursor is after eol and row got shorter', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position cursor on 't' in 'want'
+ curwin('set_cursor', {2, 34})
+ -- turn on virtualedit
+ command('set virtualedit=all')
+ -- move cursor after eol
+ exec_lua([[
+ vim.fn.winrestview({ coladd = 5 })
+ ]])
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 15, 2, 11, {
+ 'the line we do not want',
+ 'but hopefully',
+ })
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({
+ 'This should be the line we do not want',
+ 'but hopefully the last one',
+ }, get_lines(0, -1, true))
+ -- cursor should end up at eol of a new row
+ eq({2, 26}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({2, 26}, cursor)
+ -- coladd should be increased so that cursor stays in the same screen column
+ eq(13, exec_lua([[
+ return vim.fn.winsaveview().coladd
+ ]]))
+ end)
+
+ it('does not change cursor screen column when cursor is after eol and row got longer', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position cursor on 't' in 'first'
+ curwin('set_cursor', {1, 19})
+ -- turn on virtualedit
+ command('set virtualedit=all')
+ -- move cursor after eol
+ exec_lua([[
+ vim.fn.winrestview({ coladd = 21 })
+ ]])
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 15, 2, 11, {
+ 'the line we do not want',
+ 'but hopefully',
+ })
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({
+ 'This should be the line we do not want',
+ 'but hopefully the last one',
+ }, get_lines(0, -1, true))
+ -- cursor should end up at eol of a new row
+ eq({1, 38}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({1, 38}, cursor)
+ -- coladd should be increased so that cursor stays in the same screen column
+ eq(2, exec_lua([[
+ return vim.fn.winsaveview().coladd
+ ]]))
+ end)
+
+ it('does not change cursor screen column when cursor is after eol and row extended past cursor column', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position cursor on 't' in 'first'
+ curwin('set_cursor', {1, 19})
+ -- turn on virtualedit
+ command('set virtualedit=all')
+ -- move cursor after eol just a bit
+ exec_lua([[
+ vim.fn.winrestview({ coladd = 3 })
+ ]])
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 15, 2, 11, {
+ 'the line we do not want',
+ 'but hopefully',
+ })
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({
+ 'This should be the line we do not want',
+ 'but hopefully the last one',
+ }, get_lines(0, -1, true))
+ -- cursor should stay at the same screen column
+ eq({1, 22}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({1, 22}, cursor)
+ -- coladd should become 0
+ eq(0, exec_lua([[
+ return vim.fn.winsaveview().coladd
+ ]]))
+ end)
+
+ it('does not change cursor screen column when cursor is after eol and row range decreased', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and one more
+ and finally the last one]])
+
+ -- position cursor on 'e' in 'more'
+ curwin('set_cursor', {3, 11})
+ -- turn on virtualedit
+ command('set virtualedit=all')
+ -- move cursor after eol
+ exec_lua([[
+ vim.fn.winrestview({ coladd = 28 })
+ ]])
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 15, 3, 11, {
+ 'the line we do not want',
+ 'but hopefully',
+ })
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({
+ 'This should be the line we do not want',
+ 'but hopefully the last one',
+ }, get_lines(0, -1, true))
+ -- cursor should end up at eol of a new row
+ eq({2, 26}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({2, 26}, cursor)
+ -- coladd should be increased so that cursor stays in the same screen column
+ eq(13, exec_lua([[
+ return vim.fn.winsaveview().coladd
+ ]]))
+ end)
+ end)
+ end)
+
+ describe('when cursor is at end_row and after end_col', function()
+ it('adjusts cursor column when only a newline is added or deleted', function()
+ insert([[
+ first line
+ second
+ line]])
+
+ -- position the cursor on 'i'
+ curwin('set_cursor', {3, 2})
+ set_text(1, 6, 2, 0, {})
+ eq({'first line', 'second line'}, get_lines(0, -1, true))
+ -- cursor should stay on 'i'
+ eq({2, 8}, curwin('get_cursor'))
+
+ -- add a newline back
+ set_text(1, 6, 1, 6, {'', ''})
+ eq({'first line', 'second', ' line'}, get_lines(0, -1, true))
+ -- cursor should return back to the original position
+ eq({3, 2}, curwin('get_cursor'))
+ end)
+
+ it('adjusts cursor column if the range is not bound to either start or end of a line', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position the cursor on 'h' in 'the'
+ curwin('set_cursor', {3, 13})
+ set_text(0, 14, 2, 11, {})
+ eq({'This should be the last one'}, get_lines(0, -1, true))
+ -- cursor should stay on 'h'
+ eq({1, 16}, curwin('get_cursor'))
+ -- add deleted lines back
+ set_text(0, 14, 0, 14, {
+ ' first',
+ 'then there is a line we do not want',
+ 'and finally',
+ })
+ eq({
+ 'This should be first',
+ 'then there is a line we do not want',
+ 'and finally the last one',
+ }, get_lines(0, -1, true))
+ -- cursor should return back to the original position
+ eq({3, 13}, curwin('get_cursor'))
+ end)
+
+ it('adjusts cursor column if replacing lines in range, not just deleting and adding', function()
+ insert([[
+ This should be first
+ then there is a line we do not want
+ and finally the last one]])
+
+ -- position the cursor on 's' in 'last'
+ curwin('set_cursor', {3, 18})
+ set_text(0, 15, 2, 11, {
+ 'the line we do not want',
+ 'but hopefully',
+ })
+
+ eq({
+ 'This should be the line we do not want',
+ 'but hopefully the last one',
+ }, get_lines(0, -1, true))
+ -- cursor should stay on 's'
+ eq({2, 20}, curwin('get_cursor'))
+
+ set_text(0, 15, 1, 13, {
+ 'first',
+ 'then there is a line we do not want',
+ 'and finally',
+ })
+
+ eq({
+ 'This should be first',
+ 'then there is a line we do not want',
+ 'and finally the last one',
+ }, get_lines(0, -1, true))
+ -- cursor should return back to the original position
+ eq({3, 18}, curwin('get_cursor'))
+ end)
+
+ it('does not move cursor column after end of a line', function()
+ insert([[
+ This should be the only line here
+ ]])
+
+ -- position cursor at the empty line
+ curwin('set_cursor', {2, 0})
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 33, 1, 0, {'!'})
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({ 'This should be the only line here!' }, get_lines(0, -1, true))
+ -- cursor should end up on '!'
+ eq({1, 33}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({1, 33}, cursor)
+ end)
+
+ it('does not move cursor column before start of a line', function()
+ insert('\n')
+
+ eq({ '', '' }, get_lines(0, -1, true))
+
+ -- position cursor on the last '1'
+ curwin('set_cursor', {2, 2})
+
+ local cursor = exec_lua([[
+ vim.api.nvim_buf_set_text(0, 0, 0, 1, 0, {''})
+ return vim.api.nvim_win_get_cursor(0)
+ ]])
+
+ eq({ '' }, get_lines(0, -1, true))
+ -- cursor should end up on '!'
+ eq({1, 0}, curwin('get_cursor'))
+ -- immediate call to nvim_win_get_cursor should have returned the same position
+ eq({1, 0}, cursor)
+ end)
+ end)
+
it('can handle NULs', function()
set_text(0, 0, 0, 0, {'ab\0cd'})
eq('ab\0cd', curbuf_depr('get_line', 0))
diff --git a/test/functional/api/server_notifications_spec.lua b/test/functional/api/server_notifications_spec.lua
index 53642858b2..bc43f6564d 100644
--- a/test/functional/api/server_notifications_spec.lua
+++ b/test/functional/api/server_notifications_spec.lua
@@ -6,9 +6,7 @@ local eq, clear, eval, command, nvim, next_msg =
local meths = helpers.meths
local exec_lua = helpers.exec_lua
local retry = helpers.retry
-local is_ci = helpers.is_ci
local assert_alive = helpers.assert_alive
-local skip = helpers.skip
local testlog = 'Xtest-server-notify-log'
@@ -90,7 +88,6 @@ describe('notify', function()
end)
it('cancels stale events on channel close', function()
- skip(is_ci(), 'hangs on CI #14083 #15251')
local catchan = eval("jobstart(['cat'], {'rpc': v:true})")
local catpath = eval('exepath("cat")')
eq({id=catchan, argv={catpath}, stream='job', mode='rpc', client = {}}, exec_lua ([[
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index 3eb89b4556..e0a8badb67 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -1787,7 +1787,7 @@ describe('LSP', function()
eq({
'First line of text';
}, buf_lines(1))
- eq({ 1, 6 }, funcs.nvim_win_get_cursor(0))
+ eq({ 1, 17 }, funcs.nvim_win_get_cursor(0))
end)
it('fix the cursor row', function()
diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua
index ee235cd6b5..742976cbe2 100644
--- a/test/functional/ui/statuscolumn_spec.lua
+++ b/test/functional/ui/statuscolumn_spec.lua
@@ -532,6 +532,24 @@ describe('statuscolumn', function()
eq('0 3 r 7', eval("g:testvar"))
meths.input_mouse('right', 'press', '', 0, 3, 0)
eq('0 4 r 7', eval("g:testvar"))
+
+ command('rightbelow vsplit')
+ meths.input_mouse('left', 'press', '', 0, 0, 27)
+ eq('0 1 l 4', eval("g:testvar"))
+ meths.input_mouse('right', 'press', '', 0, 3, 27)
+ eq('0 1 r 7', eval("g:testvar"))
+ command('setlocal rightleft')
+ meths.input_mouse('left', 'press', '', 0, 0, 52)
+ eq('0 1 l 4', eval("g:testvar"))
+ meths.input_mouse('right', 'press', '', 0, 3, 52)
+ eq('0 1 r 7', eval("g:testvar"))
+ command('wincmd H')
+ meths.input_mouse('left', 'press', '', 0, 0, 25)
+ eq('0 1 l 4', eval("g:testvar"))
+ meths.input_mouse('right', 'press', '', 0, 3, 25)
+ eq('0 1 r 7', eval("g:testvar"))
+ command('close')
+
command('set laststatus=2 winbar=%f')
command('let g:testvar = ""')
-- Check that winbar click doesn't register as statuscolumn click
diff --git a/test/old/testdir/check.vim b/test/old/testdir/check.vim
index 281514db17..af1a80250c 100644
--- a/test/old/testdir/check.vim
+++ b/test/old/testdir/check.vim
@@ -100,6 +100,14 @@ func CheckLinux()
endif
endfunc
+" Command to check for not running on a BSD system.
+command CheckNotBSD call CheckNotBSD()
+func CheckNotBSD()
+ if has('bsd')
+ throw 'Skipped: does not work on BSD'
+ endif
+endfunc
+
" Command to check that making screendumps is supported.
" Caller must source screendump.vim
command CheckScreendump call CheckScreendump()
diff --git a/test/old/testdir/test_filetype.vim b/test/old/testdir/test_filetype.vim
index 1dd255ccf9..b2b6ad80bb 100644
--- a/test/old/testdir/test_filetype.vim
+++ b/test/old/testdir/test_filetype.vim
@@ -427,6 +427,7 @@ func s:GetFilenameChecks() abort
\ 'mrxvtrc': ['mrxvtrc', '.mrxvtrc'],
\ 'msidl': ['file.odl', 'file.mof'],
\ 'msql': ['file.msql'],
+ \ 'mojo': ['file.mojo', 'file.🔥'],
\ 'mupad': ['file.mu'],
\ 'mush': ['file.mush'],
\ 'muttrc': ['Muttngrc', 'Muttrc', '.muttngrc', '.muttngrc-file', '.muttrc', '.muttrc-file', '/.mutt/muttngrc', '/.mutt/muttngrc-file', '/.mutt/muttrc', '/.mutt/muttrc-file', '/.muttng/muttngrc', '/.muttng/muttngrc-file', '/.muttng/muttrc', '/.muttng/muttrc-file', '/etc/Muttrc.d/file', '/etc/Muttrc.d/file.rc', 'Muttngrc-file', 'Muttrc-file', 'any/.mutt/muttngrc', 'any/.mutt/muttngrc-file', 'any/.mutt/muttrc', 'any/.mutt/muttrc-file', 'any/.muttng/muttngrc', 'any/.muttng/muttngrc-file', 'any/.muttng/muttrc', 'any/.muttng/muttrc-file', 'any/etc/Muttrc.d/file', 'muttngrc', 'muttngrc-file', 'muttrc', 'muttrc-file'],
diff --git a/test/old/testdir/test_functions.vim b/test/old/testdir/test_functions.vim
index a811e01301..3e1e5a4816 100644
--- a/test/old/testdir/test_functions.vim
+++ b/test/old/testdir/test_functions.vim
@@ -290,6 +290,7 @@ endfunc
func Test_strptime()
CheckFunction strptime
+ CheckNotBSD
CheckNotMSWindows
if exists('$TZ')
@@ -305,6 +306,8 @@ func Test_strptime()
call assert_fails('call strptime()', 'E119:')
call assert_fails('call strptime("xxx")', 'E119:')
+ " This fails on BSD 14 and returns
+ " -2209078800 instead of 0
call assert_equal(0, strptime("%Y", ''))
call assert_equal(0, strptime("%Y", "xxx"))