aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJan Edmund Lazo <jan.lazo@mail.utoronto.ca>2021-01-03 15:33:21 -0500
committerGitHub <noreply@github.com>2021-01-03 15:33:21 -0500
commita1ed941a7881122fda2fd48e71e890ed55e4d08e (patch)
tree8fc3e1fcdf98861d8f6ca0c59de55814e6a73d79 /src
parentfff4facdc47a0c8d088256af4d07c792b38b4a03 (diff)
downloadrneovim-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.lua1
-rw-r--r--src/nvim/eval/funcs.c19
-rw-r--r--src/nvim/mark.c84
-rw-r--r--src/nvim/testdir/test_marks.vim25
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