refactor(lua): rename vim.diff => vim.text.diff #34864

Problem:
`vim.diff()` was introduced before we had the `vim.text` module, where
it obviously belongs.

Solution:
Move it.
This commit is contained in:
Justin M. Keyes
2025-07-12 18:36:07 -04:00
committed by GitHub
parent 430be9d01d
commit f3a54e7ccf
12 changed files with 177 additions and 174 deletions

View File

@ -38,7 +38,7 @@ LSP
LUA
todo
*vim.diff()* Renamed to |vim.text.diff()|
VIMSCRIPT

View File

@ -581,7 +581,7 @@ A subset of the `vim.*` stdlib is available in threads, including:
- `vim.mpack` and `vim.json` (useful for serializing messages between threads)
- `require` in threads can use Lua packages from the global |package.path|
- `print()` and `vim.inspect`
- `vim.diff`
- `vim.text.diff`
- Most utility functions in `vim.*` that work with pure Lua values, like
`vim.split`, `vim.tbl_*`, `vim.list_*`, etc.
- `vim.is_thread()` returns true from a non-main thread.
@ -647,74 +647,6 @@ vim.hl.range({bufnr}, {ns}, {higroup}, {start}, {finish}, {opts})
manually. nil is returned if timeout is not specified
==============================================================================
VIM.DIFF *vim.diff*
vim.diff({a}, {b}, {opts}) *vim.diff()*
Run diff on strings {a} and {b}. Any indices returned by this function,
either directly or via callback arguments, are 1-based.
Examples: >lua
vim.diff('a\n', 'b\nc\n')
-- =>
-- @@ -1 +1,2 @@
-- -a
-- +b
-- +c
vim.diff('a\n', 'b\nc\n', {result_type = 'indices'})
-- =>
-- {
-- {1, 1, 1, 2}
-- }
<
Parameters: ~
• {a} (`string`) First string to compare
• {b} (`string`) Second string to compare
• {opts} (`table?`) Optional parameters:
• {on_hunk}?
(`fun(start_a: integer, count_a: integer, start_b: integer, count_b: integer): integer?`)
Invoked for each hunk in the diff. Return a negative number
to cancel the callback for any remaining hunks. Arguments:
• `start_a` (`integer`): Start line of hunk in {a}.
• `count_a` (`integer`): Hunk size in {a}.
• `start_b` (`integer`): Start line of hunk in {b}.
• `count_b` (`integer`): Hunk size in {b}.
• {result_type}? (`'unified'|'indices'`, default: `'unified'`)
Form of the returned diff:
• `unified`: String in unified format.
• `indices`: Array of hunk locations. Note: This option is
ignored if `on_hunk` is used.
• {linematch}? (`boolean|integer`) Run linematch on the
resulting hunks from xdiff. When integer, only hunks upto
this size in lines are run through linematch. Requires
`result_type = indices`, ignored otherwise.
• {algorithm}? (`'myers'|'minimal'|'patience'|'histogram'`,
default: `'myers'`) Diff algorithm to use. Values:
• `myers`: the default algorithm
• `minimal`: spend extra time to generate the smallest
possible diff
• `patience`: patience diff algorithm
• `histogram`: histogram diff algorithm
• {ctxlen}? (`integer`) Context length
• {interhunkctxlen}? (`integer`) Inter hunk context length
• {ignore_whitespace}? (`boolean`) Ignore whitespace
• {ignore_whitespace_change}? (`boolean`) Ignore whitespace
change
• {ignore_whitespace_change_at_eol}? (`boolean`) Ignore
whitespace change at end-of-line.
• {ignore_cr_at_eol}? (`boolean`) Ignore carriage return at
end-of-line
• {ignore_blank_lines}? (`boolean`) Ignore blank lines
• {indent_heuristic}? (`boolean`) Use the indent heuristic for
the internal diff library.
Return: ~
(`string|integer[][]?`) See {opts.result_type}. `nil` if
{opts.on_hunk} is given.
==============================================================================
VIM.MPACK *vim.mpack*
@ -4959,6 +4891,70 @@ vim.snippet.stop() *vim.snippet.stop()*
==============================================================================
Lua module: vim.text *vim.text*
vim.text.diff({a}, {b}, {opts}) *vim.text.diff()*
Run diff on strings {a} and {b}. Any indices returned by this function,
either directly or via callback arguments, are 1-based.
Examples: >lua
vim.text.diff('a\n', 'b\nc\n')
-- =>
-- @@ -1 +1,2 @@
-- -a
-- +b
-- +c
vim.text.diff('a\n', 'b\nc\n', {result_type = 'indices'})
-- =>
-- {
-- {1, 1, 1, 2}
-- }
<
Parameters: ~
• {a} (`string`) First string to compare
• {b} (`string`) Second string to compare
• {opts} (`table?`) Optional parameters:
• {on_hunk}?
(`fun(start_a: integer, count_a: integer, start_b: integer, count_b: integer): integer?`)
Invoked for each hunk in the diff. Return a negative number
to cancel the callback for any remaining hunks. Arguments:
• `start_a` (`integer`): Start line of hunk in {a}.
• `count_a` (`integer`): Hunk size in {a}.
• `start_b` (`integer`): Start line of hunk in {b}.
• `count_b` (`integer`): Hunk size in {b}.
• {result_type}? (`'unified'|'indices'`, default: `'unified'`)
Form of the returned diff:
• `unified`: String in unified format.
• `indices`: Array of hunk locations. Note: This option is
ignored if `on_hunk` is used.
• {linematch}? (`boolean|integer`) Run linematch on the
resulting hunks from xdiff. When integer, only hunks upto
this size in lines are run through linematch. Requires
`result_type = indices`, ignored otherwise.
• {algorithm}? (`'myers'|'minimal'|'patience'|'histogram'`,
default: `'myers'`) Diff algorithm to use. Values:
• `myers`: the default algorithm
• `minimal`: spend extra time to generate the smallest
possible diff
• `patience`: patience diff algorithm
• `histogram`: histogram diff algorithm
• {ctxlen}? (`integer`) Context length
• {interhunkctxlen}? (`integer`) Inter hunk context length
• {ignore_whitespace}? (`boolean`) Ignore whitespace
• {ignore_whitespace_change}? (`boolean`) Ignore whitespace
change
• {ignore_whitespace_change_at_eol}? (`boolean`) Ignore
whitespace change at end-of-line.
• {ignore_cr_at_eol}? (`boolean`) Ignore carriage return at
end-of-line
• {ignore_blank_lines}? (`boolean`) Ignore blank lines
• {indent_heuristic}? (`boolean`) Use the indent heuristic for
the internal diff library.
Return: ~
(`string|integer[][]?`) See {opts.result_type}. `nil` if
{opts.on_hunk} is given.
vim.text.hexdecode({enc}) *vim.text.hexdecode()*
Hex decode a string.

