aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/extmark.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/extmark.c')
-rw-r--r--src/nvim/extmark.c166
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);