mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge pull request #23657 from luukvbaal/extmark
fix(extmark): restore extmarks when completing original text
This commit is contained in:
commit
3b6dd8608d
@ -311,9 +311,8 @@ void extmark_free_all(buf_T *buf)
|
|||||||
/// copying is useful when we cannot simply reverse the operation. This will do
|
/// copying is useful when we cannot simply reverse the operation. This will do
|
||||||
/// nothing on redo, enforces correct position when undo.
|
/// nothing on redo, enforces correct position when undo.
|
||||||
void extmark_splice_delete(buf_T *buf, int l_row, colnr_T l_col, int u_row, colnr_T u_col,
|
void extmark_splice_delete(buf_T *buf, int l_row, colnr_T l_col, int u_row, colnr_T u_col,
|
||||||
ExtmarkOp op)
|
extmark_undo_vec_t *uvp, bool only_copy, ExtmarkOp op)
|
||||||
{
|
{
|
||||||
u_header_T *uhp = u_force_get_undo_header(buf);
|
|
||||||
MarkTreeIter itr[1] = { 0 };
|
MarkTreeIter itr[1] = { 0 };
|
||||||
ExtmarkUndoObject undo;
|
ExtmarkUndoObject undo;
|
||||||
|
|
||||||
@ -328,7 +327,7 @@ void extmark_splice_delete(buf_T *buf, int l_row, colnr_T l_col, int u_row, coln
|
|||||||
|
|
||||||
bool invalidated = false;
|
bool invalidated = false;
|
||||||
// Invalidate/delete mark
|
// Invalidate/delete mark
|
||||||
if (!mt_invalid(mark) && mt_invalidate(mark) && !mt_end(mark)) {
|
if (!only_copy && !mt_invalid(mark) && mt_invalidate(mark) && !mt_end(mark)) {
|
||||||
MTPos endpos = marktree_get_altpos(buf->b_marktree, mark, NULL);
|
MTPos endpos = marktree_get_altpos(buf->b_marktree, mark, NULL);
|
||||||
if (endpos.row < 0) {
|
if (endpos.row < 0) {
|
||||||
endpos = mark.pos;
|
endpos = mark.pos;
|
||||||
@ -348,7 +347,7 @@ void extmark_splice_delete(buf_T *buf, int l_row, colnr_T l_col, int u_row, coln
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Push mark to undo header
|
// Push mark to undo header
|
||||||
if (uhp && op == kExtmarkUndo && !mt_no_undo(mark)) {
|
if (only_copy || (uvp != NULL && op == kExtmarkUndo && !mt_no_undo(mark))) {
|
||||||
ExtmarkSavePos pos;
|
ExtmarkSavePos pos;
|
||||||
pos.mark = mt_lookup_key(mark);
|
pos.mark = mt_lookup_key(mark);
|
||||||
pos.invalidated = invalidated;
|
pos.invalidated = invalidated;
|
||||||
@ -359,7 +358,7 @@ void extmark_splice_delete(buf_T *buf, int l_row, colnr_T l_col, int u_row, coln
|
|||||||
|
|
||||||
undo.data.savepos = pos;
|
undo.data.savepos = pos;
|
||||||
undo.type = kExtmarkSavePos;
|
undo.type = kExtmarkSavePos;
|
||||||
kv_push(uhp->uh_extmark, undo);
|
kv_push(*uvp, undo);
|
||||||
}
|
}
|
||||||
|
|
||||||
marktree_itr_next(buf->b_marktree, itr);
|
marktree_itr_next(buf->b_marktree, itr);
|
||||||
@ -511,7 +510,9 @@ void extmark_splice_impl(buf_T *buf, int start_row, colnr_T start_col, bcount_t
|
|||||||
// merge!)
|
// merge!)
|
||||||
int end_row = start_row + old_row;
|
int end_row = start_row + old_row;
|
||||||
int end_col = (old_row ? 0 : start_col) + old_col;
|
int end_col = (old_row ? 0 : start_col) + old_col;
|
||||||
extmark_splice_delete(buf, start_row, start_col, end_row, end_col, undo);
|
u_header_T *uhp = u_force_get_undo_header(buf);
|
||||||
|
extmark_undo_vec_t *uvp = uhp ? &uhp->uh_extmark : NULL;
|
||||||
|
extmark_splice_delete(buf, start_row, start_col, end_row, end_col, uvp, false, undo);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move the signcolumn sentinel line
|
// Move the signcolumn sentinel line
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "nvim/eval/userfunc.h"
|
#include "nvim/eval/userfunc.h"
|
||||||
#include "nvim/ex_eval.h"
|
#include "nvim/ex_eval.h"
|
||||||
#include "nvim/ex_getln.h"
|
#include "nvim/ex_getln.h"
|
||||||
|
#include "nvim/extmark.h"
|
||||||
#include "nvim/fileio.h"
|
#include "nvim/fileio.h"
|
||||||
#include "nvim/garray.h"
|
#include "nvim/garray.h"
|
||||||
#include "nvim/getchar.h"
|
#include "nvim/getchar.h"
|
||||||
@ -251,6 +252,8 @@ static colnr_T compl_col = 0; ///< column where the text starts
|
|||||||
///< that is being completed
|
///< that is being completed
|
||||||
static char *compl_orig_text = NULL; ///< text as it was before
|
static char *compl_orig_text = NULL; ///< text as it was before
|
||||||
///< completion started
|
///< completion started
|
||||||
|
/// Undo information to restore extmarks for original text.
|
||||||
|
static extmark_undo_vec_t compl_orig_extmarks;
|
||||||
static int compl_cont_mode = 0;
|
static int compl_cont_mode = 0;
|
||||||
static expand_T compl_xp;
|
static expand_T compl_xp;
|
||||||
|
|
||||||
@ -1568,6 +1571,7 @@ void ins_compl_clear(void)
|
|||||||
XFREE_CLEAR(compl_pattern);
|
XFREE_CLEAR(compl_pattern);
|
||||||
XFREE_CLEAR(compl_leader);
|
XFREE_CLEAR(compl_leader);
|
||||||
edit_submode_extra = NULL;
|
edit_submode_extra = NULL;
|
||||||
|
kv_destroy(compl_orig_extmarks);
|
||||||
XFREE_CLEAR(compl_orig_text);
|
XFREE_CLEAR(compl_orig_text);
|
||||||
compl_enter_selects = false;
|
compl_enter_selects = false;
|
||||||
// clear v:completed_item
|
// clear v:completed_item
|
||||||
@ -2018,6 +2022,7 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval)
|
|||||||
ins_bytes_len(p + compl_len, (size_t)(len - compl_len));
|
ins_bytes_len(p + compl_len, (size_t)(len - compl_len));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
restore_orig_extmarks();
|
||||||
retval = true;
|
retval = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2504,6 +2509,22 @@ static void ins_compl_add_dict(dict_T *dict)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Save extmarks in "compl_orig_text" so that they may be restored when the
|
||||||
|
/// completion is cancelled, or the original text is completed.
|
||||||
|
static void save_orig_extmarks(void)
|
||||||
|
{
|
||||||
|
extmark_splice_delete(curbuf, curwin->w_cursor.lnum - 1, compl_col, curwin->w_cursor.lnum - 1,
|
||||||
|
compl_col + compl_length, &compl_orig_extmarks, true, kExtmarkUndo);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void restore_orig_extmarks(void)
|
||||||
|
{
|
||||||
|
for (long i = (int)kv_size(compl_orig_extmarks) - 1; i > -1; i--) {
|
||||||
|
ExtmarkUndoObject undo_info = kv_A(compl_orig_extmarks, i);
|
||||||
|
extmark_apply_undo(undo_info, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Start completion for the complete() function.
|
/// Start completion for the complete() function.
|
||||||
///
|
///
|
||||||
/// @param startcol where the matched text starts (1 is first column).
|
/// @param startcol where the matched text starts (1 is first column).
|
||||||
@ -2525,10 +2546,10 @@ static void set_completion(colnr_T startcol, list_T *list)
|
|||||||
startcol = curwin->w_cursor.col;
|
startcol = curwin->w_cursor.col;
|
||||||
}
|
}
|
||||||
compl_col = startcol;
|
compl_col = startcol;
|
||||||
compl_length = (int)curwin->w_cursor.col - (int)startcol;
|
compl_length = curwin->w_cursor.col - startcol;
|
||||||
// compl_pattern doesn't need to be set
|
// compl_pattern doesn't need to be set
|
||||||
compl_orig_text = xstrnsave(get_cursor_line_ptr() + compl_col,
|
compl_orig_text = xstrnsave(get_cursor_line_ptr() + compl_col, (size_t)compl_length);
|
||||||
(size_t)compl_length);
|
save_orig_extmarks();
|
||||||
if (p_ic) {
|
if (p_ic) {
|
||||||
flags |= CP_ICASE;
|
flags |= CP_ICASE;
|
||||||
}
|
}
|
||||||
@ -3688,12 +3709,16 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
|
|||||||
if (compl_no_insert && !started) {
|
if (compl_no_insert && !started) {
|
||||||
ins_bytes(compl_orig_text + get_compl_len());
|
ins_bytes(compl_orig_text + get_compl_len());
|
||||||
compl_used_match = false;
|
compl_used_match = false;
|
||||||
|
restore_orig_extmarks();
|
||||||
} else if (insert_match) {
|
} else if (insert_match) {
|
||||||
if (!compl_get_longest || compl_used_match) {
|
if (!compl_get_longest || compl_used_match) {
|
||||||
ins_compl_insert(in_compl_func);
|
ins_compl_insert(in_compl_func);
|
||||||
} else {
|
} else {
|
||||||
ins_bytes(compl_leader + get_compl_len());
|
ins_bytes(compl_leader + get_compl_len());
|
||||||
}
|
}
|
||||||
|
if (!strcmp(compl_curr_match->cp_str, compl_orig_text)) {
|
||||||
|
restore_orig_extmarks();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
compl_used_match = false;
|
compl_used_match = false;
|
||||||
}
|
}
|
||||||
@ -4266,7 +4291,9 @@ static int ins_compl_start(void)
|
|||||||
|
|
||||||
// Always add completion for the original text.
|
// Always add completion for the original text.
|
||||||
xfree(compl_orig_text);
|
xfree(compl_orig_text);
|
||||||
|
kv_destroy(compl_orig_extmarks);
|
||||||
compl_orig_text = xstrnsave(line + compl_col, (size_t)compl_length);
|
compl_orig_text = xstrnsave(line + compl_col, (size_t)compl_length);
|
||||||
|
save_orig_extmarks();
|
||||||
int flags = CP_ORIGINAL_TEXT;
|
int flags = CP_ORIGINAL_TEXT;
|
||||||
if (p_ic) {
|
if (p_ic) {
|
||||||
flags |= CP_ICASE;
|
flags |= CP_ICASE;
|
||||||
@ -4275,6 +4302,7 @@ static int ins_compl_start(void)
|
|||||||
flags, false) != OK) {
|
flags, false) != OK) {
|
||||||
XFREE_CLEAR(compl_pattern);
|
XFREE_CLEAR(compl_pattern);
|
||||||
XFREE_CLEAR(compl_orig_text);
|
XFREE_CLEAR(compl_orig_text);
|
||||||
|
kv_destroy(compl_orig_extmarks);
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4507,6 +4535,7 @@ static unsigned quote_meta(char *dest, char *src, int len)
|
|||||||
void free_insexpand_stuff(void)
|
void free_insexpand_stuff(void)
|
||||||
{
|
{
|
||||||
XFREE_CLEAR(compl_orig_text);
|
XFREE_CLEAR(compl_orig_text);
|
||||||
|
kv_destroy(compl_orig_extmarks);
|
||||||
callback_free(&cfu_cb);
|
callback_free(&cfu_cb);
|
||||||
callback_free(&ofu_cb);
|
callback_free(&ofu_cb);
|
||||||
callback_free(&tsrfu_cb);
|
callback_free(&tsrfu_cb);
|
||||||
|
@ -1257,4 +1257,48 @@ describe('completion', function()
|
|||||||
{3:-- }{4:match 1 of 2} |
|
{3:-- }{4:match 1 of 2} |
|
||||||
]]}
|
]]}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('restores extmarks if original text is restored #23653', function()
|
||||||
|
screen:try_resize(screen._width, 4)
|
||||||
|
command([[
|
||||||
|
call setline(1, ['aaaa'])
|
||||||
|
let ns_id = nvim_create_namespace('extmark')
|
||||||
|
let mark_id = nvim_buf_set_extmark(0, ns_id, 0, 0, { 'end_col':2, 'hl_group':'Error'})
|
||||||
|
let mark = nvim_buf_get_extmark_by_id(0, ns_id, mark_id, { 'details':1 })
|
||||||
|
inoremap <C-x> <C-r>=Complete()<CR>
|
||||||
|
function Complete() abort
|
||||||
|
call complete(1, [{ 'word': 'aaaaa' }])
|
||||||
|
return ''
|
||||||
|
endfunction
|
||||||
|
]])
|
||||||
|
feed('A<C-X><C-E><Esc>')
|
||||||
|
eq(eval('mark'), eval("nvim_buf_get_extmark_by_id(0, ns_id, mark_id, { 'details':1 })"))
|
||||||
|
feed('A<C-N>')
|
||||||
|
eq(eval('mark'), eval("nvim_buf_get_extmark_by_id(0, ns_id, mark_id, { 'details':1 })"))
|
||||||
|
feed('<Esc>0Yppia<Esc>ggI<C-N>')
|
||||||
|
screen:expect([[
|
||||||
|
aaaa{7:^aa}aa |
|
||||||
|
{2:aaaa } |
|
||||||
|
{1:aaaaa } |
|
||||||
|
{3:-- Keyword completion (^N^P) }{4:match 1 of 2} |
|
||||||
|
]])
|
||||||
|
feed('<C-N><C-N><Esc>')
|
||||||
|
eq(eval('mark'), eval("nvim_buf_get_extmark_by_id(0, ns_id, mark_id, { 'details':1 })"))
|
||||||
|
feed('A<C-N>')
|
||||||
|
eq(eval('mark'), eval("nvim_buf_get_extmark_by_id(0, ns_id, mark_id, { 'details':1 })"))
|
||||||
|
feed('<C-N>')
|
||||||
|
screen:expect([[
|
||||||
|
aaaaa^ |
|
||||||
|
{1:aaaa } |
|
||||||
|
{2:aaaaa } |
|
||||||
|
{3:-- Keyword completion (^N^P) }{4:match 2 of 2} |
|
||||||
|
]])
|
||||||
|
feed('<C-E>')
|
||||||
|
screen:expect([[
|
||||||
|
{7:aa}aa^ |
|
||||||
|
aaaa |
|
||||||
|
aaaaa |
|
||||||
|
{3:-- INSERT --} |
|
||||||
|
]])
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
Loading…
Reference in New Issue
Block a user