View File

@ -140,7 +140,7 @@ The following new APIs or features were added.
• 'diffopt' now includes a `linematch` option to enable a second-stage diff on
individual hunks to provide much more accurate diffs. This option is also
available to |vim.diff()|
available to |vim.text.diff()|
See https://github.com/neovim/neovim/pull/14537.

View File

@ -87,7 +87,7 @@ LSP
LUA
todo
Renamed `vim.diff` to `vim.text.diff`.
OPTIONS

View File

@ -1314,9 +1314,12 @@ end
require('vim._options')
-- Remove at Nvim 1.0
--- Remove at Nvim 1.0
---@deprecated
vim.loop = vim.uv
--- Renamed to `vim.text.diff`, remove at Nvim 1.0
---@deprecated
vim.diff = vim._diff ---@type fun(a: string, b: string, opts?: vim.text.diff.Opts): string|integer[][]?
-- Deprecated. Remove at Nvim 2.0
vim.highlight = vim._defer_deprecated_module('vim.highlight', 'vim.hl')

View File

@ -1,71 +0,0 @@
---@meta
--- Optional parameters:
--- @class vim.diff.Opts
--- @inlinedoc
---
--- Invoked for each hunk in the diff. Return a negative number
--- to cancel the callback for any remaining hunks.
--- Arguments:
--- - `start_a` (`integer`): Start line of hunk in {a}.
--- - `count_a` (`integer`): Hunk size in {a}.
--- - `start_b` (`integer`): Start line of hunk in {b}.
--- - `count_b` (`integer`): Hunk size in {b}.
--- @field on_hunk? fun(start_a: integer, count_a: integer, start_b: integer, count_b: integer): integer?
---
--- Form of the returned diff:
--- - `unified`: String in unified format.
--- - `indices`: Array of hunk locations.
--- Note: This option is ignored if `on_hunk` is used.
--- (default: `'unified'`)
--- @field result_type? 'unified'|'indices'
---
--- Run linematch on the resulting hunks from xdiff. When integer, only hunks
--- upto this size in lines are run through linematch.
--- Requires `result_type = indices`, ignored otherwise.
--- @field linematch? boolean|integer
---
--- Diff algorithm to use. Values:
--- - `myers`: the default algorithm
--- - `minimal`: spend extra time to generate the smallest possible diff
--- - `patience`: patience diff algorithm
--- - `histogram`: histogram diff algorithm
--- (default: `'myers'`)
--- @field algorithm? 'myers'|'minimal'|'patience'|'histogram'
--- @field ctxlen? integer Context length
--- @field interhunkctxlen? integer Inter hunk context length
--- @field ignore_whitespace? boolean Ignore whitespace
--- @field ignore_whitespace_change? boolean Ignore whitespace change
--- @field ignore_whitespace_change_at_eol? boolean Ignore whitespace change at end-of-line.
--- @field ignore_cr_at_eol? boolean Ignore carriage return at end-of-line
--- @field ignore_blank_lines? boolean Ignore blank lines
--- @field indent_heuristic? boolean Use the indent heuristic for the internal diff library.
-- luacheck: no unused args
--- Run diff on strings {a} and {b}. Any indices returned by this function,
--- either directly or via callback arguments, are 1-based.
---
--- Examples:
---
--- ```lua
--- vim.diff('a\n', 'b\nc\n')
--- -- =>
--- -- @@ -1 +1,2 @@
--- -- -a
--- -- +b
--- -- +c
---
--- vim.diff('a\n', 'b\nc\n', {result_type = 'indices'})
--- -- =>
--- -- {
--- -- {1, 1, 1, 2}
--- -- }
--- ```
---
---@param a string First string to compare
---@param b string Second string to compare
---@param opts? vim.diff.Opts
---@return string|integer[][]?
--- See {opts.result_type}. `nil` if {opts.on_hunk} is given.
function vim.diff(a, b, opts) end

