aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin M. Keyes <justinkz@gmail.com>2025-02-26 14:31:03 -0800
committerGitHub <noreply@github.com>2025-02-26 14:31:03 -0800
commit4f42b69b4ad0d0034581d756ef9bcb0e55f3491d (patch)
tree0c40b6f8c3569e339d375cb5842820590c5f3103
parentf4921e2b7deb4812414998a521c33f920f571c20 (diff)
parent4a997a1732fdb7a1c99cadf780b789f1ac84d990 (diff)
downloadrneovim-4f42b69b4ad0d0034581d756ef9bcb0e55f3491d.tar.gz
rneovim-4f42b69b4ad0d0034581d756ef9bcb0e55f3491d.tar.bz2
rneovim-4f42b69b4ad0d0034581d756ef9bcb0e55f3491d.zip
Merge #32601 vim.text.indent()
-rw-r--r--runtime/doc/lua.txt35
-rw-r--r--runtime/doc/news.txt1
-rw-r--r--runtime/lua/vim/health.lua9
-rw-r--r--runtime/lua/vim/text.lua87
-rwxr-xr-xsrc/gen/gen_eval_files.lua12
-rw-r--r--src/gen/gen_help_html.lua22
-rw-r--r--src/nvim/CMakeLists.txt3
-rw-r--r--test/functional/editor/fold_spec.lua10
-rw-r--r--test/functional/ex_cmds/source_spec.lua4
-rw-r--r--test/functional/ex_cmds/swapfile_preserve_recover_spec.lua12
-rw-r--r--test/functional/legacy/036_regexp_character_classes_spec.lua35
-rw-r--r--test/functional/legacy/039_visual_block_mode_commands_spec.lua9
-rw-r--r--test/functional/legacy/061_undo_tree_spec.lua4
-rw-r--r--test/functional/legacy/eval_spec.lua5
-rw-r--r--test/functional/legacy/fold_spec.lua6
-rw-r--r--test/functional/legacy/listchars_spec.lua4
-rw-r--r--test/functional/lua/secure_spec.lua14
-rw-r--r--test/functional/lua/text_spec.lua132
-rw-r--r--test/functional/plugin/lsp/inlay_hint_spec.lua4
-rw-r--r--test/functional/testnvim.lua4
-rw-r--r--test/functional/treesitter/highlight_spec.lua16
-rw-r--r--test/functional/treesitter/node_spec.lua4
-rw-r--r--test/functional/treesitter/query_spec.lua28
-rw-r--r--test/functional/ui/float_spec.lua20
-rw-r--r--test/functional/ui/hlstate_spec.lua4
-rw-r--r--test/functional/ui/inccommand_user_spec.lua218
-rw-r--r--test/functional/ui/linematch_spec.lua69
-rw-r--r--test/functional/ui/popupmenu_spec.lua25
-rw-r--r--test/functional/ui/screen.lua5
-rw-r--r--test/functional/ui/searchhl_spec.lua42
-rw-r--r--test/testutil.lua26
31 files changed, 538 insertions, 331 deletions
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
index ef2125841d..300d809854 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -4624,6 +4624,41 @@ vim.text.hexencode({str}) *vim.text.hexencode()*
Return: ~
(`string`) Hex encoded string
+vim.text.indent({size}, {text}, {opts}) *vim.text.indent()*
+ Sets the indent (i.e. the common leading whitespace) of non-empty lines in
+ `text` to `size` spaces/tabs.
+
+ Indent is calculated by number of consecutive indent chars.
+ • The first indented, non-empty line decides the indent char (space/tab):
+ • `SPC SPC TAB …` = two-space indent.
+ • `TAB SPC …` = one-tab indent.
+ • Set `opts.expandtab` to treat tabs as spaces.
+
+ To "dedent" (remove the common indent), pass `size=0`: >lua
+ vim.print(vim.text.indent(0, ' a\n b\n'))
+<
+
+ To adjust relative-to an existing indent, call indent() twice: >lua
+ local indented, old_indent = vim.text.indent(0, ' a\n b\n')
+ indented = vim.text.indent(old_indent + 2, indented)
+ vim.print(indented)
+<
+
+ To ignore the final, blank line when calculating the indent, use gsub()
+ before calling indent(): >lua
+ local text = ' a\n b\n '
+ vim.print(vim.text.indent(0, (text:gsub('\n[\t ]+\n?$', '\n'))))
+<
+
+ Parameters: ~
+ • {size} (`integer`) Number of spaces.
+ • {text} (`string`) Text to indent.
+ • {opts} (`{ expandtab?: number }?`)
+
+ Return (multiple): ~
+ (`string`) Indented text.
+ (`integer`) Indent size before modification.
+
==============================================================================
Lua module: tohtml *vim.tohtml*
diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt
index 17de99730a..0d47c7adb9 100644
--- a/runtime/doc/news.txt
+++ b/runtime/doc/news.txt
@@ -321,6 +321,7 @@ LUA
• |vim.fs.relpath()| gets relative path compared to base path.
• |vim.fs.dir()| and |vim.fs.find()| now follow symbolic links by default,
the behavior can be turn off using the new `follow` option.
+• |vim.text.indent()| indents/dedents text.
OPTIONS
diff --git a/runtime/lua/vim/health.lua b/runtime/lua/vim/health.lua
index a265e2b901..0d42e8fed6 100644
--- a/runtime/lua/vim/health.lua
+++ b/runtime/lua/vim/health.lua
@@ -186,18 +186,13 @@ local function get_healthcheck(plugin_names)
return healthchecks
end
---- Indents lines *except* line 1 of a string if it contains newlines.
+--- Indents lines *except* line 1 of a multiline string.
---
--- @param s string
--- @param columns integer
--- @return string
local function indent_after_line1(s, columns)
- local lines = vim.split(s, '\n')
- local indent = string.rep(' ', columns)
- for i = 2, #lines do
- lines[i] = indent .. lines[i]
- end
- return table.concat(lines, '\n')
+ return (vim.text.indent(columns, s):gsub('^%s+', ''))
end
--- Changes ':h clipboard' to ':help |clipboard|'.
diff --git a/runtime/lua/vim/text.lua b/runtime/lua/vim/text.lua
index f910ab3a1d..93220a2e42 100644
--- a/runtime/lua/vim/text.lua
+++ b/runtime/lua/vim/text.lua
@@ -50,4 +50,91 @@ function M.hexdecode(enc)
return table.concat(str), nil
end
+--- Sets the indent (i.e. the common leading whitespace) of non-empty lines in `text` to `size`
+--- spaces/tabs.
+---
+--- Indent is calculated by number of consecutive indent chars.
+--- - The first indented, non-empty line decides the indent char (space/tab):
+--- - `SPC SPC TAB …` = two-space indent.
+--- - `TAB SPC …` = one-tab indent.
+--- - Set `opts.expandtab` to treat tabs as spaces.
+---
+--- To "dedent" (remove the common indent), pass `size=0`:
+--- ```lua
+--- vim.print(vim.text.indent(0, ' a\n b\n'))
+--- ```
+---
+--- To adjust relative-to an existing indent, call indent() twice:
+--- ```lua
+--- local indented, old_indent = vim.text.indent(0, ' a\n b\n')
+--- indented = vim.text.indent(old_indent + 2, indented)
+--- vim.print(indented)
+--- ```
+---
+--- To ignore the final, blank line when calculating the indent, use gsub() before calling indent():
+--- ```lua
+--- local text = ' a\n b\n '
+--- vim.print(vim.text.indent(0, (text:gsub('\n[\t ]+\n?$', '\n'))))
+--- ```
+---
+--- @param size integer Number of spaces.
+--- @param text string Text to indent.
+--- @param opts? { expandtab?: number }
+--- @return string # Indented text.
+--- @return integer # Indent size _before_ modification.
+function M.indent(size, text, opts)
+ vim.validate('size', size, 'number')
+ vim.validate('text', text, 'string')
+ vim.validate('opts', opts, 'table', true)
+ -- TODO(justinmk): `opts.prefix`, `predicate` like python https://docs.python.org/3/library/textwrap.html
+ opts = opts or {}
+ local tabspaces = opts.expandtab and (' '):rep(opts.expandtab) or nil
+
+ --- Minimum common indent shared by all lines.
+ local old_indent --[[@type number?]]
+ local prefix = tabspaces and ' ' or nil -- Indent char (space or tab).
+ --- Check all non-empty lines, capturing leading whitespace (if any).
+ --- @diagnostic disable-next-line: no-unknown
+ for line_ws, extra in text:gmatch('([\t ]*)([^\n]+)') do
+ line_ws = tabspaces and line_ws:gsub('[\t]', tabspaces) or line_ws
+ -- XXX: blank line will miss the last whitespace char in `line_ws`, so we need to check `extra`.
+ line_ws = line_ws .. (extra:match('^%s+$') or '')
+ if 0 == #line_ws then
+ -- Optimization: If any non-empty line has indent=0, there is no common indent.
+ old_indent = 0
+ break
+ end
+ prefix = prefix and prefix or line_ws:sub(1, 1)
+ local _, end_ = line_ws:find('^[' .. prefix .. ']+')
+ old_indent = math.min(old_indent or math.huge, end_ or 0)
+ end
+ -- Default to 0 if all lines are empty.
+ old_indent = old_indent or 0
+ prefix = prefix and prefix or ' '
+
+ if old_indent == size then
+ -- Optimization: if the indent is the same, return the text unchanged.
+ return text, old_indent
+ end
+
+ local new_indent = prefix:rep(size)
+
+ --- Replaces indentation of a line.
+ --- @param line string
+ local function replace_line(line)
+ -- Match the existing indent exactly; avoid over-matching any following whitespace.
+ local pat = prefix:rep(old_indent)
+ -- Expand tabs before replacing indentation.
+ line = not tabspaces and line
+ or line:gsub('^[\t ]+', function(s)
+ return s:gsub('\t', tabspaces)
+ end)
+ -- Text following the indent.
+ local line_text = line:match('^' .. pat .. '(.*)') or line
+ return new_indent .. line_text
+ end
+
+ return (text:gsub('[^\n]+', replace_line)), old_indent
+end
+
return M
diff --git a/src/gen/gen_eval_files.lua b/src/gen/gen_eval_files.lua
index 74e45507e5..f99f6bafbd 100755
--- a/src/gen/gen_eval_files.lua
+++ b/src/gen/gen_eval_files.lua
@@ -766,18 +766,8 @@ local function scope_more_doc(o)
end
--- @param x string
---- @return string
local function dedent(x)
- local xs = split(x)
- local leading_ws = xs[1]:match('^%s*') --[[@as string]]
- local leading_ws_pat = '^' .. leading_ws
-
- for i in ipairs(xs) do
- local strip_pat = xs[i]:match(leading_ws_pat) and leading_ws_pat or '^%s*'
- xs[i] = xs[i]:gsub(strip_pat, '')
- end
-
- return table.concat(xs, '\n')
+ return (vim.text.indent(0, (x:gsub('\n%s-([\n]?)$', '\n%1'))))
end
--- @return table<string,vim.option_meta>
diff --git a/src/gen/gen_help_html.lua b/src/gen/gen_help_html.lua
index 53a65fd65f..57210f6ac1 100644
--- a/src/gen/gen_help_html.lua
+++ b/src/gen/gen_help_html.lua
@@ -148,10 +148,6 @@ local function url_encode(s)
)
end
-local function expandtabs(s)
- return s:gsub('\t', (' '):rep(8)) --[[ @as string ]]
-end
-
local function to_titlecase(s)
local text = ''
for w in vim.gsplit(s, '[ \t]+') do
@@ -275,25 +271,13 @@ end
---
--- Blank lines (empty or whitespace-only) are ignored.
local function get_indent(s)
- local min_indent = nil
- for line in vim.gsplit(s, '\n') do
- if line and not is_blank(line) then
- local ws = expandtabs(line:match('^%s+') or '')
- min_indent = (not min_indent or ws:len() < min_indent) and ws:len() or min_indent
- end
- end
- return min_indent or 0
+ local _, indent = vim.text.indent(0, s, { expandtab = 8 })
+ return indent
end
--- Removes the common indent level, after expanding tabs to 8 spaces.
local function trim_indent(s)
- local indent_size = get_indent(s)
- local trimmed = ''
- for line in vim.gsplit(s, '\n') do
- line = expandtabs(line)
- trimmed = ('%s%s\n'):format(trimmed, line:sub(indent_size + 1))
- end
- return trimmed:sub(1, -2)
+ return vim.text.indent(0, s, { expandtab = 8 })
end
--- Gets raw buffer text in the node's range (+/- an offset), as a newline-delimited string.
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 8112045d11..36bcd5fbce 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -342,6 +342,7 @@ set(LUA_KEYMAP_MODULE_SOURCE ${NVIM_RUNTIME_DIR}/lua/vim/keymap.lua)
set(LUA_LOADER_MODULE_SOURCE ${NVIM_RUNTIME_DIR}/lua/vim/loader.lua)
set(LUA_OPTIONS_MODULE_SOURCE ${NVIM_RUNTIME_DIR}/lua/vim/_options.lua)
set(LUA_SHARED_MODULE_SOURCE ${NVIM_RUNTIME_DIR}/lua/vim/shared.lua)
+set(LUA_TEXT_MODULE_SOURCE ${NVIM_RUNTIME_DIR}/lua/vim/text.lua)
file(GLOB API_HEADERS CONFIGURE_DEPENDS api/*.h)
list(REMOVE_ITEM API_HEADERS ${CMAKE_CURRENT_LIST_DIR}/api/ui_events.in.h)
@@ -624,6 +625,7 @@ add_custom_command(
${LUA_DEFAULTS_MODULE_SOURCE} "vim._defaults"
${LUA_OPTIONS_MODULE_SOURCE} "vim._options"
${LUA_SHARED_MODULE_SOURCE} "vim.shared"
+ ${LUA_TEXT_MODULE_SOURCE} "vim.text"
DEPENDS
${CHAR_BLOB_GENERATOR}
${LUA_INIT_PACKAGES_MODULE_SOURCE}
@@ -637,6 +639,7 @@ add_custom_command(
${LUA_DEFAULTS_MODULE_SOURCE}
${LUA_OPTIONS_MODULE_SOURCE}
${LUA_SHARED_MODULE_SOURCE}
+ ${LUA_TEXT_MODULE_SOURCE}
VERBATIM
)
diff --git a/test/functional/editor/fold_spec.lua b/test/functional/editor/fold_spec.lua
index ee3f268a2a..2198a974f6 100644
--- a/test/functional/editor/fold_spec.lua
+++ b/test/functional/editor/fold_spec.lua
@@ -496,10 +496,12 @@ a]],
it("fdm=indent doesn't open folds when inserting lower foldlevel line", function()
insert([[
- insert an unindented line under this line
- keep the lines under this line folded
- keep this line folded 1
- keep this line folded 2
+ insert an unindented line under this line
+ keep the lines under this line folded
+ keep this line folded 1
+ keep this line folded 2
+
+ .
]])
command('set foldmethod=indent shiftwidth=2 noautoindent')
eq(1, fn.foldlevel(1))
diff --git a/test/functional/ex_cmds/source_spec.lua b/test/functional/ex_cmds/source_spec.lua
index dba158962f..8a15aa04d1 100644
--- a/test/functional/ex_cmds/source_spec.lua
+++ b/test/functional/ex_cmds/source_spec.lua
@@ -227,7 +227,7 @@ describe(':source', function()
feed('GVkk')
feed_command(':source')
- eq(' "\\ a\n \\ b', exec_lua('return _G.a'))
+ eq(' "\\ a\n \\ b', exec_lua('return _G.a'))
end)
it('whole buffer', function()
@@ -247,7 +247,7 @@ describe(':source', function()
feed_command(':source')
eq(12, eval('g:c'))
- eq(' \\ 1\n "\\ 2', exec_lua('return _G.a'))
+ eq(' \\ 1\n "\\ 2', exec_lua('return _G.a'))
eq(':source (no file)', api.nvim_get_var('sfile_value'))
eq(':source (no file)', api.nvim_get_var('stack_value'))
eq(':source (no file)', api.nvim_get_var('script_value'))
diff --git a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua
index 848db7d088..8eec02524e 100644
--- a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua
+++ b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua
@@ -152,6 +152,9 @@ describe('swapfile detection', function()
it('redrawing during prompt does not break treesitter', function()
local testfile = 'Xtest_swapredraw.lua'
+ finally(function()
+ os.remove(testfile)
+ end)
write_file(
testfile,
[[
@@ -194,8 +197,7 @@ pcall(vim.cmd.edit, 'Xtest_swapredraw.lua')
{100:vim.o.foldexpr} {100:=} {101:'v:lua.vim.treesitter.foldexpr()'} |
{102:+-- 3 lines: vim.defer_fn(function()·······························································}|
{104:pcall}{100:(vim.cmd.edit,} {101:'Xtest_swapredraw.lua'}{100:)} |
- |
- {105:~ }|*33
+ {105:~ }|*34
{106:Xtest_swapredraw.lua 1,1 All}|
|
]])
@@ -589,8 +591,10 @@ describe('quitting swapfile dialog on startup stops TUI properly', function()
api.nvim_chan_send(chan, 'q')
retry(nil, nil, function()
eq(
- { '', '[Process exited 1]', '' },
- eval("[1, 2, '$']->map({_, lnum -> getline(lnum)->trim(' ', 2)})")
+ { '[Process exited 1]' },
+ eval(
+ "[1, 2, '$']->map({_, lnum -> getline(lnum)->trim(' ', 2)})->filter({_, s -> !empty(trim(s))})"
+ )
)
end)
end)
diff --git a/test/functional/legacy/036_regexp_character_classes_spec.lua b/test/functional/legacy/036_regexp_character_classes_spec.lua
index 9c871e159c..febe6a36ce 100644
--- a/test/functional/legacy/036_regexp_character_classes_spec.lua
+++ b/test/functional/legacy/036_regexp_character_classes_spec.lua
@@ -6,6 +6,7 @@ local n = require('test.functional.testnvim')()
local clear, command, expect = n.clear, n.command, n.expect
local source, write_file = n.source, t.write_file
+--- @return string
local function sixlines(text)
local result = ''
for _ = 1, 6 do
@@ -16,6 +17,9 @@ end
local function diff(text, nodedent)
local fname = t.tmpname()
+ finally(function()
+ os.remove(fname)
+ end)
command('w! ' .. fname)
n.poke_eventloop()
local data = io.open(fname):read('*all')
@@ -24,7 +28,6 @@ local function diff(text, nodedent)
else
t.eq(t.dedent(text), data)
end
- os.remove(fname)
end
describe('character classes in regexp', function()
@@ -38,7 +41,7 @@ describe('character classes in regexp', function()
local punct4 = '{|}~'
local ctrl2 = '\127\128\130\144\155'
local iso_text = '\166\177\188\199\211\233' -- "¦±¼ÇÓé" in utf-8
- setup(function()
+ local function do_setup(no_dedent)
-- The original test32.in file was not in utf-8 encoding and did also
-- contain some control characters. We use lua escape sequences to write
-- them to the test file.
@@ -52,8 +55,9 @@ describe('character classes in regexp', function()
.. punct4
.. ctrl2
.. iso_text
- write_file('test36.in', sixlines(line))
- end)
+ write_file('test36.in', sixlines(line), no_dedent)
+ end
+ setup(do_setup)
before_each(function()
clear()
command('e test36.in')
@@ -288,16 +292,18 @@ describe('character classes in regexp', function()
ABCDEFGHIXYZ
ABCDEFGHIXYZ]])
end)
- it([["\%1l^#.*" does not match on a line starting with "#". (vim-patch:7.4.1305)]], function()
- source([[
+ pending(
+ [["\%1l^#.*" does not match on a line starting with "#". (vim-patch:7.4.1305)]],
+ function()
+ -- do_setup(true)
+ source([[
1 s/\%#=0\%1l^\t...//g
2 s/\%#=1\%2l^\t...//g
3 s/\%#=2\%3l^\t...//g
4 s/\%#=0\%4l^\t...//g
5 s/\%#=1\%5l^\t...//g
6 s/\%#=2\%6l^\t...//g]])
- diff(
- sixlines(
+ local text = sixlines(
string.sub(punct1, 1)
.. digits
.. punct2
@@ -308,8 +314,9 @@ describe('character classes in regexp', function()
.. ctrl2
.. iso_text
)
- )
- end)
+ diff(text)
+ end
+ )
it('does not convert character class ranges to an incorrect class', function()
source([[
1 s/\%#=0[0-z]//g
@@ -319,9 +326,9 @@ describe('character classes in regexp', function()
5 s/\%#=1[^0-z]//g
6 s/\%#=2[^0-z]//g
]])
- diff(
- string.rep(ctrl1 .. punct1 .. punct4 .. ctrl2 .. iso_text .. '\n', 3)
- .. string.rep(digits .. punct2 .. upper .. punct3 .. lower .. '\n', 3)
- )
+ local text = string.rep(ctrl1 .. punct1 .. punct4 .. ctrl2 .. iso_text .. '\n', 3)
+ .. string.rep(digits .. punct2 .. upper .. punct3 .. lower .. '\n', 3)
+ text = text:gsub('\t', ''):gsub('\n\t', '\n')
+ diff(text)
end)
end)
diff --git a/test/functional/legacy/039_visual_block_mode_commands_spec.lua b/test/functional/legacy/039_visual_block_mode_commands_spec.lua
index 9fbf5ae774..98bcfd8261 100644
--- a/test/functional/legacy/039_visual_block_mode_commands_spec.lua
+++ b/test/functional/legacy/039_visual_block_mode_commands_spec.lua
@@ -112,7 +112,8 @@ describe('Visual block mode', function()
line1
line2
line3
- ]])
+ .
+ ]])
-- Test for Visual block insert when virtualedit=all and utf-8 encoding.
feed_command('set ve=all')
@@ -123,7 +124,8 @@ describe('Visual block mode', function()
x line1
x line2
x line3
- ]])
+ .
+ ]])
-- Test for Visual block append when virtualedit=all.
feed('012l<C-v>jjAx<ESC>')
@@ -132,7 +134,8 @@ describe('Visual block mode', function()
x x line1
x x line2
x x line3
- ]])
+ .
+ ]])
end)
it('should make a selected part uppercase', function()
diff --git a/test/functional/legacy/061_undo_tree_spec.lua b/test/functional/legacy/061_undo_tree_spec.lua
index 4177f908a1..8feafa2cee 100644
--- a/test/functional/legacy/061_undo_tree_spec.lua
+++ b/test/functional/legacy/061_undo_tree_spec.lua
@@ -13,9 +13,7 @@ local eval = n.eval
local eq = t.eq
local function expect_empty_buffer()
- -- The space will be removed by t.dedent but is needed because dedent
- -- will fail if it can not find the common indent of the given lines.
- return expect(' ')
+ return expect('')
end
local function expect_line(line)
return eq(line, eval('getline(".")'))
diff --git a/test/functional/legacy/eval_spec.lua b/test/functional/legacy/eval_spec.lua
index 554af9418d..14375a7621 100644
--- a/test/functional/legacy/eval_spec.lua
+++ b/test/functional/legacy/eval_spec.lua
@@ -200,6 +200,7 @@ describe('eval', function()
abcFc=]])
end)
+ -- luacheck: ignore 611 (Line contains only whitespace)
it('appending NL with setreg()', function()
command('so test_eval_setup.vim')
@@ -222,6 +223,7 @@ describe('eval', function()
command([[call SetReg('D', "\n", 'l')]])
command([[call SetReg('E', "\n")]])
command([[call SetReg('F', "\n", 'b')]])
+ command("$put ='.'")
expect([[
{{{2 setreg('A', ']] .. '\000' .. [[')
@@ -256,7 +258,8 @@ describe('eval', function()
F: type ]] .. "\0220; value: abcF2\000 (['abcF2', '']), expr: abcF2\000" .. [[ (['abcF2', ''])
==
=abcF2=
- ]])
+
+ .]])
end)
it('setting and appending list with setreg()', function()
diff --git a/test/functional/legacy/fold_spec.lua b/test/functional/legacy/fold_spec.lua
index 2bad70e384..96ca1f4a07 100644
--- a/test/functional/legacy/fold_spec.lua
+++ b/test/functional/legacy/fold_spec.lua
@@ -62,10 +62,10 @@ describe('folding', function()
n.poke_eventloop()
screen:expect([[
- dd {{{ |
- ee {{{ }}} |
+ dd {{{ |
+ ee {{{ }}} |
{{{ |
- ff }}} |*2
+ ff }}} |*2
^ |
line 2 foldlevel=2 |
1 |*2
diff --git a/test/functional/legacy/listchars_spec.lua b/test/functional/legacy/listchars_spec.lua
index b4d07e03ef..76b2966443 100644
--- a/test/functional/legacy/listchars_spec.lua
+++ b/test/functional/legacy/listchars_spec.lua
@@ -62,12 +62,12 @@ describe("'listchars'", function()
..bb>---<<$
...cccc><$
dd........ee<<>-$
- <$
+ $
>-------aa>-----$
..bb>---..$
...cccc>.$
dd........ee..>-$
- .$]])
+ $]])
end)
it('works with :list', function()
diff --git a/test/functional/lua/secure_spec.lua b/test/functional/lua/secure_spec.lua
index b40b084ef9..cd3549fc8a 100644
--- a/test/functional/lua/secure_spec.lua
+++ b/test/functional/lua/secure_spec.lua
@@ -153,16 +153,16 @@ describe('vim.secure', function()
feed('v')
screen:expect {
grid = [[
- ^let g:foobar = 42 |
- {1:~ }|*2
- {2:]]
+ ^let g:foobar = 42 |
+ {1:~ }|*2
+ {2:]]
.. fn.fnamemodify(cwd, ':~')
.. pathsep
.. [[Xfile [RO]{MATCH:%s+}}|
- |
- {1:~ }|
- {4:[No Name] }|
- |
+ |
+ {1:~ }|
+ {4:[No Name] }|
+ |
]],
}
diff --git a/test/functional/lua/text_spec.lua b/test/functional/lua/text_spec.lua
index dd08a6ec04..7cdec39338 100644
--- a/test/functional/lua/text_spec.lua
+++ b/test/functional/lua/text_spec.lua
@@ -7,7 +7,133 @@ local eq = t.eq
describe('vim.text', function()
before_each(clear)
- describe('hexencode() and hexdecode()', function()
+ describe('indent()', function()
+ it('validation', function()
+ t.matches('size%: expected number, got string', t.pcall_err(vim.text.indent, 'x', 'x'))
+ t.matches('size%: expected number, got nil', t.pcall_err(vim.text.indent, nil, 'x'))
+ t.matches('opts%: expected table, got string', t.pcall_err(vim.text.indent, 0, 'x', 'z'))
+ end)
+
+ it('basic cases', function()
+ -- Basic cases.
+ eq({ '', 0 }, { vim.text.indent(0, '') })
+ eq({ '', 0 }, { vim.text.indent(2, '') })
+ eq({ ' a', 4 }, { vim.text.indent(2, ' a') })
+ eq({ ' a\n b', 4 }, { vim.text.indent(2, ' a\n b') })
+ eq({ '\t\ta', 1 }, { vim.text.indent(2, '\ta') })
+ eq({ ' a\n\n', 5 }, { vim.text.indent(1, ' a\n\n') })
+ -- Indent 1 (tab) => 0. Starting with empty + blank lines.
+ eq({ '\n\naa a aa', 1 }, { vim.text.indent(0, '\n \n aa a aa') })
+ -- Indent 1 (tab) => 2 (tabs). Starting with empty + blank lines, 1-tab indent.
+ eq({ '\n\t\t\n\t\taa a aa', 1 }, { vim.text.indent(2, '\n\t\n\taa a aa') })
+
+ -- Indent 4 => 2, expandtab=false preserves tabs after the common indent.
+ eq(
+ { ' foo\n bar\n \tbaz\n', 4 },
+ { vim.text.indent(2, ' foo\n bar\n \tbaz\n') }
+ )
+ -- Indent 9 => 3, expandtab=true.
+ eq(
+ { ' foo\n\n bar \t baz\n', 9 },
+ { vim.text.indent(3, '\t foo\n\n bar \t baz\n', { expandtab = 8 }) }
+ )
+ -- Indent 9 => 8, expandtab=true.
+ eq(
+ { ' foo\n\n bar\n', 9 },
+ { vim.text.indent(8, '\t foo\n\n bar\n', { expandtab = 8 }) }
+ )
+ -- Dedent: 5 => 0.
+ eq({ ' foo\n\nbar\n', 5 }, { vim.text.indent(0, ' foo\n\n bar\n') })
+ -- Dedent: 1 => 0. Empty lines are ignored when deciding "common indent".
+ eq(
+ { ' \n \nfoo\n\nbar\nbaz\n \n', 1 },
+ { vim.text.indent(0, ' \n \n foo\n\n bar\n baz\n \n') }
+ )
+ end)
+
+ it('real-world cases', function()
+ -- Dedent.
+ eq({
+ [[
+bufs:
+nvim args: 3
+lua args: {
+ [0] = "foo.lua"
+}
+]],
+ 10,
+ }, {
+ vim.text.indent(
+ 0,
+ [[
+ bufs:
+ nvim args: 3
+ lua args: {
+ [0] = "foo.lua"
+ }
+ ]]
+ ),
+ })
+
+ -- Indent 0 => 2.
+ eq({
+ [[
+ # yay
+
+ local function foo()
+ if true then
+ # yay
+ end
+ end
+
+ return
+]],
+ 0,
+ }, {
+ vim.text.indent(
+ 2,
+ [[
+# yay
+
+local function foo()
+ if true then
+ # yay
+ end
+end
+
+return
+]]
+ ),
+ })
+
+ -- 1-tab indent, last line spaces < tabsize.
+ -- Preserves tab char immediately following the indent.
+ eq({ 'text\n\tmatch\nmatch\ntext\n', 1 }, {
+ vim.text.indent(0, (([[
+ text
+ match
+ match
+ text
+]]):gsub('\n%s-([\n]?)$', '\n%1'))),
+ })
+
+ -- 1-tab indent, last line spaces=tabsize.
+ eq({ 'text\n match\nmatch\ntext\n', 6 }, {
+ vim.text.indent(
+ 0,
+ [[
+ text
+ match
+ match
+ text
+ ]],
+ { expandtab = 6 }
+ ),
+ })
+ end)
+ end)
+
+ describe('hexencode(), hexdecode()', function()
it('works', function()
local cases = {
{ 'Hello world!', '48656C6C6F20776F726C6421' },
@@ -21,13 +147,13 @@ describe('vim.text', function()
end
end)
- it('works with very large strings', function()
+ it('with very large strings', function()
local input, output = string.rep('😂', 2 ^ 16), string.rep('F09F9882', 2 ^ 16)
eq(output, vim.text.hexencode(input))
eq(input, vim.text.hexdecode(output))
end)
- it('errors on invalid input', function()
+ it('invalid input', function()
-- Odd number of hex characters
do
local res, err = vim.text.hexdecode('ABC')
diff --git a/test/functional/plugin/lsp/inlay_hint_spec.lua b/test/functional/plugin/lsp/inlay_hint_spec.lua
index fc6c3f46f7..eefcf825b8 100644
--- a/test/functional/plugin/lsp/inlay_hint_spec.lua
+++ b/test/functional/plugin/lsp/inlay_hint_spec.lua
@@ -316,13 +316,13 @@ test text
local grid_without_inlay_hints = [[
test text |
- ^ |
+ ^ |
|
]]
local grid_with_inlay_hints = [[
{1:01234}test text |
- ^ |
+ ^ |
|
]]
diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua
index 99d69e9287..89fa9115d9 100644
--- a/test/functional/testnvim.lua
+++ b/test/functional/testnvim.lua
@@ -609,12 +609,13 @@ function M._new_argv(...)
return args, env, io_extra
end
+--- Dedents string arguments and inserts the resulting text into the current buffer.
--- @param ... string
function M.insert(...)
nvim_feed('i')
for _, v in ipairs({ ... }) do
local escaped = v:gsub('<', '<lt>')
- M.feed(escaped)
+ M.feed(escaped) -- This also dedents :P
end
nvim_feed('<ESC>')
end
@@ -812,6 +813,7 @@ function M.rmdir(path)
end
end
+--- @deprecated Use `t.pcall_err()` to check failure, or `n.command()` to check success.
function M.exc_exec(cmd)
M.command(([[
try
diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua
index 6d59368a24..f3a321aa88 100644
--- a/test/functional/treesitter/highlight_spec.lua
+++ b/test/functional/treesitter/highlight_spec.lua
@@ -786,9 +786,9 @@ describe('treesitter highlighting (C)', function()
screen:expect({
grid = [[
- {26:int x = 4;} |
- {26:int y = 5;} |
- {26:int z = 6;} |
+ {26:int x = 4;} |
+ {26:int y = 5;} |
+ {26:int z = 6;} |
^ |
{1:~ }|*13
|
@@ -815,7 +815,7 @@ describe('treesitter highlighting (C)', function()
screen:expect({
grid = [[
- void foo(int {15:*}{25:bar}); |
+ void foo(int {15:*}{25:bar}); |
^ |
{1:~ }|*15
|
@@ -883,8 +883,8 @@ describe('treesitter highlighting (lua)', function()
screen:expect({
grid = [[
- {15:local} {25:ffi} {15:=} {16:require(}{26:'ffi'}{16:)} |
- {25:ffi}{16:.}{25:cdef}{16:(}{26:"}{16:int}{26: }{16:(}{15:*}{26:fun}{16:)(int,}{26: }{16:char}{26: }{15:*}{16:);}{26:"}{16:)} |
+ {15:local} {25:ffi} {15:=} {16:require(}{26:'ffi'}{16:)} |
+ {25:ffi}{16:.}{25:cdef}{16:(}{26:"}{16:int}{26: }{16:(}{15:*}{26:fun}{16:)(int,}{26: }{16:char}{26: }{15:*}{16:);}{26:"}{16:)} |
^ |
{1:~ }|*14
|
@@ -1185,7 +1185,7 @@ printf('Hello World!');
{18:```}{15:c} |
{25:printf}{16:(}{26:'Hello World!'}{16:);} |
{18:```} |
- ^ |
+ ^ |
|
]],
})
@@ -1271,7 +1271,7 @@ printf('Hello World!');
{8:120 }{25:printf}{16:(}{26:'Hello World!'}{16:);} |
{8:122 } |
{8:124 }{25:printf}{16:(}{26:'Hello World!'}{16:);} |
- {8:126 } ^ |
+ {8:126 }^ |
|
]])
end)
diff --git a/test/functional/treesitter/node_spec.lua b/test/functional/treesitter/node_spec.lua
index 2a1fa497af..2f6f810ef2 100644
--- a/test/functional/treesitter/node_spec.lua
+++ b/test/functional/treesitter/node_spec.lua
@@ -82,7 +82,7 @@ describe('treesitter node API', function()
]])
exec_lua(function()
- local parser = vim.treesitter.get_parser(0, 'c')
+ local parser = assert(vim.treesitter.get_parser(0, 'c'))
local tree = parser:parse()[1]
_G.root = tree:root()
vim.treesitter.language.inspect('c')
@@ -92,7 +92,7 @@ describe('treesitter node API', function()
end
end)
- exec_lua 'node = root:descendant_for_range(0, 11, 0, 16)'
+ exec_lua 'node = root:descendant_for_range(0, 9, 0, 14)'
eq('int x', lua_eval('node_text(node)'))
exec_lua 'node = node:next_sibling()'
diff --git a/test/functional/treesitter/query_spec.lua b/test/functional/treesitter/query_spec.lua
index 6db0ffe5a0..be9c60b8ad 100644
--- a/test/functional/treesitter/query_spec.lua
+++ b/test/functional/treesitter/query_spec.lua
@@ -386,8 +386,8 @@ void ui_refresh(void)
[[((primitive_type) @c-keyword (#any-of? @c-keyword "int" "float"))]]
)
eq({
- { 'c-keyword', 'primitive_type', { 2, 2, 2, 5 }, 'int' },
- { 'c-keyword', 'primitive_type', { 3, 4, 3, 7 }, 'int' },
+ { 'c-keyword', 'primitive_type', { 2, 0, 2, 3 }, 'int' },
+ { 'c-keyword', 'primitive_type', { 3, 2, 3, 5 }, 'int' },
}, res0)
local res1 = exec_lua(
@@ -401,9 +401,9 @@ void ui_refresh(void)
]]
)
eq({
- { 'fizzbuzz-strings', 'string_literal', { 6, 15, 6, 38 }, '"number= %d FizzBuzz\\n"' },
- { 'fizzbuzz-strings', 'string_literal', { 8, 15, 8, 34 }, '"number= %d Fizz\\n"' },
- { 'fizzbuzz-strings', 'string_literal', { 10, 15, 10, 34 }, '"number= %d Buzz\\n"' },
+ { 'fizzbuzz-strings', 'string_literal', { 6, 13, 6, 36 }, '"number= %d FizzBuzz\\n"' },
+ { 'fizzbuzz-strings', 'string_literal', { 8, 13, 8, 32 }, '"number= %d Fizz\\n"' },
+ { 'fizzbuzz-strings', 'string_literal', { 10, 13, 10, 32 }, '"number= %d Buzz\\n"' },
}, res1)
end)
@@ -608,9 +608,9 @@ void ui_refresh(void)
eq(
{
- { 0, 2, 0, 8 },
- { 1, 2, 1, 8 },
- { 2, 2, 2, 8 },
+ { 0, 0, 0, 6 },
+ { 1, 0, 1, 6 },
+ { 2, 0, 2, 6 },
},
test(
[[
@@ -636,9 +636,9 @@ void ui_refresh(void)
eq(
{
- { 0, 2, 0, 7 },
- { 1, 2, 1, 8 },
- { 2, 2, 2, 7 },
+ { 0, 0, 0, 5 },
+ { 1, 0, 1, 6 },
+ { 2, 0, 2, 5 },
},
test(
[[
@@ -675,9 +675,9 @@ void ui_refresh(void)
end)
eq({
- { 0, 2, 0, 12 },
- { 1, 2, 1, 12 },
- { 2, 2, 2, 12 },
+ { 0, 0, 0, 10 },
+ { 1, 0, 1, 10 },
+ { 2, 0, 2, 10 },
}, result)
end)
diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index 8155559d66..6610d25afb 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -2041,11 +2041,11 @@ describe('float window', function()
[2:----------------------------------------]|*6
[3:----------------------------------------]|
## grid 2
- neeed some dummy |
- background text |
- to show the effect |
- of color blending |
- of border shadow |
+ neeed some dummy |
+ background text |
+ to show the effect |
+ of color blending |
+ of border shadow |
^ |
## grid 3
|
@@ -2065,11 +2065,11 @@ describe('float window', function()
}}
else
screen:expect{grid=[[
- neeed some dummy |
- background text |
- to {1: halloj! }{23:e}ffect |
- of {1: BORDAA }{24:n}ding |
- of {23:b}{24:order sha}dow |
+ neeed some dummy |
+ background text |
+ to sh{1: halloj! }{23:f}ect |
+ of co{1: BORDAA }{24:i}ng |
+ of bo{23:r}{24:der shado}w |
^ |
|
]]}
diff --git a/test/functional/ui/hlstate_spec.lua b/test/functional/ui/hlstate_spec.lua
index e10c79fa48..e5b0d29f95 100644
--- a/test/functional/ui/hlstate_spec.lua
+++ b/test/functional/ui/hlstate_spec.lua
@@ -502,9 +502,7 @@ describe('ext_hlstate detailed highlights', function()
local num_lines = 500
insert('first line\n')
for _ = 1, num_lines do
- insert([[
- line
- ]])
+ api.nvim_paste(' line\n', false, -1)
end
insert('last line')
diff --git a/test/functional/ui/inccommand_user_spec.lua b/test/functional/ui/inccommand_user_spec.lua
index 3eee9a6e07..5d604d22d7 100644
--- a/test/functional/ui/inccommand_user_spec.lua
+++ b/test/functional/ui/inccommand_user_spec.lua
@@ -281,14 +281,14 @@ describe("'inccommand' for user commands", function()
]])
feed('<Esc>')
screen:expect([[
- text on line 1 |
- more text on line 2 |
- oh no, even more text |
- will the text ever stop |
- oh well |
- did the text stop |
- why won't it stop |
- make the text stop |
+ text on line 1 |
+ more text on line 2 |
+ oh no, even more text |
+ will the text ever stop |
+ oh well |
+ did the text stop |
+ why won't it stop |
+ make the text stop |
^ |
{1:~ }|*7
|
@@ -301,14 +301,14 @@ describe("'inccommand' for user commands", function()
command('set inccommand=nosplit')
feed(':Replace text cats')
screen:expect([[
- {10:cats} on line 1 |
- more {10:cats} on line 2 |
- oh no, even more {10:cats} |
- will the {10:cats} ever stop |
- oh well |
- did the {10:cats} stop |
- why won't it stop |
- make the {10:cats} stop |
+ {10:cats} on line 1 |
+ more {10:cats} on line 2 |
+ oh no, even more {10:cats} |
+ will the {10:cats} ever stop |
+ oh well |
+ did the {10:cats} stop |
+ why won't it stop |
+ make the {10:cats} stop |
|
{1:~ }|*7
:Replace text cats^ |
@@ -319,21 +319,21 @@ describe("'inccommand' for user commands", function()
command('set inccommand=split')
feed(':Replace text cats')
screen:expect([[
- {10:cats} on line 1 |
- more {10:cats} on line 2 |
- oh no, even more {10:cats} |
- will the {10:cats} ever stop |
- oh well |
- did the {10:cats} stop |
- why won't it stop |
- make the {10:cats} stop |
+ {10:cats} on line 1 |
+ more {10:cats} on line 2 |
+ oh no, even more {10:cats} |
+ will the {10:cats} ever stop |
+ oh well |
+ did the {10:cats} stop |
+ why won't it stop |
+ make the {10:cats} stop |
|
{3:[No Name] [+] }|
- |1| {10:cats} on line 1 |
- |2| more {10:cats} on line 2 |
- |3| oh no, even more {10:cats} |
- |4| will the {10:cats} ever stop |
- |6| did the {10:cats} stop |
+ |1| {10:cats} on line 1 |
+ |2| more {10:cats} on line 2 |
+ |3| oh no, even more {10:cats} |
+ |4| will the {10:cats} ever stop |
+ |6| did the {10:cats} stop |
{2:[Preview] }|
:Replace text cats^ |
]])
@@ -343,14 +343,14 @@ describe("'inccommand' for user commands", function()
command('set inccommand=split')
feed(':Replace text cats<Esc>')
screen:expect([[
- text on line 1 |
- more text on line 2 |
- oh no, even more text |
- will the text ever stop |
- oh well |
- did the text stop |
- why won't it stop |
- make the text stop |
+ text on line 1 |
+ more text on line 2 |
+ oh no, even more text |
+ will the text ever stop |
+ oh well |
+ did the text stop |
+ why won't it stop |
+ make the text stop |
^ |
{1:~ }|*7
|
@@ -361,14 +361,14 @@ describe("'inccommand' for user commands", function()
command('set inccommand=split')
feed(':Replace text cats<CR>')
screen:expect([[
- cats on line 1 |
- more cats on line 2 |
- oh no, even more cats |
- will the cats ever stop |
- oh well |
- did the cats stop |
- why won't it stop |
- make the cats stop |
+ cats on line 1 |
+ more cats on line 2 |
+ oh no, even more cats |
+ will the cats ever stop |
+ oh well |
+ did the cats stop |
+ why won't it stop |
+ make the cats stop |
^ |
{1:~ }|*7
:Replace text cats |
@@ -379,14 +379,14 @@ describe("'inccommand' for user commands", function()
command('set inccommand=split')
feed('gg:.Replace text cats')
screen:expect([[
- {10:cats} on line 1 |
- more text on line 2 |
- oh no, even more text |
- will the text ever stop |
- oh well |
- did the text stop |
- why won't it stop |
- make the text stop |
+ {10:cats} on line 1 |
+ more text on line 2 |
+ oh no, even more text |
+ will the text ever stop |
+ oh well |
+ did the text stop |
+ why won't it stop |
+ make the text stop |
|
{1:~ }|*7
:.Replace text cats^ |
@@ -432,14 +432,14 @@ describe("'inccommand' for user commands", function()
]])
feed(':C')
screen:expect([[
- {10: cats on line 1} |
- more cats on line 2 |
- oh no, even more cats |
- will the cats ever stop |
- oh well |
- did the cats stop |
- why won't it stop |
- make the cats stop |
+ {10:cats on line 1} |
+ more cats on line 2 |
+ oh no, even more cats |
+ will the cats ever stop |
+ oh well |
+ did the cats stop |
+ why won't it stop |
+ make the cats stop |
|
{1:~ }|*7
:C^ |
@@ -482,42 +482,42 @@ describe("'inccommand' for user commands", function()
]])
feed(':Test a.a.a.a.')
screen:expect([[
- text on line 1 |
- more text on line 2 |
- oh no, even more text |
- will the text ever stop |
- oh well |
- did the text stop |
- why won't it stop |
- make the text stop |
+ text on line 1 |
+ more text on line 2 |
+ oh no, even more text |
+ will the text ever stop |
+ oh well |
+ did the text stop |
+ why won't it stop |
+ make the text stop |
a.a.a.a. |
{1:~ }|*7
:Test a.a.a.a.^ |
]])
feed('<C-V><Esc>u')
screen:expect([[
- text on line 1 |
- more text on line 2 |
- oh no, even more text |
- will the text ever stop |
- oh well |
- did the text stop |
- why won't it stop |
- make the text stop |
+ text on line 1 |
+ more text on line 2 |
+ oh no, even more text |
+ will the text ever stop |
+ oh well |
+ did the text stop |
+ why won't it stop |
+ make the text stop |
a.a.a. |
{1:~ }|*7
:Test a.a.a.a.{18:^[}u^ |
]])
feed('<Esc>')
screen:expect([[
- text on line 1 |
- more text on line 2 |
- oh no, even more text |
- will the text ever stop |
- oh well |
- did the text stop |
- why won't it stop |
- make the text stop |
+ text on line 1 |
+ more text on line 2 |
+ oh no, even more text |
+ will the text ever stop |
+ oh well |
+ did the text stop |
+ why won't it stop |
+ make the text stop |
^ |
{1:~ }|*7
|
@@ -572,12 +572,12 @@ describe("'inccommand' for user commands", function()
screen:expect({
grid = [[
Preview |
- oh no, even more text |
- will the text ever stop |
- oh well |
- did the text stop |
- why won't it stop |
- make the text stop |
+ oh no, even more text |
+ will the text ever stop |
+ oh well |
+ did the text stop |
+ why won't it stop |
+ make the text stop |
|
{1:~ }|*8
:Test barb^az |
@@ -611,9 +611,9 @@ describe("'inccommand' with multiple buffers", function()
command('set inccommand=nosplit')
feed(':Replace foo bar')
screen:expect([[
- bar baz {10:bar} │ {10:bar} bar baz |
- baz {10:bar} bar │ bar baz {10:bar} |
- {10:bar} bar baz │ baz {10:bar} bar |
+ bar baz {10:bar} │{10:bar} bar baz |
+ baz {10:bar} bar │bar baz {10:bar} |
+ {10:bar} bar baz │baz {10:bar} bar |
│ |
{1:~ }│{1:~ }|*11
{3:[No Name] [+] }{2:[No Name] [+] }|
@@ -621,9 +621,9 @@ describe("'inccommand' with multiple buffers", function()
]])
feed('<CR>')
screen:expect([[
- bar baz bar │ bar bar baz |
- baz bar bar │ bar baz bar |
- bar bar baz │ baz bar bar |
+ bar baz bar │bar bar baz |
+ baz bar bar │bar baz bar |
+ bar bar baz │baz bar bar |
^ │ |
{1:~ }│{1:~ }|*11
{3:[No Name] [+] }{2:[No Name] [+] }|
@@ -635,19 +635,19 @@ describe("'inccommand' with multiple buffers", function()
command('set inccommand=split')
feed(':Replace foo bar')
screen:expect([[
- bar baz {10:bar} │ {10:bar} bar baz |
- baz {10:bar} bar │ bar baz {10:bar} |
- {10:bar} bar baz │ baz {10:bar} bar |
+ bar baz {10:bar} │{10:bar} bar baz |
+ baz {10:bar} bar │bar baz {10:bar} |
+ {10:bar} bar baz │baz {10:bar} bar |
│ |
{3:[No Name] [+] }{2:[No Name] [+] }|
Buffer #1: |
- |1| {10:bar} bar baz |
- |2| bar baz {10:bar} |
- |3| baz {10:bar} bar |
+ |1| {10:bar} bar baz |
+ |2| bar baz {10:bar} |
+ |3| baz {10:bar} bar |
Buffer #2: |
- |1| bar baz {10:bar} |
- |2| baz {10:bar} bar |
- |3| {10:bar} bar baz |
+ |1| bar baz {10:bar} |
+ |2| baz {10:bar} bar |
+ |3| {10:bar} bar baz |
|
{1:~ }|
{2:[Preview] }|
@@ -655,9 +655,9 @@ describe("'inccommand' with multiple buffers", function()
]])
feed('<CR>')
screen:expect([[
- bar baz bar │ bar bar baz |
- baz bar bar │ bar baz bar |
- bar bar baz │ baz bar bar |
+ bar baz bar │bar bar baz |
+ baz bar bar │bar baz bar |
+ bar bar baz │baz bar bar |
^ │ |
{1:~ }│{1:~ }|*11
{3:[No Name] [+] }{2:[No Name] [+] }|
diff --git a/test/functional/ui/linematch_spec.lua b/test/functional/ui/linematch_spec.lua
index 3593604c49..dc16036f21 100644
--- a/test/functional/ui/linematch_spec.lua
+++ b/test/functional/ui/linematch_spec.lua
@@ -95,8 +95,7 @@ describe('Diff mode screen with 3 diffs open', function()
{7: }{8: 9 }{4: BBB }│{7: }{8: 9 }{4: BBB }│{7: }{8: }{23:---------------------------}|
{7: }{8: 10 }{4: BBB }│{7: }{8: 10 }{4: BBB }│{7: }{8: }{23:---------------------------}|
{7: }{8: 11 }{4:>>>>>>> branch1 }│{7: }{8: 11 }{4:>>>>>>> branch1 }│{7: }{8: }{23:---------------------------}|
- {7: }{8: 12 } │{7: }{8: 12 } │{7: }{8: 6 } |
- {1:~ }│{1:~ }│{1:~ }|*2
+ {1:~ }│{1:~ }│{1:~ }|*3
{3:<-functional-diff-screen-1.3 [+] }{2:<est-functional-diff-screen-1.2 Xtest-functional-diff-screen-1 }|
:2,6diffget screen-1.2 |
]])
@@ -114,8 +113,7 @@ describe('Diff mode screen with 3 diffs open', function()
{7: }{8: 4 }{4: }{27:BBB}{4: }│{7: }{8: 6 }{4: }{27:BBB}{4: }│{7: }{8: 4 }{4: }{27:AAA}{4: }|
{7: }{8: 5 }{4: }{27:BBB}{4: }│{7: }{8: 7 }{4: }{27:BBB}{4: }│{7: }{8: 5 }{4: }{27:AAA}{4: }|
{7: }{8: }{23:---------------------------}│{7: }{8: 8 }{22:>>>>>>> branch1 }│{7: }{8: }{23:---------------------------}|
- {7: }{8: 6 } │{7: }{8: 9 } │{7: }{8: 6 } |
- {1:~ }│{1:~ }│{1:~ }|*5
+ {1:~ }│{1:~ }│{1:~ }|*6
{2:<test-functional-diff-screen-1.3 }{3:<functional-diff-screen-1.2 [+] }{2:Xtest-functional-diff-screen-1 }|
:5,7diffget screen-1.3 |
]])
@@ -136,8 +134,7 @@ describe('Diff mode screen with 3 diffs open', function()
{7: }{8: 4 } BBB │{7: }{8: 9 } BBB │{7: }{8: 8 } BBB |
{7: }{8: 5 } BBB │{7: }{8: 10 } BBB │{7: }{8: 9 } BBB |
{7: }{8: }{23:---------------------------}│{7: }{8: 11 }{4:>>>>>>> branch1 }│{7: }{8: 10 }{4:>>>>>>> branch1 }|
- {7: }{8: 6 } │{7: }{8: 12 } │{7: }{8: 11 } |
- {1:~ }│{1:~ }│{1:~ }|*2
+ {1:~ }│{1:~ }│{1:~ }|*3
{2:<test-functional-diff-screen-1.3 <est-functional-diff-screen-1.2 }{3:<st-functional-diff-screen-1 [+] }|
:5,6diffget screen-1.2 |
]])
@@ -158,8 +155,7 @@ describe('Diff mode screen with 3 diffs open', function()
{7: }{8: 4 }{4: BBB }│{7: }{8: 9 }{4: BBB }│{7: }{8: }{23:---------------------------}|
{7: }{8: 5 } BBB │{7: }{8: 10 } BBB │{7: }{8: 7 } BBB |
{7: }{8: }{23:---------------------------}│{7: }{8: 11 }{22:>>>>>>> branch1 }│{7: }{8: }{23:---------------------------}|
- {7: }{8: 6 } │{7: }{8: 12 } │{7: }{8: 8 } |
- {1:~ }│{1:~ }│{1:~ }|*2
+ {1:~ }│{1:~ }│{1:~ }|*3
{2:<test-functional-diff-screen-1.3 }{3:<est-functional-diff-screen-1.2 }{2:<st-functional-diff-screen-1 [+] }|
:6,8diffput screen-1 |
]])
@@ -179,8 +175,7 @@ describe('Diff mode screen with 3 diffs open', function()
{7: }{8: 4 } BBB │{7: }{8: 9 } BBB │{7: }{8: 8 } BBB |
{7: }{8: 5 } BBB │{7: }{8: 10 } BBB │{7: }{8: 9 } BBB |
{7: }{8: }{23:---------------------------}│{7: }{8: 11 }{4:>>>>>>> branch1 }│{7: }{8: 10 }{4:>>>>>>> branch1 }|
- {7: }{8: 6 } │{7: }{8: 12 } │{7: }{8: 11 } |
- {1:~ }│{1:~ }│{1:~ }|*2
+ {1:~ }│{1:~ }│{1:~ }|*3
{2:<test-functional-diff-screen-1.3 }{3:<est-functional-diff-screen-1.2 }{2:<st-functional-diff-screen-1 [+] }|
:6,11diffput screen-1 |
]])
@@ -276,8 +271,7 @@ something
{7: }{8: 14 }common line │{7: }{8: 15 }common line |
{7: }{8: }{23:-------------------------------------------}│{7: }{8: 16 }{22:DEF }|
{7: }{8: 15 }something │{7: }{8: 17 }something |
- {7: }{8: 16 } │{7: }{8: 18 } |
- {1:~ }│{1:~ }|*6
+ {1:~ }│{1:~ }|*7
{3:Xtest-functional-diff-screen-1.2 [+] }{2:Xtest-functional-diff-screen-1 }|
:5,9diffget |
]])
@@ -300,8 +294,7 @@ something
{7: }{8: 11 }common line │{7: }{8: 12 }common line |
{7: }{8: }{23:-------------------------------------------}│{7: }{8: 13 }{22:DEF }|
{7: }{8: 12 }something │{7: }{8: 14 }something |
- {7: }{8: 13 } │{7: }{8: 15 } |
- {1:~ }│{1:~ }|*3
+ {1:~ }│{1:~ }|*4
{2:Xtest-functional-diff-screen-1.2 }{3:Xtest-functional-diff-screen-1 [+] }|
:5,10diffget |
]])
@@ -322,8 +315,7 @@ something
{7: }{8: 10 }common line │{7: }{8: 10 }common line |
{7: }{8: 11 }common line │{7: }{8: 11 }common line |
{7: }{8: 12 }something │{7: }{8: 12 }something |
- {7: }{8: 13 } │{7: }{8: 13 } |
- {1:~ }│{1:~ }|*5
+ {1:~ }│{1:~ }|*6
{2:Xtest-functional-diff-screen-1.2 }{3:Xtest-functional-diff-screen-1 [+] }|
:4,17diffget |
]])
@@ -349,7 +341,7 @@ something
{7: }{8: 15 }common line │{7: }{8: 15 }common line |
{7: }{8: 16 }DEF │{7: }{8: 16 }DEF |
{7: }{8: 17 }something │{7: }{8: 17 }something |
- {7: }{8: 18 } │{7: }{8: 18 } |
+ {1:~ }│{1:~ }|
{3:Xtest-functional-diff-screen-1.2 [+] }{2:Xtest-functional-diff-screen-1 }|
:4,12diffget |
]])
@@ -376,7 +368,7 @@ something
{7: }{8: 11 }common line │{7: }{8: 15 }common line |
{7: }{8: }{23:-------------------------------------------}│{7: }{8: 16 }{22:DEF }|
{7: }{8: 12 }something │{7: }{8: 17 }something |
- {7: }{8: 13 } │{7: }{8: 18 } |
+ {1:~ }│{1:~ }|
{3:Xtest-functional-diff-screen-1.2 [+] }{2:Xtest-functional-diff-screen-1 }|
:e |
]])
@@ -403,7 +395,7 @@ something
{7: }{8: 11 }common line │{7: }{8: 15 }common line |
{7: }{8: }{23:-------------------------------------------}│{7: }{8: 16 }{22:DEF }|
{7: }{8: 12 }something │{7: }{8: 17 }something |
- {7: }{8: 13 } │{7: }{8: 18 } |
+ {1:~ }│{1:~ }|
{3:Xtest-functional-diff-screen-1.2 [+] }{2:Xtest-functional-diff-screen-1 }|
:e |
]])
@@ -430,7 +422,7 @@ something
{7: }{8: 11 }common line │{7: }{8: 15 }common line |
{7: }{8: }{23:-------------------------------------------}│{7: }{8: 16 }{22:DEF }|
{7: }{8: 12 }something │{7: }{8: 17 }something |
- {7: }{8: 13 } │{7: }{8: 18 } |
+ {1:~ }│{1:~ }|
{3:Xtest-functional-diff-screen-1.2 [+] }{2:Xtest-functional-diff-screen-1 }|
:e |
]])
@@ -457,7 +449,7 @@ something
{7: }{8: 12 }^common line │{7: }{8: 15 }common line |
{7: }{8: }{23:-------------------------------------------}│{7: }{8: 16 }{22:DEF }|
{7: }{8: 13 }something │{7: }{8: 17 }something |
- {7: }{8: 14 } │{7: }{8: 18 } |
+ {1:~ }│{1:~ }|
{3:Xtest-functional-diff-screen-1.2 [+] }{2:Xtest-functional-diff-screen-1 }|
:e |
]])
@@ -484,7 +476,7 @@ something
{7: }{8: 11 }common line │{7: }{8: 15 }common line |
{7: }{8: 12 }DEF │{7: }{8: 16 }DEF |
{7: }{8: 13 }^something │{7: }{8: 17 }something |
- {7: }{8: 14 } │{7: }{8: 18 } |
+ {1:~ }│{1:~ }|
{3:Xtest-functional-diff-screen-1.2 [+] }{2:Xtest-functional-diff-screen-1 }|
:e |
]])
@@ -511,7 +503,7 @@ something
{7: }{8: 11 }common line │{7: }{8: 15 }common line |
{7: }{8: }{23:-------------------------------------------}│{7: }{8: 16 }{22:DEF }|
{7: }{8: 12 }something │{7: }{8: 17 }something |
- {7: }{8: 13 } │{7: }{8: 18 } |
+ {1:~ }│{1:~ }|
{3:Xtest-functional-diff-screen-1.2 }{2:Xtest-functional-diff-screen-1 [+] }|
:e |
]])
@@ -538,7 +530,7 @@ something
{7: }{8: 11 }common line │{7: }{8: 15 }common line |
{7: }{8: }{23:-------------------------------------------}│{7: }{8: 16 }{22:DEF }|
{7: }{8: 12 }something │{7: }{8: 17 }something |
- {7: }{8: 13 } │{7: }{8: 18 } |
+ {1:~ }│{1:~ }|
{3:Xtest-functional-diff-screen-1.2 }{2:Xtest-functional-diff-screen-1 [+] }|
:e |
]])
@@ -565,7 +557,7 @@ something
{7: }{8: 11 }common line │{7: }{8: 15 }common line |
{7: }{8: }{23:-------------------------------------------}│{7: }{8: 16 }{22:DEF }|
{7: }{8: 12 }something │{7: }{8: 17 }something |
- {7: }{8: 13 } │{7: }{8: 18 } |
+ {1:~ }│{1:~ }|
{3:Xtest-functional-diff-screen-1.2 }{2:Xtest-functional-diff-screen-1 [+] }|
:e |
]])
@@ -591,7 +583,7 @@ something
{7: }{8: 11 }^common line │{7: }{8: 14 }common line |
{7: }{8: }{23:-------------------------------------------}│{7: }{8: 15 }{22:DEF }|
{7: }{8: 12 }something │{7: }{8: 16 }something |
- {7: }{8: 13 } │{7: }{8: 17 } |
+ {1:~ }│{1:~ }|
{1:~ }│{1:~ }|
{3:Xtest-functional-diff-screen-1.2 }{2:Xtest-functional-diff-screen-1 [+] }|
:e |
@@ -618,7 +610,7 @@ something
{7: }{8: }{23:-------------------------------------------}│{7: }{8: 14 }{22:DEF }|
{7: }{8: 11 }common line │{7: }{8: 15 }common line |
{7: }{8: 12 }^something │{7: }{8: 16 }something |
- {7: }{8: 13 } │{7: }{8: 17 } |
+ {1:~ }│{1:~ }|
{1:~ }│{1:~ }|
{3:Xtest-functional-diff-screen-1.2 }{2:Xtest-functional-diff-screen-1 [+] }|
:e |
@@ -646,7 +638,7 @@ something
{7: }{8: 14 }common line │{7: }{8: 15 }common line |
{7: }{8: }{23:-------------------------------------------}│{7: }{8: 16 }{22:DEF }|
{7: }{8: 15 }something │{7: }{8: 17 }something |
- {7: }{8: 16 } │{7: }{8: 18 } |
+ {1:~ }│{1:~ }|
{2:Xtest-functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }|
:e |
]])
@@ -673,7 +665,7 @@ something
{7: }{8: 14 }common line │{7: }{8: 15 }common line |
{7: }{8: }{23:-------------------------------------------}│{7: }{8: 16 }{22:DEF }|
{7: }{8: 15 }something │{7: }{8: 17 }something |
- {7: }{8: 16 } │{7: }{8: 18 } |
+ {1:~ }│{1:~ }|
{2:Xtest-functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }|
:e |
]])
@@ -700,7 +692,7 @@ something
{7: }{8: 11 }common line │{7: }{8: 15 }common line |
{7: }{8: }{23:-------------------------------------------}│{7: }{8: 16 }{22:DEF }|
{7: }{8: 12 }something │{7: }{8: 17 }something |
- {7: }{8: 13 } │{7: }{8: 18 } |
+ {1:~ }│{1:~ }|
{2:Xtest-functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }|
:e |
]])
@@ -727,7 +719,7 @@ something
{7: }{8: 11 }common line │{7: }{8: 15 }common line |
{7: }{8: 12 }DEF │{7: }{8: 16 }DEF |
{7: }{8: 13 }something │{7: }{8: 17 }^something |
- {7: }{8: 14 } │{7: }{8: 18 } |
+ {1:~ }│{1:~ }|
{2:Xtest-functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }|
:e |
]])
@@ -757,8 +749,7 @@ d
{7: }{8: 2 }{4:abc d }│{7: }{8: 1 }{27:// }{4:abc d }|
{7: }{8: 3 }{4:d }│{7: }{8: 2 }{27:// }{4:d }|
{7: }{8: }{23:-------------------------------------------}│{7: }{8: 3 }{22:// d }|
- {7: }{8: 4 } │{7: }{8: 4 } |
- {1:~ }│{1:~ }|*13
+ {1:~ }│{1:~ }|*14
{3:Xtest-functional-diff-screen-1.2 }{2:Xtest-functional-diff-screen-1 }|
:e |
]])
@@ -794,8 +785,7 @@ void testFunction () {
{7: }{8: 3 }{4: }{27:// }{4:} }│{7: }{8: 4 }{4: } }|
{7: }{8: }{23:-------------------------------------------}│{7: }{8: 5 }{22: } }|
{7: }{8: 4 }} │{7: }{8: 6 }} |
- {7: }{8: 5 } │{7: }{8: 7 } |
- {1:~ }│{1:~ }|*11
+ {1:~ }│{1:~ }|*12
{3:Xtest-functional-diff-screen-1.2 }{2:Xtest-functional-diff-screen-1 }|
:e |
]])
@@ -834,8 +824,7 @@ void testFunction () {
{7: }{8: 6 }{22:?B }│{7: }{8: }{23:--------------------------------------------}|
{7: }{8: 7 }{22:?B }│{7: }{8: }{23:--------------------------------------------}|
{7: }{8: 8 }{22:?C }│{7: }{8: }{23:--------------------------------------------}|
- {7: }{8: 9 } │{7: }{8: 4 } |
- {1:~ }│{1:~ }|*9
+ {1:~ }│{1:~ }|*10
{3:Xtest-functional-diff-screen-1.2 }{2:Xtest-functional-diff-screen-1 }|
:e |
]])
@@ -874,8 +863,7 @@ void testFunction () {
{7: }{8: 6 }{27:?}{4:B }│{7: }{8: 2 }{27:!}{4:B }|
{7: }{8: 7 }{27:?}{4:C }│{7: }{8: 3 }{27:!}{4:C }|
{7: }{8: 8 }{22:?C }│{7: }{8: }{23:--------------------------------------------}|
- {7: }{8: 9 } │{7: }{8: 4 } |
- {1:~ }│{1:~ }|*9
+ {1:~ }│{1:~ }|*10
{3:Xtest-functional-diff-screen-1.2 }{2:Xtest-functional-diff-screen-1 }|
:e |
]])
@@ -1017,8 +1005,7 @@ something
{7: }{8: 9 }HIL │{7: }{8: 9 }HIL |
{7: }{8: 10 }common line │{7: }{8: 10 }common line |
{7: }{8: 11 }something │{7: }{8: 11 }something |
- {7: }{8: 12 } │{7: }{8: 12 } |
- {1:~ }│{1:~ }|*6
+ {1:~ }│{1:~ }|*7
{3:Xtest-functional-diff-screen-1.2 [+] }{2:Xtest-functional-diff-screen-1 }|
:1,19diffget |
]])
diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
index fe093b67d5..375bc560dc 100644
--- a/test/functional/ui/popupmenu_spec.lua
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -2318,25 +2318,26 @@ describe('builtin popupmenu', function()
command('set completeopt+=noinsert')
command('set mouse=a')
insert([[
- Lorem ipsum dolor sit amet, consectetur
- adipisicing elit, sed do eiusmod tempor
- incididunt ut labore et dolore magna aliqua.
- Ut enim ad minim veniam, quis nostrud
- exercitation ullamco laboris nisi ut aliquip ex
- ea commodo consequat. Duis aute irure dolor in
- reprehenderit in voluptate velit esse cillum
- dolore eu fugiat nulla pariatur. Excepteur sint
- occaecat cupidatat non proident, sunt in culpa
- qui officia deserunt mollit anim id est
- laborum.
+ Lorem ipsum dolor sit amet, consectetur
+ adipisicing elit, sed do eiusmod tempor
+ incididunt ut labore et dolore magna aliqua.
+ Ut enim ad minim veniam, quis nostrud
+ exercitation ullamco laboris nisi ut aliquip ex
+ ea commodo consequat. Duis aute irure dolor in
+ reprehenderit in voluptate velit esse cillum
+ dolore eu fugiat nulla pariatur. Excepteur sint
+ occaecat cupidatat non proident, sunt in culpa
+ qui officia deserunt mollit anim id est
+ laborum.
+ .
]])
screen:expect([[
- reprehenderit in voluptate velit esse cillum |
dolore eu fugiat nulla pariatur. Excepteur sint |
occaecat cupidatat non proident, sunt in culpa |
qui officia deserunt mollit anim id est |
laborum. |
+ . |
^ |
{4:[No Name] [+] }|
Lorem ipsum dolor sit amet, consectetur |
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 934b4e9032..adc3080586 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -494,9 +494,8 @@ function Screen:expect(expected, attr_ids, ...)
local expected_rows = {} --- @type string[]
if grid then
- -- Remove the last line and dedent. Note that gsub returns more then one
- -- value.
- grid = dedent(grid:gsub('\n[ ]+$', ''), 0)
+ -- Dedent (ignores last line if it is blank).
+ grid = dedent(grid, 0)
for row in grid:gmatch('[^\n]+') do
table.insert(expected_rows, row)
end
diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua
index 86490b4527..5479cf6ee6 100644
--- a/test/functional/ui/searchhl_spec.lua
+++ b/test/functional/ui/searchhl_spec.lua
@@ -73,10 +73,10 @@ describe('search highlighting', function()
-- 'hlsearch' is enabled by default. #2859
feed('gg/text<cr>')
screen:expect([[
- some {2:^text} |
- more {2:text}stuff |
- stupid{2:texttext}stuff |
- a {2:text} word |
+ some {2:^text} |
+ more {2:text}stuff |
+ stupid{2:texttext}stuff |
+ a {2:text} word |
|
{1:~ }|
/text |
@@ -85,10 +85,10 @@ describe('search highlighting', function()
-- overlapping matches not allowed
feed('3nx')
screen:expect([[
- some {2:text} |
- more {2:text}stuff |
- stupid{2:text}^extstuff |
- a {2:text} word |
+ some {2:text} |
+ more {2:text}stuff |
+ stupid{2:text}^extstuff |
+ a {2:text} word |
|
{1:~ }|
/text |
@@ -96,10 +96,10 @@ describe('search highlighting', function()
feed('ggn*') -- search for entire word
screen:expect([[
- some {2:text} |
- more textstuff |
- stupidtextextstuff |
- a {2:^text} word |
+ some {2:text} |
+ more textstuff |
+ stupidtextextstuff |
+ a {2:^text} word |
|
{1:~ }|
/\<text\> |
@@ -107,10 +107,10 @@ describe('search highlighting', function()
feed_command('nohlsearch')
screen:expect([[
- some text |
- more textstuff |
- stupidtextextstuff |
- a ^text word |
+ some text |
+ more textstuff |
+ stupidtextextstuff |
+ a ^text word |
|
{1:~ }|
:nohlsearch |
@@ -641,7 +641,7 @@ describe('search highlighting', function()
feed_command('/ial te')
screen:expect {
grid = [[
- very {5:spec^ial}{2: te}{6:xt} |
+ very {5:spec^ial}{2: te}{6:xt} |
|
{1:~ }|*4
{4:search hit BOTTOM, continuing at TOP} |
@@ -652,7 +652,7 @@ describe('search highlighting', function()
topline = 0,
botline = 3,
curline = 0,
- curcol = 11,
+ curcol = 9,
linecount = 2,
sum_scroll_delta = 0,
},
@@ -670,7 +670,7 @@ describe('search highlighting', function()
}
command('%foldopen')
screen:expect([[
- very {5:spec^ial}{2: te}{6:xt} |
+ very {5:spec^ial}{2: te}{6:xt} |
|
{1:~ }|*4
{4:search hit BOTTOM, continuing at TOP} |
@@ -678,7 +678,7 @@ describe('search highlighting', function()
feed_command('call clearmatches()')
screen:expect([[
- very spec{2:^ial te}xt |
+ very spec{2:^ial te}xt |
|
{1:~ }|*4
:call clearmatches() |
@@ -688,7 +688,7 @@ describe('search highlighting', function()
-- nonconflicting attributes are combined
feed_command('syntax keyword MyGroup special')
screen:expect([[
- very {5:spec}{7:^ial}{2: te}xt |
+ very {5:spec}{7:^ial}{2: te}xt |
|
{1:~ }|*4
:syntax keyword MyGroup special |
diff --git a/test/testutil.lua b/test/testutil.lua
index e69dcae120..3655a87d93 100644
--- a/test/testutil.lua
+++ b/test/testutil.lua
@@ -148,6 +148,7 @@ end
--- @param actual string
--- @return boolean
function M.matches(pat, actual)
+ assert(pat and pat ~= '', 'pat must be a non-empty string')
if nil ~= string.match(actual, pat) then
return true
end
@@ -641,28 +642,9 @@ end
--- @param leave_indent? integer
--- @return string
function M.dedent(str, leave_indent)
- -- find minimum common indent across lines
- local indent --- @type string?
- for line in str:gmatch('[^\n]+') do
- local line_indent = line:match('^%s+') or ''
- if indent == nil or #line_indent < #indent then
- indent = line_indent
- end
- end
-
- if not indent or #indent == 0 then
- -- no minimum common indent
- return str
- end
-
- local left_indent = (' '):rep(leave_indent or 0)
- -- create a pattern for the indent
- indent = indent:gsub('%s', '[ \t]')
- -- strip it from the first line
- str = str:gsub('^' .. indent, left_indent)
- -- strip it from the remaining lines
- str = str:gsub('[\n]' .. indent, '\n' .. left_indent)
- return str
+ -- Last blank line often has non-matching indent, so remove it.
+ str = str:gsub('\n[ ]+$', '\n')
+ return (vim.text.indent(leave_indent or 0, str))
end
function M.intchar2lua(ch)