mirror of
https://github.com/neovim/neovim.git
synced 2025-09-20 18:28:19 +00:00
fix(api): wrong return value with reverse range + overlap #32956
Problem: When iterating in reverse with {start} > {end} in
`nvim_buf_get_extmarks()`, marks that overlap {start} and are
greater than {end} are included in the return value twice.
Marks that overlap {end} and do not overlap {start} are not
not included in the return value at all. Marks are not
actually returned in a meaningful "traversal order".
Solution: Rather than actually iterating in reverse, (also possible but
requires convoluted conditions and would require fetching
overlapping marks for both the {start} and {end} position,
while still ending up with non-traversal ordered marks),
iterate normally and reverse the return value.
(cherry picked from commit 65170e8dad
)
This commit is contained in:

committed by
github-actions[bot]
![github-actions[bot]](/assets/img/avatar_default.png)
parent
3b0c88a537
commit
fb71d631a5
@@ -241,8 +241,11 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id,
|
||||
/// vim.api.nvim_buf_get_extmarks(0, my_ns, {0,0}, {-1,-1}, {})
|
||||
/// ```
|
||||
///
|
||||
/// If `end` is less than `start`, traversal works backwards. (Useful
|
||||
/// with `limit`, to get the first marks prior to a given position.)
|
||||
/// If `end` is less than `start`, marks are returned in reverse order.
|
||||
/// (Useful with `limit`, to get the first marks prior to a given position.)
|
||||
///
|
||||
/// Note: For a reverse range, `limit` does not actually affect the traversed
|
||||
/// range, just how many marks are returned
|
||||
///
|
||||
/// Note: when using extmark ranges (marks with a end_row/end_col position)
|
||||
/// the `overlap` option might be useful. Otherwise only the start position
|
||||
@@ -327,8 +330,6 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
|
||||
limit = INT64_MAX;
|
||||
}
|
||||
|
||||
bool reverse = false;
|
||||
|
||||
int l_row;
|
||||
colnr_T l_col;
|
||||
if (!extmark_get_index_from_obj(buf, ns_id, start, &l_row, &l_col, err)) {
|
||||
@@ -341,17 +342,31 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (l_row > u_row || (l_row == u_row && l_col > u_col)) {
|
||||
reverse = true;
|
||||
size_t rv_limit = (size_t)limit;
|
||||
bool reverse = l_row > u_row || (l_row == u_row && l_col > u_col);
|
||||
if (reverse) {
|
||||
limit = INT64_MAX; // limit the return value instead
|
||||
int row = l_row;
|
||||
l_row = u_row;
|
||||
u_row = row;
|
||||
colnr_T col = l_col;
|
||||
l_col = u_col;
|
||||
u_col = col;
|
||||
}
|
||||
|
||||
// note: ns_id=-1 allowed, represented as UINT32_MAX
|
||||
ExtmarkInfoArray marks = extmark_get(buf, (uint32_t)ns_id, l_row, l_col, u_row,
|
||||
u_col, (int64_t)limit, reverse, type, opts->overlap);
|
||||
u_col, (int64_t)limit, type, opts->overlap);
|
||||
|
||||
rv = arena_array(arena, kv_size(marks));
|
||||
for (size_t i = 0; i < kv_size(marks); i++) {
|
||||
ADD_C(rv, ARRAY_OBJ(extmark_to_array(kv_A(marks, i), true, details, hl_name, arena)));
|
||||
rv = arena_array(arena, MIN(kv_size(marks), rv_limit));
|
||||
if (reverse) {
|
||||
for (int i = (int)kv_size(marks) - 1; i >= 0 && kv_size(rv) < rv_limit; i--) {
|
||||
ADD_C(rv, ARRAY_OBJ(extmark_to_array(kv_A(marks, i), true, details, hl_name, arena)));
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < kv_size(marks); i++) {
|
||||
ADD_C(rv, ARRAY_OBJ(extmark_to_array(kv_A(marks, i), true, details, hl_name, arena)));
|
||||
}
|
||||
}
|
||||
|
||||
kv_destroy(marks);
|
||||
|
Reference in New Issue
Block a user