View File

@ -2,6 +2,80 @@
local M = {}
--- Optional parameters:
--- @class vim.text.diff.Opts
--- @inlinedoc
---
--- Invoked for each hunk in the diff. Return a negative number
--- to cancel the callback for any remaining hunks.
--- Arguments:
--- - `start_a` (`integer`): Start line of hunk in {a}.
--- - `count_a` (`integer`): Hunk size in {a}.
--- - `start_b` (`integer`): Start line of hunk in {b}.
--- - `count_b` (`integer`): Hunk size in {b}.
--- @field on_hunk? fun(start_a: integer, count_a: integer, start_b: integer, count_b: integer): integer?
---
--- Form of the returned diff:
--- - `unified`: String in unified format.
--- - `indices`: Array of hunk locations.
--- Note: This option is ignored if `on_hunk` is used.
--- (default: `'unified'`)
--- @field result_type? 'unified'|'indices'
---
--- Run linematch on the resulting hunks from xdiff. When integer, only hunks
--- upto this size in lines are run through linematch.
--- Requires `result_type = indices`, ignored otherwise.
--- @field linematch? boolean|integer
---
--- Diff algorithm to use. Values:
--- - `myers`: the default algorithm
--- - `minimal`: spend extra time to generate the smallest possible diff
--- - `patience`: patience diff algorithm
--- - `histogram`: histogram diff algorithm
--- (default: `'myers'`)
--- @field algorithm? 'myers'|'minimal'|'patience'|'histogram'
--- @field ctxlen? integer Context length
--- @field interhunkctxlen? integer Inter hunk context length
--- @field ignore_whitespace? boolean Ignore whitespace
--- @field ignore_whitespace_change? boolean Ignore whitespace change
--- @field ignore_whitespace_change_at_eol? boolean Ignore whitespace change at end-of-line.
--- @field ignore_cr_at_eol? boolean Ignore carriage return at end-of-line
--- @field ignore_blank_lines? boolean Ignore blank lines
--- @field indent_heuristic? boolean Use the indent heuristic for the internal diff library.
-- luacheck: no unused args
--- Run diff on strings {a} and {b}. Any indices returned by this function,
--- either directly or via callback arguments, are 1-based.
---
--- Examples:
---
--- ```lua
--- vim.text.diff('a\n', 'b\nc\n')
--- -- =>
--- -- @@ -1 +1,2 @@
--- -- -a
--- -- +b
--- -- +c
---
--- vim.text.diff('a\n', 'b\nc\n', {result_type = 'indices'})
--- -- =>
--- -- {
--- -- {1, 1, 1, 2}
--- -- }
--- ```
---
---@diagnostic disable-next-line: undefined-doc-param
---@param a string First string to compare
---@diagnostic disable-next-line: undefined-doc-param
---@param b string Second string to compare
---@diagnostic disable-next-line: undefined-doc-param
---@param opts? vim.text.diff.Opts
---@return string|integer[][]? # See {opts.result_type}. `nil` if {opts.on_hunk} is given.
function M.diff(...)
return vim._diff(...)
end
local alphabet = '0123456789ABCDEF'
local atoi = {} ---@type table<string, integer>
local itoa = {} ---@type table<integer, string>

