From 46a87a5d2bac598fed0870f0d3c926087f95d30f Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 14 Feb 2023 05:19:04 -0500 Subject: refactor(api): VALIDATE macros #22187 Problem: - API validation involves too much boilerplate. - API validation errors are not consistently worded. Solution: Introduce some macros. Currently these are clumsy, but they at least help with consistency and avoid some nesting. --- test/functional/api/extmark_spec.lua | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'test/functional/api/extmark_spec.lua') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 9902826c72..fc68f11a67 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -106,7 +106,7 @@ describe('API/extmarks', function() end_col = 0, end_row = 1 }) - eq("end_col value outside range", + eq("Invalid end_col: '(out of range)'", pcall_err(set_extmark, ns, marks[2], 0, 0, { end_col = 1, end_row = 1 })) end) @@ -1344,10 +1344,10 @@ describe('API/extmarks', function() it('throws consistent error codes', function() local ns_invalid = ns2 + 1 - eq("Invalid ns_id", pcall_err(set_extmark, ns_invalid, marks[1], positions[1][1], positions[1][2])) - eq("Invalid ns_id", pcall_err(curbufmeths.del_extmark, ns_invalid, marks[1])) - eq("Invalid ns_id", pcall_err(get_extmarks, ns_invalid, positions[1], positions[2])) - eq("Invalid ns_id", pcall_err(get_extmark_by_id, ns_invalid, marks[1])) + eq("Invalid ns_id: 3", pcall_err(set_extmark, ns_invalid, marks[1], positions[1][1], positions[1][2])) + eq("Invalid ns_id: 3", pcall_err(curbufmeths.del_extmark, ns_invalid, marks[1])) + eq("Invalid ns_id: 3", pcall_err(get_extmarks, ns_invalid, positions[1], positions[2])) + eq("Invalid ns_id: 3", pcall_err(get_extmark_by_id, ns_invalid, marks[1])) end) it('when col = line-length, set the mark on eol', function() @@ -1362,13 +1362,13 @@ describe('API/extmarks', function() it('when col = line-length, set the mark on eol', function() local invalid_col = init_text:len() + 1 - eq("col value outside range", pcall_err(set_extmark, ns, marks[1], 0, invalid_col)) + eq("Invalid col: '(out of range)'", pcall_err(set_extmark, ns, marks[1], 0, invalid_col)) end) it('fails when line > line_count', function() local invalid_col = init_text:len() + 1 local invalid_lnum = 3 - eq('line value outside range', pcall_err(set_extmark, ns, marks[1], invalid_lnum, invalid_col)) + eq("Invalid line: '(out of range)'", pcall_err(set_extmark, ns, marks[1], invalid_lnum, invalid_col)) eq({}, get_extmark_by_id(ns, marks[1])) end) -- cgit From ff3d04b75b4a9314815c37d53ebc4d035a043335 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 14 Feb 2023 08:07:38 -0500 Subject: refactor(api): VALIDATE macros #22256 - VALIDATE() takes a format string - deduplicate check_string_array - VALIDATE_RANGE - validate UI args --- test/functional/api/extmark_spec.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'test/functional/api/extmark_spec.lua') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index fc68f11a67..fab1557204 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -106,7 +106,7 @@ describe('API/extmarks', function() end_col = 0, end_row = 1 }) - eq("Invalid end_col: '(out of range)'", + eq("Invalid 'end_col': out of range", pcall_err(set_extmark, ns, marks[2], 0, 0, { end_col = 1, end_row = 1 })) end) @@ -1362,13 +1362,13 @@ describe('API/extmarks', function() it('when col = line-length, set the mark on eol', function() local invalid_col = init_text:len() + 1 - eq("Invalid col: '(out of range)'", pcall_err(set_extmark, ns, marks[1], 0, invalid_col)) + eq("Invalid 'col': out of range", pcall_err(set_extmark, ns, marks[1], 0, invalid_col)) end) it('fails when line > line_count', function() local invalid_col = init_text:len() + 1 local invalid_lnum = 3 - eq("Invalid line: '(out of range)'", pcall_err(set_extmark, ns, marks[1], invalid_lnum, invalid_col)) + eq("Invalid 'line': out of range", pcall_err(set_extmark, ns, marks[1], invalid_lnum, invalid_col)) eq({}, get_extmark_by_id(ns, marks[1])) end) -- cgit From 556f8646c01d1751cf39fe4df9c622899dceab9d Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 14 Feb 2023 14:19:28 -0500 Subject: refactor(api): consistent VALIDATE messages #22262 Problem: Validation messages are not consistently formatted. - Parameter names sometimes are NOT quoted. - Descriptive names (non-parameters) sometimes ARE quoted. Solution: Always quote the `name` value passed to a VALIDATE macro _unless_ the value has whitespace. --- test/functional/api/extmark_spec.lua | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'test/functional/api/extmark_spec.lua') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index fab1557204..3f9cb94260 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -101,6 +101,14 @@ describe('API/extmarks', function() ns2 = request('nvim_create_namespace', "my-fancy-plugin2") end) + it('validation', function() + eq("Invalid 'end_col': expected Integer, got Array", pcall_err(set_extmark, ns, marks[2], 0, 0, { end_col = {}, end_row = 1 })) + eq("Invalid 'end_row': expected Integer, got Array", pcall_err(set_extmark, ns, marks[2], 0, 0, { end_col = 1, end_row = {} })) + eq("Invalid 'id': expected positive Integer", pcall_err(set_extmark, ns, {}, 0, 0, { end_col = 1, end_row = 1 })) + eq("Invalid mark position: expected 2 Integer items", pcall_err(get_extmarks, ns, {}, {-1, -1})) + eq("Invalid mark position: expected mark id Integer or 2-item Array", pcall_err(get_extmarks, ns, true, {-1, -1})) + end) + it("can end extranges past final newline using end_col = 0", function() set_extmark(ns, marks[1], 0, 0, { end_col = 0, @@ -1344,10 +1352,10 @@ describe('API/extmarks', function() it('throws consistent error codes', function() local ns_invalid = ns2 + 1 - eq("Invalid ns_id: 3", pcall_err(set_extmark, ns_invalid, marks[1], positions[1][1], positions[1][2])) - eq("Invalid ns_id: 3", pcall_err(curbufmeths.del_extmark, ns_invalid, marks[1])) - eq("Invalid ns_id: 3", pcall_err(get_extmarks, ns_invalid, positions[1], positions[2])) - eq("Invalid ns_id: 3", pcall_err(get_extmark_by_id, ns_invalid, marks[1])) + eq("Invalid 'ns_id': 3", pcall_err(set_extmark, ns_invalid, marks[1], positions[1][1], positions[1][2])) + eq("Invalid 'ns_id': 3", pcall_err(curbufmeths.del_extmark, ns_invalid, marks[1])) + eq("Invalid 'ns_id': 3", pcall_err(get_extmarks, ns_invalid, positions[1], positions[2])) + eq("Invalid 'ns_id': 3", pcall_err(get_extmark_by_id, ns_invalid, marks[1])) end) it('when col = line-length, set the mark on eol', function() -- cgit From 39842be8cd8808c7da2638a6cc84d7c3fe40b996 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 5 Mar 2023 07:09:28 +0800 Subject: fix(extmarks): don't leak memory on error (#22507) --- test/functional/api/extmark_spec.lua | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'test/functional/api/extmark_spec.lua') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 3f9cb94260..30e75b8061 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -107,6 +107,13 @@ describe('API/extmarks', function() eq("Invalid 'id': expected positive Integer", pcall_err(set_extmark, ns, {}, 0, 0, { end_col = 1, end_row = 1 })) eq("Invalid mark position: expected 2 Integer items", pcall_err(get_extmarks, ns, {}, {-1, -1})) eq("Invalid mark position: expected mark id Integer or 2-item Array", pcall_err(get_extmarks, ns, true, {-1, -1})) + -- No memory leak with virt_text, virt_lines, sign_text + eq("right_gravity is not a boolean", pcall_err(set_extmark, ns, marks[2], 0, 0, { + virt_text = {{'foo', 'Normal'}}, + virt_lines = {{{'bar', 'Normal'}}}, + sign_text = 'a', + right_gravity = 'baz', + })) end) it("can end extranges past final newline using end_col = 0", function() -- cgit From fe9cbcb3a5c82932ecfb8f49d07e98a1fc2b31e5 Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Sat, 25 Mar 2023 18:58:48 +0200 Subject: feat(api): nvim_exec2(), deprecate nvim_exec() #19032 Problem: The signature of nvim_exec() is not extensible per ":help api-contract". Solution: Introduce nvim_exec2() and deprecate nvim_exec(). --- test/functional/api/extmark_spec.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'test/functional/api/extmark_spec.lua') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 30e75b8061..e9a175625b 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -1413,12 +1413,12 @@ describe('API/extmarks', function() end) it('does not crash with append/delete/undo sequence', function() - meths.exec([[ + meths.exec2([[ let ns = nvim_create_namespace('myplugin') call nvim_buf_set_extmark(0, ns, 0, 0, {}) call append(0, '') %delete - undo]],false) + undo]], { output = false }) assert_alive() end) @@ -1450,7 +1450,7 @@ describe('API/extmarks', function() feed('u') -- handles pasting - meths.exec([[let @a='asdfasdf']], false) + meths.exec2([[let @a='asdfasdf']], { output = false }) feed([["ap]]) eq({ {1, 0, 0}, {2, 0, 8} }, meths.buf_get_extmarks(0, ns, 0, -1, {})) -- cgit From 4863ca6b8902c5b0aab95f2af640118cd417d379 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 26 Mar 2023 10:49:32 +0800 Subject: test: use exec_capture() in more places (#22787) Problem: Using `meths.exec2("code", { output = true })` is too verbose. Solution: Use exec_capture() in more places. --- test/functional/api/extmark_spec.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'test/functional/api/extmark_spec.lua') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index e9a175625b..3882fc90ca 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -11,6 +11,7 @@ local insert = helpers.insert local feed = helpers.feed local clear = helpers.clear local command = helpers.command +local exec = helpers.exec local meths = helpers.meths local assert_alive = helpers.assert_alive @@ -1413,12 +1414,12 @@ describe('API/extmarks', function() end) it('does not crash with append/delete/undo sequence', function() - meths.exec2([[ + exec([[ let ns = nvim_create_namespace('myplugin') call nvim_buf_set_extmark(0, ns, 0, 0, {}) call append(0, '') %delete - undo]], { output = false }) + undo]]) assert_alive() end) @@ -1450,7 +1451,7 @@ describe('API/extmarks', function() feed('u') -- handles pasting - meths.exec2([[let @a='asdfasdf']], { output = false }) + exec([[let @a='asdfasdf']]) feed([["ap]]) eq({ {1, 0, 0}, {2, 0, 8} }, meths.buf_get_extmarks(0, ns, 0, -1, {})) -- cgit From 2a10f64e254375e77e1c5a6aeae3cd65cd122afb Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Sat, 25 Mar 2023 02:24:24 +0100 Subject: feat(extmarks): extend nvim_buf_get_extmarks() Problem: Can not get all extmarks in a buffer. Properties are missing from the details array. Solution: Allow getting all extmarks in a buffer by supplying a -1 "ns_id". Add missing properties to the details array. --- test/functional/api/extmark_spec.lua | 68 ++++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 14 deletions(-) (limited to 'test/functional/api/extmark_spec.lua') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 3882fc90ca..4bd8f51904 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -1463,6 +1463,7 @@ describe('API/extmarks', function() end_line = 1 }) eq({ {1, 0, 0, { + ns_id = 1, end_col = 0, end_row = 1, right_gravity = true, @@ -1480,20 +1481,27 @@ describe('API/extmarks', function() it('can get details', function() set_extmark(ns, marks[1], 0, 0, { + conceal = "c", + cursorline_hl_group = "Statement", end_col = 0, - end_row = 1, - right_gravity = false, end_right_gravity = true, - priority = 0, + end_row = 1, hl_eol = true, - hl_mode = "blend", hl_group = "String", - virt_text = { { "text", "Statement" } }, - virt_text_pos = "right_align", - virt_text_hide = true, + hl_mode = "blend", + line_hl_group = "Statement", + number_hl_group = "Statement", + priority = 0, + right_gravity = false, + sign_hl_group = "Statement", + sign_text = ">>", + spell = true, virt_lines = { { { "lines", "Statement" } }}, virt_lines_above = true, virt_lines_leftcol = true, + virt_text = { { "text", "Statement" } }, + virt_text_hide = true, + virt_text_pos = "right_align", }) set_extmark(ns, marks[2], 0, 0, { priority = 0, @@ -1501,22 +1509,31 @@ describe('API/extmarks', function() virt_text_win_col = 1, }) eq({0, 0, { + conceal = "c", + cursorline_hl_group = "Statement", end_col = 0, - end_row = 1, - right_gravity = false, end_right_gravity = true, - priority = 0, + end_row = 1, hl_eol = true, - hl_mode = "blend", hl_group = "String", - virt_text = { { "text", "Statement" } }, - virt_text_pos = "right_align", - virt_text_hide = true, + hl_mode = "blend", + line_hl_group = "Statement", + ns_id = 1, + number_hl_group = "Statement", + priority = 0, + right_gravity = false, + sign_hl_group = "Statement", + sign_text = ">>", + spell = true, virt_lines = { { { "lines", "Statement" } }}, virt_lines_above = true, virt_lines_leftcol = true, + virt_text = { { "text", "Statement" } }, + virt_text_hide = true, + virt_text_pos = "right_align", } }, get_extmark_by_id(ns, marks[1], { details = true })) eq({0, 0, { + ns_id = 1, right_gravity = true, priority = 0, virt_text = { { "text", "Statement" } }, @@ -1525,6 +1542,29 @@ describe('API/extmarks', function() virt_text_win_col = 1, } }, get_extmark_by_id(ns, marks[2], { details = true })) end) + + it('can get marks from anonymous namespaces', function() + ns = request('nvim_create_namespace', "") + ns2 = request('nvim_create_namespace', "") + set_extmark(ns, 1, 0, 0, {}) + set_extmark(ns2, 2, 1, 0, {}) + eq({{ 1, 0, 0, { ns_id = ns, right_gravity = true }}, + { 2, 1, 0, { ns_id = ns2, right_gravity = true }}}, + get_extmarks(-1, 0, -1, { details = true })) + end) + + it('can filter by extmark properties', function() + set_extmark(ns, 1, 0, 0, {}) + set_extmark(ns, 2, 0, 0, { hl_group = 'Normal' }) + set_extmark(ns, 3, 0, 0, { sign_text = '>>' }) + set_extmark(ns, 4, 0, 0, { virt_text = {{'text', 'Normal'}}}) + set_extmark(ns, 5, 0, 0, { virt_lines = {{{ 'line', 'Normal' }}}}) + eq(5, #get_extmarks(-1, 0, -1, { details = true })) + eq({{ 2, 0, 0 }}, get_extmarks(-1, 0, -1, { type = 'highlight' })) + eq({{ 3, 0, 0 }}, get_extmarks(-1, 0, -1, { type = 'sign' })) + eq({{ 4, 0, 0 }}, get_extmarks(-1, 0, -1, { type = 'virt_text' })) + eq({{ 5, 0, 0 }}, get_extmarks(-1, 0, -1, { type = 'virt_lines' })) + end) end) describe('Extmarks buffer api with many marks', function() -- cgit From 59fed8bb6457eb6c5204dc39a49d7ea0e1781482 Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Tue, 18 Apr 2023 15:07:37 +0200 Subject: fix(api): extmark highlight groups not always included in details (#23179) Problem: Erroneous for loop condition. Solution: Remove for loop condition. --- test/functional/api/extmark_spec.lua | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'test/functional/api/extmark_spec.lua') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 4bd8f51904..e30ffc92b6 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -1541,6 +1541,12 @@ describe('API/extmarks', function() virt_text_pos = "win_col", virt_text_win_col = 1, } }, get_extmark_by_id(ns, marks[2], { details = true })) + set_extmark(ns, marks[3], 0, 0, { cursorline_hl_group = "Statement" }) + eq({0, 0, { + ns_id = 1, + cursorline_hl_group = "Statement", + right_gravity = true, + } }, get_extmark_by_id(ns, marks[3], { details = true })) end) it('can get marks from anonymous namespaces', function() -- cgit From 1fe1bb084d0099fc4f9bfdc11189485d0f74b75a Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Mon, 19 Dec 2022 16:37:45 +0000 Subject: refactor(options): deprecate nvim[_buf|_win]_[gs]et_option Co-authored-by: zeertzjq Co-authored-by: famiu --- test/functional/api/extmark_spec.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test/functional/api/extmark_spec.lua') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index e30ffc92b6..0960e910f1 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -1401,7 +1401,7 @@ describe('API/extmarks', function() it('in read-only buffer', function() command("view! runtime/doc/help.txt") - eq(true, curbufmeths.get_option('ro')) + eq(true, meths.get_option_value('ro', {buf=0})) local id = set_extmark(ns, 0, 0, 2) eq({{id, 0, 2}}, get_extmarks(ns,0, -1)) end) @@ -1474,7 +1474,7 @@ describe('API/extmarks', function() it('in prompt buffer', function() feed('dd') local id = set_extmark(ns, marks[1], 0, 0, {}) - curbufmeths.set_option('buftype', 'prompt') + meths.set_option_value('buftype', 'prompt', {buf = 0}) feed('i') eq({{id, 0, 2}}, get_extmarks(ns, 0, -1)) end) -- cgit From 576dddb46168e81aa0f78c28816082c662dedea1 Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Mon, 22 May 2023 12:47:10 +0600 Subject: test: don't unnecessarily specify win/buf for `nvim_(get|set)_option_value` `nvim_(get|set)_option_value` pick the current buffer / window by default for buffer-local/window-local (but not global-local) options. So specifying `buf = 0` or `win = 0` in opts is unnecessary for those options. This PR removes those to reduce code clutter. --- test/functional/api/extmark_spec.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test/functional/api/extmark_spec.lua') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 0960e910f1..675c8332de 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -1401,7 +1401,7 @@ describe('API/extmarks', function() it('in read-only buffer', function() command("view! runtime/doc/help.txt") - eq(true, meths.get_option_value('ro', {buf=0})) + eq(true, meths.get_option_value('ro', {})) local id = set_extmark(ns, 0, 0, 2) eq({{id, 0, 2}}, get_extmarks(ns,0, -1)) end) @@ -1474,7 +1474,7 @@ describe('API/extmarks', function() it('in prompt buffer', function() feed('dd') local id = set_extmark(ns, marks[1], 0, 0, {}) - meths.set_option_value('buftype', 'prompt', {buf = 0}) + meths.set_option_value('buftype', 'prompt', {}) feed('i') eq({{id, 0, 2}}, get_extmarks(ns, 0, -1)) end) -- cgit From a9cd8467cbd54035e7814b862054c828467c2ce2 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 22 Jun 2023 13:59:57 +0800 Subject: fix(api): wrong nvim_buf_set_extmark error for invalid hl_mode --- test/functional/api/extmark_spec.lua | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'test/functional/api/extmark_spec.lua') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 675c8332de..ec1c9245ba 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -105,6 +105,10 @@ describe('API/extmarks', function() it('validation', function() eq("Invalid 'end_col': expected Integer, got Array", pcall_err(set_extmark, ns, marks[2], 0, 0, { end_col = {}, end_row = 1 })) eq("Invalid 'end_row': expected Integer, got Array", pcall_err(set_extmark, ns, marks[2], 0, 0, { end_col = 1, end_row = {} })) + eq("Invalid 'virt_text_pos': expected String, got Integer", pcall_err(set_extmark, ns, marks[2], 0, 0, { virt_text_pos = 0 })) + eq("Invalid 'virt_text_pos': 'foo'", pcall_err(set_extmark, ns, marks[2], 0, 0, { virt_text_pos = 'foo' })) + eq("Invalid 'hl_mode': expected String, got Integer", pcall_err(set_extmark, ns, marks[2], 0, 0, { hl_mode = 0 })) + eq("Invalid 'hl_mode': 'foo'", pcall_err(set_extmark, ns, marks[2], 0, 0, { hl_mode = 'foo' })) eq("Invalid 'id': expected positive Integer", pcall_err(set_extmark, ns, {}, 0, 0, { end_col = 1, end_row = 1 })) eq("Invalid mark position: expected 2 Integer items", pcall_err(get_extmarks, ns, {}, {-1, -1})) eq("Invalid mark position: expected mark id Integer or 2-item Array", pcall_err(get_extmarks, ns, true, {-1, -1})) -- cgit From 7bc93e0e2f246dd78026a3472d929a0fe450f70d Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 1 Aug 2023 14:01:19 +0200 Subject: refactor(api): use typed keysets Initially this is just for geting rid of boilerplate, but eventually the types could get exposed as metadata --- test/functional/api/extmark_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional/api/extmark_spec.lua') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index ec1c9245ba..6d8e3d8e0a 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -109,7 +109,7 @@ describe('API/extmarks', function() eq("Invalid 'virt_text_pos': 'foo'", pcall_err(set_extmark, ns, marks[2], 0, 0, { virt_text_pos = 'foo' })) eq("Invalid 'hl_mode': expected String, got Integer", pcall_err(set_extmark, ns, marks[2], 0, 0, { hl_mode = 0 })) eq("Invalid 'hl_mode': 'foo'", pcall_err(set_extmark, ns, marks[2], 0, 0, { hl_mode = 'foo' })) - eq("Invalid 'id': expected positive Integer", pcall_err(set_extmark, ns, {}, 0, 0, { end_col = 1, end_row = 1 })) + eq("Invalid 'id': expected Integer, got Array", pcall_err(set_extmark, ns, {}, 0, 0, { end_col = 1, end_row = 1 })) eq("Invalid mark position: expected 2 Integer items", pcall_err(get_extmarks, ns, {}, {-1, -1})) eq("Invalid mark position: expected mark id Integer or 2-item Array", pcall_err(get_extmarks, ns, true, {-1, -1})) -- No memory leak with virt_text, virt_lines, sign_text -- cgit From b04286a187d57c50f01cd36cd4668b7a69026579 Mon Sep 17 00:00:00 2001 From: bfredl Date: Sun, 22 Nov 2020 10:10:37 +0100 Subject: feat(extmark): support proper multiline ranges The removes the previous restriction that nvim_buf_set_extmark() could not be used to highlight arbitrary multi-line regions The problem can be summarized as follows: let's assume an extmark with a hl_group is placed covering the region (5,0) to (50,0) Now, consider what happens if nvim needs to redraw a window covering the lines 20-30. It needs to be able to ask the marktree what extmarks cover this region, even if they don't begin or end here. Therefore the marktree needs to be augmented with the information covers a point, not just what marks begin or end there. To do this, we augment each node with a field "intersect" which is a set the ids of the marks which overlap this node, but only if it is not part of the set of any parent. This ensures the number of nodes that need to be explicitly marked grows only logarithmically with the total number of explicitly nodes (and thus the number of of overlapping marks). Thus we can quickly iterate all marks which overlaps any query position by looking up what leaf node contains that position. Then we only need to consider all "start" marks within that leaf node, and the "intersect" set of that node and all its parents. Now, and the major source of complexity is that the tree restructuring operations (to ensure that each node has T-1 <= size <= 2*T-1) also need to update these sets. If a full inner node is split in two, one of the new parents might start to completely overlap some ranges and its ids will need to be moved from its children's sets to its own set. Similarly, if two undersized nodes gets joined into one, it might no longer completely overlap some ranges, and now the children which do needs to have the have the ids in its set instead. And then there are the pivots! Yes the pivot operations when a child gets moved from one parent to another. --- test/functional/api/extmark_spec.lua | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'test/functional/api/extmark_spec.lua') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 6d8e3d8e0a..a917432dab 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -753,7 +753,14 @@ describe('API/extmarks', function() }) end) - -- TODO(bfredl): add more tests! + it('can get overlapping extmarks', function() + set_extmark(ns, 1, 0, 0, {end_row = 5, end_col=0}) + set_extmark(ns, 2, 2, 5, {end_row = 2, end_col=30}) + set_extmark(ns, 3, 0, 5, {end_row = 2, end_col=10}) + set_extmark(ns, 4, 0, 0, {end_row = 1, end_col=0}) + eq({{ 2, 2, 5 }}, get_extmarks(ns, {2, 0}, {2, -1}, { overlap=false })) + eq({{ 1, 0, 0 }, { 3, 0, 5}, {2, 2, 5}}, get_extmarks(ns, {2, 0}, {2, -1}, { overlap=true })) + end) end) it('replace works', function() -- cgit From 585549625d8aef073e874d7cace9ab9df0d71847 Mon Sep 17 00:00:00 2001 From: L Lllvvuu Date: Fri, 15 Sep 2023 21:43:49 -0700 Subject: fix(marktree): off-by-one error in `marktree_move` If you would insert element X at position j, then if you are moving that same element X from position i < j, you should move it to position j - 1, because you are losing an element. This error caused a gap to be left in the array, so that it looked like [x, null, y] instead of [x, y], where len = 2. This triggered #25147. Fixes: #25147 --- test/functional/api/extmark_spec.lua | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'test/functional/api/extmark_spec.lua') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index a917432dab..c4449bc201 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -208,6 +208,23 @@ describe('API/extmarks', function() eq({}, get_extmarks(ns2, {0, 0}, {-1, -1})) end) + it('can undo with extmarks (#25147)', function() + feed('itest') + set_extmark(ns, 1, 0, 0) + set_extmark(ns, 2, 1, 0) + eq({ { 1, 0, 0 }, { 2, 1, 0 } }, get_extmarks(ns, {0, 0}, {-1, -1})) + feed('dd') + eq({ { 1, 1, 0 }, { 2, 1, 0 } }, get_extmarks(ns, {0, 0}, {-1, -1})) + curbufmeths.clear_namespace(ns, 0, -1) + eq({}, get_extmarks(ns, {0, 0}, {-1, -1})) + set_extmark(ns, 1, 0, 0, { right_gravity = false }) + set_extmark(ns, 2, 1, 0, { right_gravity = false }) + eq({ { 1, 0, 0 }, { 2, 1, 0 } }, get_extmarks(ns, {0, 0}, {-1, -1})) + feed('u') + eq({ { 1, 0, 0 }, { 2, 1, 0 } }, get_extmarks(ns, {0, 0}, {-1, -1})) + curbufmeths.clear_namespace(ns, 0, -1) + end) + it('querying for information and ranges', function() --marks = {1, 2, 3} --positions = {{0, 0,}, {0, 2}, {0, 3}} -- cgit From b7763d7f6b7fdcabe06658c664457df8bc147563 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 22 Sep 2023 17:56:05 +0800 Subject: fix(api): get virtual text with multiple hl properly (#25307) --- test/functional/api/extmark_spec.lua | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'test/functional/api/extmark_spec.lua') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index c4449bc201..133ec67942 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -1524,16 +1524,19 @@ describe('API/extmarks', function() sign_hl_group = "Statement", sign_text = ">>", spell = true, - virt_lines = { { { "lines", "Statement" } }}, + virt_lines = { + { { "lines", "Macro" }, { "???" } }, + { { "stack", { "Type", "Search" } }, { "!!!" } }, + }, virt_lines_above = true, virt_lines_leftcol = true, - virt_text = { { "text", "Statement" } }, + virt_text = { { "text", "Macro" }, { "???" }, { "stack", { "Type", "Search" } } }, virt_text_hide = true, virt_text_pos = "right_align", }) set_extmark(ns, marks[2], 0, 0, { priority = 0, - virt_text = { { "text", "Statement" } }, + virt_text = { { "", "Macro" }, { "", { "Type", "Search" } }, { "" } }, virt_text_win_col = 1, }) eq({0, 0, { @@ -1553,10 +1556,13 @@ describe('API/extmarks', function() sign_hl_group = "Statement", sign_text = ">>", spell = true, - virt_lines = { { { "lines", "Statement" } }}, + virt_lines = { + { { "lines", "Macro" }, { "???" } }, + { { "stack", { "Type", "Search" } }, { "!!!" } }, + }, virt_lines_above = true, virt_lines_leftcol = true, - virt_text = { { "text", "Statement" } }, + virt_text = { { "text", "Macro" }, { "???" }, { "stack", { "Type", "Search" } } }, virt_text_hide = true, virt_text_pos = "right_align", } }, get_extmark_by_id(ns, marks[1], { details = true })) @@ -1564,7 +1570,7 @@ describe('API/extmarks', function() ns_id = 1, right_gravity = true, priority = 0, - virt_text = { { "text", "Statement" } }, + virt_text = { { "", "Macro" }, { "", { "Type", "Search" } }, { "" } }, virt_text_hide = false, virt_text_pos = "win_col", virt_text_win_col = 1, -- cgit From 4e6f559b8c5f77924fdbe2e5abd9c6aa8efad13f Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Tue, 24 Oct 2023 13:32:00 +0200 Subject: feat(extmarks): add 'invalidate' property to extmarks Problem: No way to have extmarks automatically removed when the range it is attached to is deleted. Solution: Add new 'invalidate' property that will hide a mark when the entirety of its range is deleted. When "undo_restore" is set to false, delete the mark from the buffer instead. --- test/functional/api/extmark_spec.lua | 60 +++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) (limited to 'test/functional/api/extmark_spec.lua') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 133ec67942..6e00be611d 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -1599,12 +1599,70 @@ describe('API/extmarks', function() set_extmark(ns, 3, 0, 0, { sign_text = '>>' }) set_extmark(ns, 4, 0, 0, { virt_text = {{'text', 'Normal'}}}) set_extmark(ns, 5, 0, 0, { virt_lines = {{{ 'line', 'Normal' }}}}) - eq(5, #get_extmarks(-1, 0, -1, { details = true })) + eq(5, #get_extmarks(-1, 0, -1, {})) eq({{ 2, 0, 0 }}, get_extmarks(-1, 0, -1, { type = 'highlight' })) eq({{ 3, 0, 0 }}, get_extmarks(-1, 0, -1, { type = 'sign' })) eq({{ 4, 0, 0 }}, get_extmarks(-1, 0, -1, { type = 'virt_text' })) eq({{ 5, 0, 0 }}, get_extmarks(-1, 0, -1, { type = 'virt_lines' })) end) + + it("invalidated marks are deleted", function() + screen = Screen.new(40, 6) + screen:attach() + feed('dd6iaaa bbb cccgg') + set_extmark(ns, 1, 0, 0, { invalidate = true, sign_text = 'S1' }) + set_extmark(ns, 2, 1, 0, { invalidate = true, sign_text = 'S2' }) + -- mark with invalidate is removed + command('d') + screen:expect([[ + S2^aaa bbb ccc | + aaa bbb ccc | + aaa bbb ccc | + aaa bbb ccc | + aaa bbb ccc | + | + ]]) + -- mark is restored with undo_restore == true + command('silent undo') + screen:expect([[ + S1^aaa bbb ccc | + S2aaa bbb ccc | + aaa bbb ccc | + aaa bbb ccc | + aaa bbb ccc | + | + ]]) + -- mark is deleted with undo_restore == false + set_extmark(ns, 1, 0, 0, { invalidate = true, undo_restore = false, sign_text = 'S1' }) + set_extmark(ns, 2, 1, 0, { invalidate = true, undo_restore = false, sign_text = 'S2' }) + command('1d 2') + eq(0, #get_extmarks(-1, 0, -1, {})) + -- mark is not removed when deleting bytes before the range + set_extmark(ns, 3, 0, 4, { invalidate = true, undo_restore = false, + hl_group = 'Error', end_col = 7 }) + feed('dw') + eq(3, get_extmark_by_id(ns, 3, { details = true })[3].end_col) + -- mark is not removed when deleting bytes at the start of the range + feed('x') + eq(2, get_extmark_by_id(ns, 3, { details = true })[3].end_col) + -- mark is not removed when deleting bytes from the end of the range + feed('lx') + eq(1, get_extmark_by_id(ns, 3, { details = true})[3].end_col) + -- mark is not removed when deleting bytes beyond end of the range + feed('x') + eq(1, get_extmark_by_id(ns, 3, { details = true})[3].end_col) + -- mark is removed when all bytes in the range are deleted + feed('hx') + eq({}, get_extmark_by_id(ns, 3, {})) + -- multiline mark is not removed when start of its range is deleted + set_extmark(ns, 4, 1, 4, { undo_restore = false, invalidate = true, + hl_group = 'Error', end_col = 7, end_row = 3 }) + feed('ddDdd') + eq({0, 0}, get_extmark_by_id(ns, 4, {})) + -- multiline mark is removed when entirety of its range is deleted + feed('vj2ed') + eq({}, get_extmark_by_id(ns, 4, {})) + end) end) describe('Extmarks buffer api with many marks', function() -- cgit From 0b38fe4dbb77c15ae6f5779174855acab25fc86c Mon Sep 17 00:00:00 2001 From: bfredl Date: Wed, 8 Mar 2023 15:18:02 +0100 Subject: refactor(decorations): break up Decoration struct into smaller pieces Remove the monolithic Decoration struct. Before this change, each extmark could either represent just a hl_id + priority value as a inline decoration, or it would take a pointer to this monolitic 112 byte struct which has to be allocated. This change separates the decorations into two pieces: DecorSignHighlight for signs, highlights and simple set-flag decorations (like spell, ui-watched), and DecorVirtText for virtual text and lines. The main separation here is whether they are expected to allocate more memory. Currently this is not really true as sign text has to be an allocated string, but the plan is to get rid of this eventually (it can just be an array of two schar_T:s). Further refactors are expected to improve the representation of each decoration kind individually. The goal of this particular PR is to get things started by cutting the Gordian knot which was the monolithic struct Decoration. Now, each extmark can either contain chained indicies/pointers to these kinds of objects, or it can fit a subset of DecorSignHighlight inline. The point of this change is not only to make decorations smaller in memory. In fact, the main motivation is to later allow them to grow _larger_, but on a dynamic, on demand fashion. As a simple example, it would be possible to augment highlights to take a list of multiple `hl_group`:s, which then would trivially map to a chain of multiple DecorSignHighlight entries. One small feature improvement included with this refactor itself, is that the restriction that extmarks cannot be removed inside a decoration provider has been lifted. These are instead safely lifetime extended on a "to free" list until the current iteration of screen drawing is done. NB: flags is a mess. but DecorLevel is useless, this slightly less so --- test/functional/api/extmark_spec.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'test/functional/api/extmark_spec.lua') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 6e00be611d..2115c7c244 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -1579,6 +1579,7 @@ describe('API/extmarks', function() eq({0, 0, { ns_id = 1, cursorline_hl_group = "Statement", + priority = 4096, right_gravity = true, } }, get_extmark_by_id(ns, marks[3], { details = true })) end) -- cgit From c249058758af6919f718750b2f4acb96bafeb2dd Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Sat, 18 Nov 2023 23:49:11 +0100 Subject: feat(extmarks): add sign name to extmark "details" array Problem: Unable to identify legacy signs when fetching extmarks with `nvim_buf_get_extmarks()`. Solution: Add "sign_name" to the extmark detail array. Add some misc. changes as follow-up to #25724 --- test/functional/api/extmark_spec.lua | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'test/functional/api/extmark_spec.lua') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 2115c7c244..44a151cf6a 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -1582,6 +1582,23 @@ describe('API/extmarks', function() priority = 4096, right_gravity = true, } }, get_extmark_by_id(ns, marks[3], { details = true })) + curbufmeths.clear_namespace(ns, 0, -1) + -- legacy sign mark includes sign name + command('sign define sign1 text=s1 texthl=Title linehl=LineNR numhl=Normal culhl=CursorLine') + command('sign place 1 name=sign1 line=1') + eq({ {1, 0, 0, { + cursorline_hl_group = 'CursorLine', + invalidate = true, + line_hl_group = 'LineNr', + ns_id = 0, + number_hl_group = 'Normal', + priority = 10, + right_gravity = true, + sign_hl_group = 'Title', + sign_name = 'sign1', + sign_text = 's1', + undo_restore = false + } } }, get_extmarks(-1, 0, -1, { details = true })) end) it('can get marks from anonymous namespaces', function() -- cgit