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)
cfb4b47de0

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>
This commit is contained in:
Jan Edmund Lazo
2021-01-03 15:33:21 -05:00
committed by GitHub
parent fff4facdc4
commit a1ed941a78
6 changed files with 149 additions and 0 deletions

View File

@@ -2184,6 +2184,7 @@ getjumplist([{winnr} [, {tabnr}]])
getline({lnum}) String line {lnum} of current buffer getline({lnum}) String line {lnum} of current buffer
getline({lnum}, {end}) List lines {lnum} to {end} of current buffer getline({lnum}, {end}) List lines {lnum} to {end} of current buffer
getloclist({nr} [, {what}]) List list of location list items getloclist({nr} [, {what}]) List list of location list items
getmarklist([{expr}]) List list of global/local marks
getmatches([{win}]) List list of current matches getmatches([{win}]) List list of current matches
getpid() Number process ID of Vim getpid() Number process ID of Vim
getpos({expr}) List position of cursor, mark, etc. getpos({expr}) List position of cursor, mark, etc.
@@ -4649,6 +4650,24 @@ getloclist({nr},[, {what}]) *getloclist()*
field is applicable only when called from a location list field is applicable only when called from a location list
window. See |location-list-file-window| for more details. window. See |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()* getmatches([{win}]) *getmatches()*
Returns a |List| with all matches previously defined for the Returns a |List| with all matches previously defined for the
current window by |matchadd()| and the |:match| commands. current window by |matchadd()| and the |:match| commands.

View File

@@ -723,6 +723,7 @@ Cursor and mark position: *cursor-functions* *mark-functions*
getcurpos() get position of the cursor getcurpos() get position of the cursor
getpos() get position of cursor, mark, etc. getpos() get position of cursor, mark, etc.
setpos() set 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 byte2line() get line number at a specific byte count
line2byte() byte count at a specific line line2byte() byte count at a specific line
diff_filler() get the number of filler lines above a line diff_filler() get the number of filler lines above a line

View File

@@ -150,6 +150,7 @@ return {
getjumplist={args={0, 2}}, getjumplist={args={0, 2}},
getline={args={1, 2}}, getline={args={1, 2}},
getloclist={args={1, 2}}, getloclist={args={1, 2}},
getmarklist={args={0, 1}},
getmatches={args={0, 1}}, getmatches={args={0, 1}},
getpid={}, getpid={},
getpos={args=1}, getpos={args=1},

View File

@@ -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); 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 * "getmatches()" function
*/ */

View File

@@ -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);
}
}
}
}

View File

@@ -201,3 +201,28 @@ func Test_mark_error()
call assert_fails('mark xx', 'E488:') call assert_fails('mark xx', 'E488:')
call assert_fails('mark _', 'E191:') call assert_fails('mark _', 'E191:')
endfunc 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