View File

@ -133,7 +133,6 @@ local config = {
filename = 'lua.txt',
section_order = {
'hl.lua',
'diff.lua',
'mpack.lua',
'json.lua',
'base64.lua',
@ -185,7 +184,6 @@ local config = {
'runtime/lua/vim/text.lua',
'runtime/lua/vim/glob.lua',
'runtime/lua/vim/_meta/builtin.lua',
'runtime/lua/vim/_meta/diff.lua',
'runtime/lua/vim/_meta/mpack.lua',
'runtime/lua/vim/_meta/json.lua',
'runtime/lua/vim/_meta/base64.lua',
@ -230,7 +228,6 @@ local config = {
'mpack',
'json',
'base64',
'diff',
'spell',
'regex',
'lpeg',

View File

@ -761,9 +761,9 @@ void nlua_state_add_stdlib(lua_State *const lstate, bool is_thread)
lua_setfield(lstate, -2, "lpeg");
lua_pop(lstate, 4);
// vim.diff
// vim.text.diff
lua_pushcfunction(lstate, &nlua_xdl_diff);
lua_setfield(lstate, -2, "diff");
lua_setfield(lstate, -2, "_diff");
// vim.json
lua_cjson_new(lstate);

View File

@ -164,9 +164,7 @@ static int call_on_hunk_cb(int start_a, int count_a, int start_b, int count_b, v
lua_pushinteger(lstate, count_b);
if (lua_pcall(lstate, 4, 1, 0) != 0) {
api_set_error(err, kErrorTypeException,
"error running function on_hunk: %s",
lua_tostring(lstate, -1));
api_set_error(err, kErrorTypeException, "on_hunk: %s", lua_tostring(lstate, -1));
return -1;
}

View File

@ -217,7 +217,7 @@ describe('thread', function()
it('diff', function()
exec_lua [[
local entry = function(async)
async:send(vim.diff('Hello\n', 'Helli\n'))
async:send(vim.text.diff('Hello\n', 'Helli\n'))
end
local on_async = function(ret)
vim.rpcnotify(1, 'result', ret)
@ -372,7 +372,7 @@ describe('threadpool', function()
it('work', function()
exec_lua [[
local work_fn = function()
return vim.diff('Hello\n', 'Helli\n')
return vim.text.diff('Hello\n', 'Helli\n')
end
local after_work_fn = function(ret)
vim.rpcnotify(1, 'result', ret)

View File

@ -27,7 +27,7 @@ describe('xdiff bindings', function()
'',
}, '\n'),
exec_lua(function()
return vim.diff(a1, b1)
return vim.text.diff(a1, b1)
end)
)
@ -43,7 +43,7 @@ describe('xdiff bindings', function()
'',
}, '\n'),
exec_lua(function()
return vim.diff(a2, b2)
return vim.text.diff(a2, b2)
end)
)
end)
@ -53,7 +53,7 @@ describe('xdiff bindings', function()
{ { 1, 1, 1, 1 } },
exec_lua(function()
local exp = {} --- @type table[]
assert(vim.diff(a1, b1, {
assert(vim.text.diff(a1, b1, {
on_hunk = function(...)
exp[#exp + 1] = { ... }
end,
@ -66,7 +66,7 @@ describe('xdiff bindings', function()
{ { 1, 1, 1, 1 }, { 3, 1, 3, 2 } },
exec_lua(function()
local exp = {} --- @type table[]
assert(vim.diff(a2, b2, {
assert(vim.text.diff(a2, b2, {
on_hunk = function(...)
exp[#exp + 1] = { ... }
end,
@ -80,7 +80,7 @@ describe('xdiff bindings', function()
{ { 1, 1, 1, 1 }, { 3, 1, 3, 2 } },
exec_lua(function()
local exp = {} --- @type table[]
assert(vim.diff(a2, b2, {
assert(vim.text.diff(a2, b2, {
on_hunk = function(...)
exp[#exp + 1] = { ... }
end,
@ -92,10 +92,10 @@ describe('xdiff bindings', function()
end)
it('with error callback', function()
eq(
[[.../xdiff_spec.lua:0: error running function on_hunk: .../xdiff_spec.lua:0: ERROR1]],
t.matches(
[[on_hunk: %.%.%./xdiff_spec%.lua%:0%: ERROR1]],
pcall_err(exec_lua, function()
vim.diff(a1, b1, {
vim.text.diff(a1, b1, {
on_hunk = function()
error('ERROR1')
end,
@ -108,14 +108,14 @@ describe('xdiff bindings', function()
eq(
{ { 1, 1, 1, 1 } },
exec_lua(function()
return vim.diff(a1, b1, { result_type = 'indices' })
return vim.text.diff(a1, b1, { result_type = 'indices' })
end)
)
eq(
{ { 1, 1, 1, 1 }, { 3, 1, 3, 2 } },
exec_lua(function()
return vim.diff(a2, b2, { result_type = 'indices' })
return vim.text.diff(a2, b2, { result_type = 'indices' })
end)
)
end)
@ -160,7 +160,7 @@ describe('xdiff bindings', function()
'',
}, '\n'),
exec_lua(function()
return vim.diff(a, b, {
return vim.text.diff(a, b, {
algorithm = 'patience',
})
end)
@ -169,20 +169,26 @@ describe('xdiff bindings', function()
end)
it('can handle bad args', function()
eq([[Expected at least 2 arguments]], pcall_err(exec_lua, [[vim.diff('a')]]))
eq([[Expected at least 2 arguments]], pcall_err(exec_lua, [[vim.text.diff('a')]]))
eq([[bad argument #1 to 'diff' (expected string)]], pcall_err(exec_lua, [[vim.diff(1, 2)]]))
eq(
[[bad argument #3 to 'diff' (expected table)]],
pcall_err(exec_lua, [[vim.diff('a', 'b', true)]])
t.matches(
[[bad argument %#1 to '_?diff' %(expected string%)]],
pcall_err(exec_lua, [[vim.text.diff(1, 2)]])
)
eq([[invalid key: bad_key]], pcall_err(exec_lua, [[vim.diff('a', 'b', { bad_key = true })]]))
t.matches(
[[bad argument %#3 to '_?diff' %(expected table%)]],
pcall_err(exec_lua, [[vim.text.diff('a', 'b', true)]])
)
eq(
[[invalid key: bad_key]],
pcall_err(exec_lua, [[vim.text.diff('a', 'b', { bad_key = true })]])
)
eq(
[[on_hunk is not a function]],
pcall_err(exec_lua, [[vim.diff('a', 'b', { on_hunk = true })]])
pcall_err(exec_lua, [[vim.text.diff('a', 'b', { on_hunk = true })]])
)
end)
@ -190,7 +196,7 @@ describe('xdiff bindings', function()
eq(
{ { 0, 0, 1, 1 }, { 1, 0, 3, 2 } },
exec_lua(function()
return vim.diff('\n', '\0\n\n\nb', { linematch = true, result_type = 'indices' })
return vim.text.diff('\n', '\0\n\n\nb', { linematch = true, result_type = 'indices' })
end)
)
end)