diff options
Diffstat (limited to 'src/nvim/extmark.c')
-rw-r--r-- | src/nvim/extmark.c | 166 |
1 files changed, 97 insertions, 69 deletions
diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c index d9c1993f32..c4a34f8019 100644 --- a/src/nvim/extmark.c +++ b/src/nvim/extmark.c @@ -32,14 +32,18 @@ #include "nvim/buffer_defs.h" #include "nvim/buffer_updates.h" #include "nvim/decoration.h" +#include "nvim/decoration_defs.h" #include "nvim/extmark.h" #include "nvim/extmark_defs.h" #include "nvim/globals.h" #include "nvim/map_defs.h" #include "nvim/marktree.h" #include "nvim/memline.h" +#include "nvim/memory.h" #include "nvim/pos_defs.h" +#include "nvim/types_defs.h" #include "nvim/undo.h" +#include "nvim/undo_defs.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "extmark.c.generated.h" @@ -50,12 +54,12 @@ /// must not be used during iteration! void extmark_set(buf_T *buf, uint32_t ns_id, uint32_t *idp, int row, colnr_T col, int end_row, colnr_T end_col, DecorInline decor, uint16_t decor_flags, bool right_gravity, - bool end_right_gravity, bool no_undo, bool invalidate, Error *err) + bool end_right_gravity, bool no_undo, bool invalidate, bool scoped, Error *err) { uint32_t *ns = map_put_ref(uint32_t, uint32_t)(buf->b_extmark_ns, ns_id, NULL, NULL); uint32_t id = idp ? *idp : 0; - uint16_t flags = mt_flags(right_gravity, no_undo, invalidate, decor.ext) | decor_flags; + uint16_t flags = mt_flags(right_gravity, no_undo, invalidate, decor.ext, scoped) | decor_flags; if (id == 0) { id = ++*ns; } else { @@ -66,19 +70,27 @@ void extmark_set(buf_T *buf, uint32_t ns_id, uint32_t *idp, int row, colnr_T col extmark_del_id(buf, ns_id, id); } else { assert(marktree_itr_valid(itr)); + bool invalid = mt_invalid(old_mark); if (old_mark.pos.row == row && old_mark.pos.col == col) { - if (mt_decor_any(old_mark)) { - buf_decor_remove(buf, row, row, mt_decor(old_mark), true); - } - // not paired: we can revise in place - mt_itr_rawkey(itr).flags &= (uint16_t) ~MT_FLAG_EXTERNAL_MASK; - mt_itr_rawkey(itr).flags |= flags; + if (!invalid && mt_decor_any(old_mark)) { + // TODO(bfredl): conflict of concerns: buf_decor_remove() must process + // the buffer as if MT_FLAG_DECOR_SIGNTEXT is already removed, however + // marktree must precisely adjust the set of flags from the old set to the new + uint16_t save_flags = mt_itr_rawkey(itr).flags; + mt_itr_rawkey(itr).flags &= (uint16_t) ~MT_FLAG_DECOR_SIGNTEXT; + buf_decor_remove(buf, row, row, col, mt_decor(old_mark), true); + mt_itr_rawkey(itr).flags = save_flags; + } + marktree_revise_flags(buf->b_marktree, itr, flags); mt_itr_rawkey(itr).decor_data = decor.data; goto revised; } - buf_decor_remove(buf, old_mark.pos.row, old_mark.pos.row, mt_decor(old_mark), true); marktree_del_itr(buf->b_marktree, itr, false); + if (!invalid) { + buf_decor_remove(buf, old_mark.pos.row, old_mark.pos.row, old_mark.pos.col, + mt_decor(old_mark), true); + } } } else { *ns = MAX(*ns, id); @@ -92,7 +104,7 @@ void extmark_set(buf_T *buf, uint32_t ns_id, uint32_t *idp, int row, colnr_T col revised: if (decor_flags || decor.ext) { buf_put_decor(buf, decor, row, end_row > -1 ? end_row : row); - decor_redraw(buf, row, end_row > -1 ? end_row : row, decor); + decor_redraw(buf, row, end_row > -1 ? end_row : row, col, decor); } if (idp) { @@ -100,20 +112,39 @@ revised: } } -static bool extmark_setraw(buf_T *buf, uint64_t mark, int row, colnr_T col) +static void extmark_setraw(buf_T *buf, uint64_t mark, int row, colnr_T col, bool invalid) { MarkTreeIter itr[1] = { 0 }; MTKey key = marktree_lookup(buf->b_marktree, mark, itr); - if (key.pos.row == -1) { - return false; + if (key.pos.row < 0 || (key.pos.row == row && key.pos.col == col)) { + return; + } + + // Only the position before undo needs to be redrawn here, + // as the position after undo should be marked as changed. + if (!invalid && mt_decor_any(key) && key.pos.row != row) { + decor_redraw(buf, key.pos.row, key.pos.row, key.pos.col, mt_decor(key)); } - if (key.pos.row == row && key.pos.col == col) { - return true; + int row1 = 0; + int row2 = 0; + if (invalid) { + mt_itr_rawkey(itr).flags &= (uint16_t) ~MT_FLAG_INVALID; + } else if (key.flags & MT_FLAG_DECOR_SIGNTEXT && buf->b_signcols.autom) { + MTPos end = marktree_get_altpos(buf->b_marktree, key, NULL); + row1 = MIN(end.row, MIN(key.pos.row, row)); + row2 = MAX(end.row, MAX(key.pos.row, row)); + buf_signcols_count_range(buf, row1, row2, 0, kTrue); } marktree_move(buf->b_marktree, itr, row, col); - return true; + + if (invalid) { + MTPos end = marktree_get_altpos(buf->b_marktree, key, NULL); + buf_put_decor(buf, mt_decor(key), row, end.row); + } else if (key.flags & MT_FLAG_DECOR_SIGNTEXT && buf->b_signcols.autom) { + buf_signcols_count_range(buf, row1, row2, 0, kNone); + } } /// Remove an extmark in "ns_id" by "id" @@ -147,7 +178,11 @@ void extmark_del(buf_T *buf, MarkTreeIter *itr, MTKey key, bool restore) } if (mt_decor_any(key)) { - buf_decor_remove(buf, key.pos.row, key2.pos.row, mt_decor(key), true); + if (mt_invalid(key)) { + decor_free(mt_decor(key)); + } else { + buf_decor_remove(buf, key.pos.row, key2.pos.row, key.pos.col, mt_decor(key), true); + } } // TODO(bfredl): delete it from current undo header, opportunistically? @@ -218,7 +253,7 @@ ExtmarkInfoArray extmark_get(buf_T *buf, uint32_t ns_id, int l_row, colnr_T l_co } else { // Find all the marks beginning with the start position marktree_itr_get_ext(buf->b_marktree, MTPos(l_row, l_col), - itr, reverse, false, NULL); + itr, reverse, false, NULL, NULL); } int order = reverse ? -1 : 1; @@ -302,6 +337,9 @@ void extmark_free_all(buf_T *buf) marktree_clear(buf->b_marktree); + buf->b_signcols.max = 0; + CLEAR_FIELD(buf->b_signcols.count); + map_destroy(uint32_t, buf->b_extmark_ns); *buf->b_extmark_ns = (Map(uint32_t, uint32_t)) MAP_INIT; } @@ -311,9 +349,8 @@ void extmark_free_all(buf_T *buf) /// copying is useful when we cannot simply reverse the operation. This will do /// 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, - 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 }; ExtmarkUndoObject undo; @@ -328,38 +365,37 @@ void extmark_splice_delete(buf_T *buf, int l_row, colnr_T l_col, int u_row, coln bool invalidated = false; // 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); - if (endpos.row < 0) { - endpos = mark.pos; - } - if ((endpos.col <= u_col || (!u_col && endpos.row == mark.pos.row)) - && mark.pos.col >= l_col - && mark.pos.row >= l_row && endpos.row <= u_row - (u_col ? 0 : 1)) { + // Invalidate unpaired marks in deleted lines and paired marks whose entire + // range has been deleted. + if ((!mt_paired(mark) && mark.pos.row < u_row) + || (mt_paired(mark) + && (endpos.col <= u_col || (!u_col && endpos.row == mark.pos.row)) + && mark.pos.col >= l_col + && mark.pos.row >= l_row && endpos.row <= u_row - (u_col ? 0 : 1))) { if (mt_no_undo(mark)) { extmark_del(buf, itr, mark, true); continue; } else { invalidated = true; mt_itr_rawkey(itr).flags |= MT_FLAG_INVALID; - buf_decor_remove(buf, mark.pos.row, endpos.row, mt_decor(mark), false); + buf_decor_remove(buf, mark.pos.row, endpos.row, mark.pos.col, mt_decor(mark), false); } } } // Push mark to undo header - if (uhp && op == kExtmarkUndo && !mt_no_undo(mark)) { - ExtmarkSavePos pos; - pos.mark = mt_lookup_key(mark); - pos.invalidated = invalidated; - pos.old_row = mark.pos.row; - pos.old_col = mark.pos.col; - pos.row = -1; - pos.col = -1; - + if (only_copy || (uvp != NULL && op == kExtmarkUndo && !mt_no_undo(mark))) { + ExtmarkSavePos pos = { + .mark = mt_lookup_key(mark), + .invalidated = invalidated, + .old_row = mark.pos.row, + .old_col = mark.pos.col + }; undo.data.savepos = pos; undo.type = kExtmarkSavePos; - kv_push(uhp->uh_extmark, undo); + kv_push(*uvp, undo); } marktree_itr_next(buf->b_marktree, itr); @@ -389,23 +425,10 @@ void extmark_apply_undo(ExtmarkUndoObject undo_info, bool undo) // kExtmarkSavePos } else if (undo_info.type == kExtmarkSavePos) { ExtmarkSavePos pos = undo_info.data.savepos; - if (undo) { - if (pos.invalidated) { - MarkTreeIter itr[1] = { 0 }; - MTKey mark = marktree_lookup(curbuf->b_marktree, pos.mark, itr); - mt_itr_rawkey(itr).flags &= (uint16_t) ~MT_FLAG_INVALID; - MTPos end = marktree_get_altpos(curbuf->b_marktree, mark, itr); - buf_put_decor(curbuf, mt_decor(mark), mark.pos.row, end.row < 0 ? mark.pos.row : end.row); - } - if (pos.old_row >= 0) { - extmark_setraw(curbuf, pos.mark, pos.old_row, pos.old_col); - } - // Redo - } else { - if (pos.row >= 0) { - extmark_setraw(curbuf, pos.mark, pos.row, pos.col); - } + if (undo && pos.old_row >= 0) { + extmark_setraw(curbuf, pos.mark, pos.old_row, pos.old_col, pos.invalidated); } + // No Redo since kExtmarkSplice will move marks back } else if (undo_info.type == kExtmarkMove) { ExtmarkMove move = undo_info.data.move; if (undo) { @@ -432,8 +455,10 @@ void extmark_adjust(buf_T *buf, linenr_T line1, linenr_T line2, linenr_T amount, return; } bcount_t start_byte = ml_find_line_or_offset(buf, line1, NULL, true); - bcount_t old_byte = 0, new_byte = 0; - int old_row, new_row; + bcount_t old_byte = 0; + bcount_t new_byte = 0; + int old_row; + int new_row; if (amount == MAXLNUM) { old_row = line2 - line1 + 1; // TODO(bfredl): ej kasta? @@ -511,27 +536,24 @@ void extmark_splice_impl(buf_T *buf, int start_row, colnr_T start_col, bcount_t // merge!) int end_row = start_row + old_row; 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 - if (buf->b_signs_with_text && buf->b_signcols.sentinel) { - linenr_T se_lnum = buf->b_signcols.sentinel; - if (se_lnum >= start_row) { - if (old_row != 0 && se_lnum > old_row + start_row) { - buf->b_signcols.sentinel += new_row - old_row; - } else if (new_row == 0) { - buf->b_signcols.sentinel = 0; - } else { - buf->b_signcols.sentinel += new_row; - } - } + // Remove signs inside edited region from "b_signcols.count", add after splicing. + if (old_row > 0 || new_row > 0) { + buf_signcols_count_range(buf, start_row, start_row + old_row, 0, kTrue); } marktree_splice(buf->b_marktree, (int32_t)start_row, start_col, old_row, old_col, new_row, new_col); + if (old_row > 0 || new_row > 0) { + buf_signcols_count_range(buf, start_row, start_row + new_row, 0, kNone); + } + if (undo == kExtmarkUndo) { u_header_T *uhp = u_force_get_undo_header(buf); if (!uhp) { @@ -610,10 +632,16 @@ void extmark_move_region(buf_T *buf, int start_row, colnr_T start_col, bcount_t extent_row, extent_col, extent_byte, 0, 0, 0); + int row1 = MIN(start_row, new_row); + int row2 = MAX(start_row, new_row) + extent_row; + buf_signcols_count_range(buf, row1, row2, 0, kTrue); + marktree_move_region(buf->b_marktree, start_row, start_col, extent_row, extent_col, new_row, new_col); + buf_signcols_count_range(buf, row1, row2, 0, kNone); + buf_updates_send_splice(buf, new_row, new_col, new_byte, 0, 0, 0, extent_row, extent_col, extent_byte); |