mirror of
https://github.com/neovim/neovim.git
synced 2025-09-11 13:58:18 +00:00
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:
@@ -2184,6 +2184,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
|
||||
getpid() Number process ID of Vim
|
||||
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
|
||||
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()*
|
||||
Returns a |List| with all matches previously defined for the
|
||||
current window by |matchadd()| and the |:match| commands.
|
||||
|
@@ -723,6 +723,7 @@ Cursor and mark position: *cursor-functions* *mark-functions*
|
||||
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
|
||||
|
@@ -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},
|
||||
|
@@ -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
|
||||
*/
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user