aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/buffer_defs.h3
-rw-r--r--src/nvim/eval.c2
-rw-r--r--src/nvim/eval/funcs.c1
-rw-r--r--src/nvim/ex_docmd.c8
-rw-r--r--src/nvim/map.c1
-rw-r--r--src/nvim/map.h1
-rw-r--r--src/nvim/mark.c159
-rw-r--r--src/nvim/option.c4
-rw-r--r--src/nvim/option_defs.h2
-rw-r--r--src/nvim/options.lua7
10 files changed, 181 insertions, 7 deletions
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 0d34200d89..e45addb790 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -672,9 +672,10 @@ struct file_buffer {
#ifdef BACKSLASH_IN_FILENAME
char *b_p_csl; ///< 'completeslash'
#endif
+ char *b_p_tfu; ///< 'tagfunc'
char *b_p_cfu; ///< 'completefunc'
char *b_p_ofu; ///< 'omnifunc'
- char *b_p_tfu; ///< 'tagfunc'
+ char *b_p_umf; ///< 'usermarkfunc'
int b_p_eol; ///< 'endofline'
int b_p_fixeol; ///< 'fixendofline'
int b_p_et; ///< 'expandtab'
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index ead01fcbad..8969b2d227 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -6410,7 +6410,7 @@ pos_T *var2fpos(const typval_T *const tv, const bool dollar_lnum, int *const ret
}
} else if (name[0] == '\'') {
// mark
- int mname = (uint8_t)name[1];
+ int mname = utf_ptr2char(name + 1);
const fmark_T *const fm = mark_get(curbuf, curwin, NULL, kMarkAll, mname);
if (fm == NULL || fm->mark.lnum <= 0) {
return NULL;
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 4a139c85d1..19e8dda0a7 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -3635,6 +3635,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
"title",
"user-commands", // was accidentally included in 5.4
"user_commands",
+ "usermarks",
"vartabs",
"vertsplit",
"vimscript-1",
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 5defabc05a..2045f5d28e 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -3144,7 +3144,7 @@ char *skip_range(const char *cmd, int *ctx)
}
}
if (*cmd != NUL) {
- cmd++;
+ cmd += utf_ptr2len(cmd);
}
}
@@ -3287,13 +3287,13 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int
goto error;
}
if (skip) {
- cmd++;
+ cmd += utfc_ptr2len(cmd);
} else {
// Only accept a mark in another file when it is
// used by itself: ":'M".
MarkGet flag = to_other_file && cmd[1] == NUL ? kMarkAll : kMarkBufLocal;
- fmark_T *fm = mark_get(curbuf, curwin, NULL, flag, *cmd);
- cmd++;
+ fmark_T *fm = mark_get(curbuf, curwin, NULL, flag, utf_ptr2char(cmd));
+ cmd += utf_ptr2len(cmd);
if (fm != NULL && fm->fnum != curbuf->handle) {
// Jumped to another file.
lnum = curwin->w_cursor.lnum;
diff --git a/src/nvim/map.c b/src/nvim/map.c
index 1561b089a7..d62eb94109 100644
--- a/src/nvim/map.c
+++ b/src/nvim/map.c
@@ -163,6 +163,7 @@ static inline bool ColorKey_eq(ColorKey ae1, ColorKey ae2)
return memcmp(&ae1, &ae2, sizeof(ae1)) == 0;
}
+MAP_IMPL(int, ptr_t, DEFAULT_INITIALIZER)
MAP_IMPL(int, int, DEFAULT_INITIALIZER)
MAP_IMPL(int, cstr_t, DEFAULT_INITIALIZER)
MAP_IMPL(cstr_t, ptr_t, DEFAULT_INITIALIZER)
diff --git a/src/nvim/map.h b/src/nvim/map.h
index f5f30f5a85..8b950300b3 100644
--- a/src/nvim/map.h
+++ b/src/nvim/map.h
@@ -34,6 +34,7 @@
//
// NOTE: Keys AND values must be allocated! khash.h does not make a copy.
//
+MAP_DECLS(int, ptr_t)
MAP_DECLS(int, int)
MAP_DECLS(int, cstr_t)
MAP_DECLS(cstr_t, ptr_t)
diff --git a/src/nvim/mark.c b/src/nvim/mark.c
index 6f8aecb3ff..049a3cb50b 100644
--- a/src/nvim/mark.c
+++ b/src/nvim/mark.c
@@ -15,10 +15,12 @@
#include "nvim/diff.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
+#include "nvim/eval/typval.h"
#include "nvim/ex_cmds.h"
#include "nvim/extmark.h"
#include "nvim/fold.h"
#include "nvim/mark.h"
+#include "nvim/mark_defs.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
@@ -36,6 +38,8 @@
#include "nvim/textobject.h"
#include "nvim/ui.h"
#include "nvim/vim.h"
+#include "nvim/map.h"
+#include "nvim/eval/userfunc.h"
// This file contains routines to maintain and manipulate marks.
@@ -48,6 +52,32 @@
/// Global marks (marks with file number or name)
static xfmark_T namedfm[NGLOBALMARKS];
+static struct {
+ Map(int, ptr_t) named;
+} usermarks;
+bool usermarks_init;
+
+static xfmark_T* lookup_user_mark(int mark)
+{
+ if (!usermarks_init) {
+ map_init(int, ptr_t, &usermarks.named);
+ usermarks_init = 1;
+ }
+
+ xfmark_T **ret =
+ (xfmark_T**) map_ref(int, ptr_t)(&usermarks.named, mark, true);
+
+ if (ret) {
+ if (! (*ret)) {
+ *ret = xcalloc(sizeof(xfmark_T), 1);
+ }
+
+ return *ret;
+ }
+
+ return NULL;
+}
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "mark.c.generated.h"
#endif
@@ -154,7 +184,8 @@ int setmark_pos(int c, pos_T *pos, int fnum, fmarkv_T *view_pt)
RESET_XFMARK(namedfm + i, *pos, fnum, view, NULL);
return OK;
}
- return FAIL;
+
+ return mark_set_user(buf, c);
}
// Set the previous context mark to the current position and add it to the
@@ -335,6 +366,15 @@ fmark_T *mark_get(buf_T *buf, win_T *win, fmark_T *fmp, MarkGet flag, int name)
// Local Marks
fm = mark_get_local(buf, win, name);
}
+
+ if (!fm) {
+ // Get usermark.
+ xfmark_T* xm = mark_get_user(buf, name);
+ if (xm) {
+ fm = &xm->fmark;
+ }
+ }
+
if (fmp != NULL && fm != NULL) {
*fmp = *fm;
return fmp;
@@ -423,6 +463,123 @@ fmark_T *mark_get_local(buf_T *buf, win_T *win, int name)
return mark;
}
+/// Loads the mark 'out' with the results from calling the usermarkfunc.
+///
+/// @param umf String for the usermarkfunc
+/// @param name name for the mark
+/// @param[out] out the mark to write the results to.
+static int call_umf(
+ const char* umf, int name, typval_T* out, const char* get_or_set_a)
+{
+ char markname_str[5];
+ char get_or_set[4];
+ int len;
+
+ strncpy(get_or_set, get_or_set_a, sizeof(get_or_set));
+ get_or_set[3] = 0;
+
+ len = (*utf_char2len)(name);
+ markname_str[len] = 0;
+ utf_char2bytes(name, markname_str);
+
+ typval_T args[3];
+ args[0].v_type = VAR_STRING;
+ args[1].v_type = VAR_STRING;
+ args[2].v_type = VAR_UNKNOWN;
+
+ args[0].vval.v_string = get_or_set;
+ args[1].vval.v_string = markname_str;
+
+ funcexe_T funcexe = FUNCEXE_INIT;
+ funcexe.evaluate = true;
+
+ return call_func(umf, -1, out, 2, args, &funcexe);
+}
+
+static int typval_to_xfmark(buf_T* buf, xfmark_T* out, typval_T* in)
+{
+ varnumber_T line;
+ varnumber_T col;
+ char* filename = NULL;
+
+ switch (in->v_type) {
+ case VAR_DICT:
+ line = tv_dict_get_number(in->vval.v_dict, "line");
+ col = tv_dict_get_number(in->vval.v_dict, "col");
+ filename = tv_dict_get_string(in->vval.v_dict, "file", true);
+ break;
+
+ case VAR_NUMBER:
+ line = in->vval.v_number;
+ col = 1;
+ break;
+
+ default:
+ return -1;
+ }
+
+ free_xfmark(*out);
+ memset(out, 0, sizeof(*out));
+
+ out->fname = filename;
+ out->fmark.mark.col = (int) col;
+ out->fmark.mark.lnum = (int) line;
+ out->fmark.fnum = 0;
+ out->fmark.timestamp = os_time();
+
+ return 0;
+}
+
+/// Gets marks that are defined by the user.
+///
+/// @param buf the buffer
+/// @param name name fo the mark
+xfmark_T *mark_get_user(buf_T* buf, int name)
+{
+ const char* umf = (const char*) buf->b_p_umf;
+
+ if (!umf) {
+ return NULL;
+ }
+
+ xfmark_T* mark = lookup_user_mark(name);
+ if (mark) {
+ typval_T* typval = xcalloc(sizeof(typval_T), 1);
+ call_umf(umf, name, typval, "get");
+ typval_to_xfmark(buf, mark, typval);
+ tv_free(typval);
+
+ if (mark->fname) {
+ buf_T* buffer =
+ buflist_new(
+ mark->fname, NULL, mark->fmark.mark.lnum, BLN_CURBUF | BLN_LISTED);
+
+ if (buffer) {
+ mark->fmark.fnum = buffer->b_fnum;
+ }
+ } else {
+ mark->fmark.fnum = buf->b_fnum;
+ }
+ }
+
+ return mark;
+}
+
+int mark_set_user(buf_T* buf, int name)
+{
+ const char* umf = (const char*) buf->b_p_umf;
+
+ if (!umf) {
+ return FAIL;
+ }
+
+ typval_T* out = xcalloc(sizeof(typval_T), 1);
+ call_umf(umf, name, out, "set");
+ tv_free(out);
+
+ return OK;
+}
+
/// Get marks that are actually motions but return them as marks
///
/// Gets the following motions as marks: '{', '}', '(', ')'
diff --git a/src/nvim/option.c b/src/nvim/option.c
index ab4db30aaf..540d3b714e 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -4119,6 +4119,8 @@ static char_u *get_varp(vimoption_T *p)
return (char_u *)&(curbuf->b_p_sw);
case PV_TFU:
return (char_u *)&(curbuf->b_p_tfu);
+ case PV_UMF:
+ return (char_u *)&(curbuf->b_p_umf);
case PV_TS:
return (char_u *)&(curbuf->b_p_ts);
case PV_TW:
@@ -4458,6 +4460,8 @@ void buf_copy_options(buf_T *buf, int flags)
COPY_OPT_SCTX(buf, BV_OFU);
buf->b_p_tfu = xstrdup(p_tfu);
COPY_OPT_SCTX(buf, BV_TFU);
+ buf->b_p_umf = vim_strsave(p_umf);
+ COPY_OPT_SCTX(buf, BV_UMF);
buf->b_p_sts = p_sts;
COPY_OPT_SCTX(buf, BV_STS);
buf->b_p_sts_nopaste = p_sts_nopaste;
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index 5dabc92bfc..fb7bd8588f 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -726,6 +726,7 @@ EXTERN unsigned int tpf_flags; ///< flags from 'termpastefilter'
#define TPF_DEL 0x010
#define TPF_C0 0x020
#define TPF_C1 0x040
+EXTERN char *p_umf; ///< 'usermarkfunc'
EXTERN char *p_tfu; ///< 'tagfunc'
EXTERN char *p_spc; ///< 'spellcapcheck'
EXTERN char *p_spf; ///< 'spellfile'
@@ -910,6 +911,7 @@ enum {
BV_SW,
BV_SWF,
BV_TFU,
+ BV_UMF,
BV_TSRFU,
BV_TAGS,
BV_TC,
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 1d9a821e20..2acc1297b2 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -2700,6 +2700,13 @@ return {
defaults={if_true=4000}
},
{
+ full_name='usermarkfunc', abbreviation='umf',
+ short_desc=N_("function used to perform jumps/sets to user marks."),
+ type='string', scope={'buffer'},
+ varname='p_umf',
+ defaults={if_true=""}
+ },
+ {
full_name='varsofttabstop', abbreviation='vsts',
short_desc=N_("list of numbers of spaces that <Tab> uses while editing"),
type='string', list='comma', scope={'buffer'},