diff options
-rw-r--r-- | src/nvim/buffer_defs.h | 1 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 8 | ||||
-rw-r--r-- | src/nvim/map.h | 2 | ||||
-rw-r--r-- | src/nvim/mark.c | 161 | ||||
-rw-r--r-- | src/nvim/option.c | 4 | ||||
-rw-r--r-- | src/nvim/option_defs.h | 2 | ||||
-rw-r--r-- | src/nvim/options.lua | 7 |
7 files changed, 179 insertions, 6 deletions
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 48e6b61492..e2c93f481d 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -663,6 +663,7 @@ struct file_buffer { Callback b_ofu_cb; ///< 'omnifunc' callback char *b_p_tfu; ///< 'tagfunc' Callback b_tfu_cb; ///< 'tagfunc' callback + char *b_p_umf; ///< 'usermarkfunc' char *b_p_urf; ///< 'userregfunc' int b_p_eof; ///< 'endoffile' int b_p_eol; ///< 'endofline' diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index e11dd0a2f6..785b727cd3 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -3184,7 +3184,7 @@ char *skip_range(const char *cmd, int *ctx) } } if (*cmd != NUL) { - cmd++; + cmd += utf_ptr2len(cmd); } } @@ -3327,13 +3327,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.h b/src/nvim/map.h index 59991b9b94..9b91d3c7a9 100644 --- a/src/nvim/map.h +++ b/src/nvim/map.h @@ -39,8 +39,8 @@ // // NOTE: Keys AND values must be allocated! khash.h does not make a copy. // -MAP_DECLS(int, int) MAP_DECLS(int, ptr_t) +MAP_DECLS(int, int) MAP_DECLS(ptr_t, 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 b98935e93d..904eaf32c0 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -15,6 +15,9 @@ #include "nvim/cursor.h" #include "nvim/diff.h" #include "nvim/edit.h" +#include "nvim/eval.h" +#include "nvim/eval/typval.h" +#include "nvim/ex_cmds.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/ex_cmds_defs.h" @@ -25,6 +28,7 @@ #include "nvim/globals.h" #include "nvim/highlight_defs.h" #include "nvim/mark.h" +#include "nvim/mark_defs.h" #include "nvim/mbyte.h" #include "nvim/memline.h" #include "nvim/memory.h" @@ -42,6 +46,8 @@ #include "nvim/types.h" #include "nvim/undo_defs.h" #include "nvim/vim.h" +#include "nvim/map.h" +#include "nvim/eval/userfunc.h" // This file contains routines to maintain and manipulate marks. @@ -54,6 +60,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 @@ -160,7 +192,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 @@ -341,6 +374,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; @@ -429,6 +471,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.fe_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 f236392f4a..97a1c04572 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -4002,6 +4002,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: @@ -4337,6 +4339,8 @@ void buf_copy_options(buf_T *buf, int flags) set_buflocal_ofu_callback(buf); buf->b_p_tfu = xstrdup(p_tfu); COPY_OPT_SCTX(buf, BV_TFU); + buf->b_p_umf = xstrdup(p_umf); + COPY_OPT_SCTX(buf, BV_UMF); set_buflocal_tfu_callback(buf); buf->b_p_sts = p_sts; COPY_OPT_SCTX(buf, BV_STS); diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 95304bf904..32733d0c4b 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -716,6 +716,7 @@ EXTERN unsigned int tpf_flags; ///< flags from 'termpastefilter' #define TPF_C0 0x020 #define TPF_C1 0x040 EXTERN char *p_tfu; ///< 'tagfunc' +EXTERN char *p_umf; ///< 'usermarkfunc' EXTERN char *p_spc; ///< 'spellcapcheck' EXTERN char *p_spf; ///< 'spellfile' EXTERN char *p_spk; ///< 'splitkeep' @@ -903,6 +904,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 a7f7ca2cf7..7d2f9075f6 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -2629,6 +2629,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='userregfunc', abbreviation='urf', short_desc=N_("Function used to define behavior of user-defined registers."), type='string', scope={'buffer'}, |