diff options
author | Jan Edmund Lazo <jan.lazo@mail.utoronto.ca> | 2021-01-03 15:33:21 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-03 15:33:21 -0500 |
commit | a1ed941a7881122fda2fd48e71e890ed55e4d08e (patch) | |
tree | 8fc3e1fcdf98861d8f6ca0c59de55814e6a73d79 /src | |
parent | fff4facdc47a0c8d088256af4d07c792b38b4a03 (diff) | |
download | rneovim-a1ed941a7881122fda2fd48e71e890ed55e4d08e.tar.gz rneovim-a1ed941a7881122fda2fd48e71e890ed55e4d08e.tar.bz2 rneovim-a1ed941a7881122fda2fd48e71e890ed55e4d08e.zip |
vim-patch:8.2.0861: cannot easily get all the current marks (#13676)
Problem: Cannot easily get all the current marks.
Solution: Add getmarklist(). (Yegappan Lakshmanan, closes #6032)
https://github.com/vim/vim/commit/cfb4b47de08e4437c692d382067dc1692cd83c23
Cherry-pick the column number fix from patch v8.2.0871
because patch v8.2.0871 cannot be fully ported
without the method patches.
Co-authored-by: Peter Wolf <pwolf2310@gmail.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/eval.lua | 1 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 19 | ||||
-rw-r--r-- | src/nvim/mark.c | 84 | ||||
-rw-r--r-- | src/nvim/testdir/test_marks.vim | 25 |
4 files changed, 129 insertions, 0 deletions
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 466f1800c7..952fa35b83 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -150,6 +150,7 @@ return { getjumplist={args={0, 2}}, getline={args={1, 2}}, getloclist={args={1, 2}}, + getmarklist={args={0, 1}}, getmatches={args={0, 1}}, getpid={}, getpos={args=1}, diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 06baed4d5f..8235d74cbb 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -3483,6 +3483,25 @@ static void f_getloclist(typval_T *argvars, typval_T *rettv, FunPtr fptr) get_qf_loc_list(false, wp, &argvars[1], rettv); } + +/// "getmarklist()" function +static void f_getmarklist(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + tv_list_alloc_ret(rettv, kListLenMayKnow); + + if (argvars[0].v_type == VAR_UNKNOWN) { + get_global_marks(rettv->vval.v_list); + return; + } + + buf_T *buf = tv_get_buf(&argvars[0], false); + if (buf == NULL) { + return; + } + + get_buf_local_marks(buf, rettv->vval.v_list); +} + /* * "getmatches()" function */ diff --git a/src/nvim/mark.c b/src/nvim/mark.c index 1ecfae57ed..45ca097033 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -1552,3 +1552,87 @@ void mark_mb_adjustpos(buf_T *buf, pos_T *lp) } } } + + +// Add information about mark 'mname' to list 'l' +static int add_mark(list_T *l, const char *mname, const pos_T *pos, int bufnr, + const char *fname) + FUNC_ATTR_NONNULL_ARG(1, 2, 3) +{ + if (pos->lnum <= 0) { + return OK; + } + + dict_T *d = tv_dict_alloc(); + tv_list_append_dict(l, d); + + list_T *lpos = tv_list_alloc(kListLenMayKnow); + + tv_list_append_number(lpos, bufnr); + tv_list_append_number(lpos, pos->lnum); + tv_list_append_number(lpos, pos->col + 1); + tv_list_append_number(lpos, pos->coladd); + + if (tv_dict_add_str(d, S_LEN("mark"), mname) == FAIL + || tv_dict_add_list(d, S_LEN("pos"), lpos) == FAIL + || (fname != NULL && tv_dict_add_str(d, S_LEN("file"), fname) == FAIL)) { + return FAIL; + } + + return OK; +} + + +/// Get information about marks local to a buffer. +/// +/// @param[in] buf Buffer to get the marks from +/// @param[out] l List to store marks +void get_buf_local_marks(const buf_T *buf, list_T *l) + FUNC_ATTR_NONNULL_ALL +{ + char mname[3] = "' "; + + // Marks 'a' to 'z' + for (int i = 0; i < NMARKS; i++) { + mname[1] = (char)('a' + i); + add_mark(l, mname, &buf->b_namedm[i].mark, buf->b_fnum, NULL); + } + + // Mark '' is a window local mark and not a buffer local mark + add_mark(l, "''", &curwin->w_pcmark, curbuf->b_fnum, NULL); + + add_mark(l, "'\"", &buf->b_last_cursor.mark, buf->b_fnum, NULL); + add_mark(l, "'[", &buf->b_op_start, buf->b_fnum, NULL); + add_mark(l, "']", &buf->b_op_end, buf->b_fnum, NULL); + add_mark(l, "'^", &buf->b_last_insert.mark, buf->b_fnum, NULL); + add_mark(l, "'.", &buf->b_last_change.mark, buf->b_fnum, NULL); + add_mark(l, "'<", &buf->b_visual.vi_start, buf->b_fnum, NULL); + add_mark(l, "'>", &buf->b_visual.vi_end, buf->b_fnum, NULL); +} + +/// Get information about global marks ('A' to 'Z' and '0' to '9') +/// +/// @param[out] l List to store global marks +void get_global_marks(list_T *l) + FUNC_ATTR_NONNULL_ALL +{ + char mname[3] = "' "; + char *name; + + // Marks 'A' to 'Z' and '0' to '9' + for (int i = 0; i < NMARKS + EXTRA_MARKS; i++) { + if (namedfm[i].fmark.fnum != 0) { + name = (char *)buflist_nr2name(namedfm[i].fmark.fnum, true, true); + } else { + name = (char *)namedfm[i].fname; + } + if (name != NULL) { + mname[1] = i >= NMARKS ? (char)(i - NMARKS + '0') : (char)(i + 'A'); + + add_mark(l, mname, &namedfm[i].fmark.mark, namedfm[i].fmark.fnum, name); + if (namedfm[i].fmark.fnum != 0) { + xfree(name); + } + } + } +} diff --git a/src/nvim/testdir/test_marks.vim b/src/nvim/testdir/test_marks.vim index 66df57ea39..e25fe33bb7 100644 --- a/src/nvim/testdir/test_marks.vim +++ b/src/nvim/testdir/test_marks.vim @@ -201,3 +201,28 @@ func Test_mark_error() call assert_fails('mark xx', 'E488:') call assert_fails('mark _', 'E191:') endfunc + +" Test for the getmarklist() function +func Test_getmarklist() + new + " global marks + delmarks A-Z 0-9 \" ^.[] + call assert_equal([], getmarklist()) + call setline(1, ['one', 'two', 'three']) + mark A + call cursor(3, 5) + normal mN + call assert_equal([{'file' : '', 'mark' : "'A", 'pos' : [bufnr(), 1, 1, 0]}, + \ {'file' : '', 'mark' : "'N", 'pos' : [bufnr(), 3, 5, 0]}], + \ getmarklist()) + " buffer local marks + delmarks! + call assert_equal([{'mark' : "''", 'pos' : [bufnr(), 1, 1, 0]}, + \ {'mark' : "'\"", 'pos' : [bufnr(), 1, 1, 0]}], getmarklist(bufnr())) + call cursor(2, 2) + normal mr + call assert_equal({'mark' : "'r", 'pos' : [bufnr(), 2, 2, 0]}, + \ getmarklist(bufnr())[0]) + call assert_equal([], getmarklist({})) + close! +endfunc |