# HG changeset patch # User Bram Moolenaar # Date 1590932704 -7200 # Node ID 8eed1e9389bb31a36fc86572cfa0976ae1e77f24 # Parent 78caf677340d8991f44219fe8c2cb1d74947613f patch 8.2.0861: cannot easily get all the current marks Commit: https://github.com/vim/vim/commit/cfb4b47de08e4437c692d382067dc1692cd83c23 Author: Bram Moolenaar Date: Sun May 31 15:41:57 2020 +0200 patch 8.2.0861: cannot easily get all the current marks Problem: Cannot easily get all the current marks. Solution: Add getmarklist(). (Yegappan Lakshmanan, closes https://github.com/vim/vim/issues/6032) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2497,6 +2497,7 @@ getjumplist([{winnr} [, {tabnr}]]) getline({lnum}) String line {lnum} of current buffer getline({lnum}, {end}) List lines {lnum} to {end} of current buffer getloclist({nr} [, {what}]) List list of location list items +getmarklist([{expr}]) List list of global/local marks getmatches([{win}]) List list of current matches getmousepos() Dict last known mouse position getpid() Number process ID of Vim @@ -5365,6 +5366,25 @@ getloclist({nr} [, {what}]) *getlocli |location-list-file-window| for more details. +getmarklist([{expr}] *getmarklist()* + Without the {expr} argument returns a |List| with information + about all the global marks. |mark| + + If the optional {expr} argument is specified, returns the + local marks defined in buffer {expr}. For the use of {expr}, + see |bufname()|. + + Each item in the retuned List is a |Dict| with the following: + name - name of the mark prefixed by "'" + pos - a |List| with the position of the mark: + [bufnum, lnum, col, off] + Refer to |getpos()| for more information. + file - file name + + Refer to |getpos()| for getting information about a specific + mark. + + getmatches([{win}]) *getmatches()* Returns a |List| with all matches previously defined for the current window by |matchadd()| and the |:match| commands. diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt --- a/runtime/doc/usr_41.txt +++ b/runtime/doc/usr_41.txt @@ -724,6 +724,7 @@ Cursor and mark position: *cursor-funct getcurpos() get position of the cursor getpos() get position of cursor, mark, etc. setpos() set position of cursor, mark, etc. + getmarklist() list of global/local marks byte2line() get line number at a specific byte count line2byte() byte count at a specific line diff_filler() get the number of filler lines above a line diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -579,6 +579,7 @@ static funcentry_T global_functions[] = {"getjumplist", 0, 2, FEARG_1, ret_list_any, f_getjumplist}, {"getline", 1, 2, FEARG_1, ret_f_getline, f_getline}, {"getloclist", 1, 2, 0, ret_list_dict_any, f_getloclist}, + {"getmarklist", 0, 1, 0, ret_list_dict_any, f_getmarklist}, {"getmatches", 0, 1, 0, ret_list_dict_any, f_getmatches}, {"getmousepos", 0, 0, 0, ret_dict_number, f_getmousepos}, {"getpid", 0, 0, 0, ret_number, f_getpid}, diff --git a/src/mark.c b/src/mark.c --- a/src/mark.c +++ b/src/mark.c @@ -1412,3 +1412,124 @@ get_namedfm(void) { return namedfm; } + +#if defined(FEAT_EVAL) || defined(PROTO) +/* + * Add information about mark 'mname' to list 'l' + */ + static int +add_mark(list_T *l, char_u *mname, pos_T *pos, int bufnr, char_u *fname) +{ + dict_T *d; + list_T *lpos; + + if (pos->lnum <= 0) + return OK; + + d = dict_alloc(); + if (d == NULL) + return FAIL; + + if (list_append_dict(l, d) == FAIL) + { + dict_unref(d); + return FAIL; + } + + lpos = list_alloc(); + if (lpos == NULL) + return FAIL; + + list_append_number(lpos, bufnr); + list_append_number(lpos, pos->lnum); + list_append_number(lpos, pos->col); + list_append_number(lpos, pos->coladd); + + if (dict_add_string(d, "mark", mname) == FAIL + || dict_add_list(d, "pos", lpos) == FAIL + || (fname != NULL && dict_add_string(d, "file", fname) == FAIL)) + return FAIL; + + return OK; +} + +/* + * Get information about marks local to a buffer. + */ + static void +get_buf_local_marks(buf_T *buf, list_T *l) +{ + char_u mname[3] = "' "; + int i; + + // Marks 'a' to 'z' + for (i = 0; i < NMARKS; ++i) + { + mname[1] = 'a' + i; + add_mark(l, mname, &buf->b_namedm[i], buf->b_fnum, NULL); + } + + // Mark '' is a window local mark and not a buffer local mark + add_mark(l, (char_u *)"''", &curwin->w_pcmark, curbuf->b_fnum, NULL); + + add_mark(l, (char_u *)"'\"", &buf->b_last_cursor, buf->b_fnum, NULL); + add_mark(l, (char_u *)"'[", &buf->b_op_start, buf->b_fnum, NULL); + add_mark(l, (char_u *)"']", &buf->b_op_end, buf->b_fnum, NULL); + add_mark(l, (char_u *)"'^", &buf->b_last_insert, buf->b_fnum, NULL); + add_mark(l, (char_u *)"'.", &buf->b_last_change, buf->b_fnum, NULL); + add_mark(l, (char_u *)"'<", &buf->b_visual.vi_start, buf->b_fnum, NULL); + add_mark(l, (char_u *)"'>", &buf->b_visual.vi_end, buf->b_fnum, NULL); +} + +/* + * Get information about global marks ('A' to 'Z' and '0' to '9') + */ + static void +get_global_marks(list_T *l) +{ + char_u mname[3] = "' "; + int i; + char_u *name; + + // Marks 'A' to 'Z' and '0' to '9' + for (i = 0; i < NMARKS + EXTRA_MARKS; ++i) + { + if (namedfm[i].fmark.fnum != 0) + name = buflist_nr2name(namedfm[i].fmark.fnum, TRUE, TRUE); + else + name = namedfm[i].fname; + if (name != NULL) + { + mname[1] = i >= NMARKS ? i - NMARKS + '0' : i + 'A'; + add_mark(l, mname, &namedfm[i].fmark.mark, + namedfm[i].fmark.fnum, name); + if (namedfm[i].fmark.fnum != 0) + vim_free(name); + } + } +} + +/* + * getmarklist() function + */ + void +f_getmarklist(typval_T *argvars, typval_T *rettv) +{ + buf_T *buf = NULL; + + if (rettv_list_alloc(rettv) != OK) + return; + + if (argvars[0].v_type == VAR_UNKNOWN) + { + get_global_marks(rettv->vval.v_list); + return; + } + + buf = tv_get_buf(&argvars[0], FALSE); + if (buf == NULL) + return; + + get_buf_local_marks(buf, rettv->vval.v_list); +} +#endif diff --git a/src/proto/mark.pro b/src/proto/mark.pro --- a/src/proto/mark.pro +++ b/src/proto/mark.pro @@ -27,4 +27,5 @@ void free_jumplist(win_T *wp); void set_last_cursor(win_T *win); void free_all_marks(void); xfmark_T *get_namedfm(void); +void f_getmarklist(typval_T *argvars, typval_T *rettv); /* vim: set ft=c : */ diff --git a/src/testdir/test_marks.vim b/src/testdir/test_marks.vim --- a/src/testdir/test_marks.vim +++ b/src/testdir/test_marks.vim @@ -259,4 +259,29 @@ func Test_file_mark() call delete('Xtwo') 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, 0, 0]}, + \ {'file' : '', 'mark' : "'N", 'pos' : [bufnr(), 3, 4, 0]}], + \ getmarklist()) + " buffer local marks + delmarks! + call assert_equal([{'mark' : "''", 'pos' : [bufnr(), 1, 0, 0]}, + \ {'mark' : "'\"", 'pos' : [bufnr(), 1, 0, 0]}], getmarklist(bufnr())) + call cursor(2, 2) + normal mr + call assert_equal({'mark' : "'r", 'pos' : [bufnr(), 2, 1, 0]}, + \ getmarklist(bufnr())[0]) + call assert_equal([], getmarklist({})) + close! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -747,6 +747,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 861, +/**/ 860, /**/ 859,