diff --git a/src/nvim/mark.c b/src/nvim/mark.c index 39fc623676..6480a47344 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -51,9 +51,6 @@ // There are marks 'A - 'Z (set by user) and '0 to '9 (set when writing // shada). -/// Global marks (marks with file number or name) -static xfmark_T namedfm[NGLOBALMARKS]; - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "mark.c.generated.h" #endif @@ -935,6 +932,7 @@ void ex_delmarks(exarg_T *eap) emsg(_(e_argreq)); } else { // clear specified marks only + const Timestamp timestamp = os_time(); for (p = eap->arg; *p != NUL; p++) { lower = ASCII_ISLOWER(*p); digit = ascii_isdigit(*p); @@ -959,6 +957,7 @@ void ex_delmarks(exarg_T *eap) for (int i = from; i <= to; i++) { if (lower) { curbuf->b_namedm[i - 'a'].mark.lnum = 0; + curbuf->b_namedm[i - 'a'].timestamp = timestamp; } else { if (digit) { n = i - '0' + NMARKS; @@ -967,17 +966,24 @@ void ex_delmarks(exarg_T *eap) } namedfm[n].fmark.mark.lnum = 0; namedfm[n].fmark.fnum = 0; + namedfm[n].fmark.timestamp = timestamp; XFREE_CLEAR(namedfm[n].fname); } } } else { switch (*p) { case '"': - CLEAR_FMARK(&curbuf->b_last_cursor); break; + curbuf->b_last_cursor.timestamp = timestamp; + CLEAR_FMARK(&curbuf->b_last_cursor); + break; case '^': - CLEAR_FMARK(&curbuf->b_last_insert); break; + curbuf->b_last_insert.timestamp = timestamp; + CLEAR_FMARK(&curbuf->b_last_insert); + break; case '.': - CLEAR_FMARK(&curbuf->b_last_change); break; + curbuf->b_last_change.timestamp = timestamp; + CLEAR_FMARK(&curbuf->b_last_change); + break; case '[': curbuf->b_op_start.lnum = 0; break; case ']': diff --git a/src/nvim/mark_defs.h b/src/nvim/mark_defs.h index cfe19eac6f..6be919a7ab 100644 --- a/src/nvim/mark_defs.h +++ b/src/nvim/mark_defs.h @@ -86,4 +86,7 @@ typedef struct xfilemark { #define INIT_XFMARK { INIT_FMARK, NULL } +/// Global marks (marks with file number or name) +EXTERN xfmark_T namedfm[NGLOBALMARKS] INIT(= { 0 }); + #endif // NVIM_MARK_DEFS_H diff --git a/src/nvim/shada.c b/src/nvim/shada.c index f8c448dce0..49136402ac 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -2160,6 +2160,12 @@ static inline ShaDaWriteResult shada_read_when_writing(ShaDaReadDef *const sd_re shada_free_shada_entry(&entry); break; } + if (wms->global_marks[idx].data.type == kSDItemMissing) { + if (namedfm[idx].fmark.timestamp >= entry.timestamp) { + shada_free_shada_entry(&entry); + break; + } + } COMPARE_WITH_ENTRY(&wms->global_marks[idx], entry); } break; @@ -2189,6 +2195,7 @@ static inline ShaDaWriteResult shada_read_when_writing(ShaDaReadDef *const sd_re entry; } else { PossiblyFreedShadaEntry *const wms_entry = &filemarks->marks[idx]; + bool set_wms = true; if (wms_entry->data.type != kSDItemMissing) { if (wms_entry->data.timestamp >= entry.timestamp) { shada_free_shada_entry(&entry); @@ -2200,8 +2207,23 @@ static inline ShaDaWriteResult shada_read_when_writing(ShaDaReadDef *const sd_re } shada_free_shada_entry(&wms_entry->data); } + } else { + FOR_ALL_BUFFERS(buf) { + if (buf->b_ffname != NULL + && path_fnamecmp(entry.data.filemark.fname, buf->b_ffname) == 0) { + fmark_T fm; + mark_get(buf, curwin, &fm, kMarkBufLocal, (int)entry.data.filemark.name); + if (fm.timestamp >= entry.timestamp) { + set_wms = false; + shada_free_shada_entry(&entry); + break; + } + } + } + } + if (set_wms) { + *wms_entry = pfs_entry; } - *wms_entry = pfs_entry; } } else { #define AFTERFREE_DUMMY(entry) diff --git a/test/functional/shada/marks_spec.lua b/test/functional/shada/marks_spec.lua index a91be18841..07364382e8 100644 --- a/test/functional/shada/marks_spec.lua +++ b/test/functional/shada/marks_spec.lua @@ -3,6 +3,7 @@ local helpers = require('test.functional.helpers')(after_each) local meths, curwinmeths, curbufmeths, nvim_command, funcs, eq = helpers.meths, helpers.curwinmeths, helpers.curbufmeths, helpers.command, helpers.funcs, helpers.eq +local feed = helpers.feed local exc_exec, exec_capture = helpers.exc_exec, helpers.exec_capture local expect_exit = helpers.expect_exit @@ -248,4 +249,24 @@ describe('ShaDa support code', function() eq('', funcs.system(argv)) eq(0, exc_exec('rshada')) end) + + it('updates deleted marks', function() + nvim_command('edit ' .. testfilename) + + nvim_command('mark A') + nvim_command('mark a') + -- create a change to set the '.' mark, + -- since it can't be set via :mark + feed('ggifoobar') + nvim_command('wshada') + nvim_command('normal! `A`a`.') + + nvim_command('delmarks A a .') + nvim_command('wshada') + + reset() + eq('Vim(normal):E20: Mark not set', exc_exec('normal! `A')) + eq('Vim(normal):E20: Mark not set', exc_exec('normal! `a')) + eq('Vim(normal):E20: Mark not set', exc_exec('normal! `.')) + end) end)