Commit 244dbe3a authored by ZyX's avatar ZyX

viminfo: First version of ShaDa file dumping

What works:

1. ShaDa file dumping: header, registers, jump list, history, search patterns,
   substitute strings, variables.
2. ShaDa file reading: registers, global marks, variables.

Most was not tested.

TODO:

1. Merging.
2. Reading history, local marks, jump and buffer lists.
3. Documentation update.
4. Converting some data from &encoding.
5. Safer variant of dumping viminfo (dump to temporary file then rename).
6. Removing old viminfo code (currently masked with `#if 0` in a ShaDa file for
   reference).
parent 0fdaab99
......@@ -9,7 +9,7 @@ def DirectoryOfThisScript():
def GetDatabase():
compilation_database_folder = os.path.join(DirectoryOfThisScript(),
'..', 'build')
'..', '..', 'build')
if os.path.exists(compilation_database_folder):
return ycm_core.CompilationDatabase(compilation_database_folder)
return None
......
......@@ -6770,10 +6770,14 @@ A jump table for the options with a short description can be found at |Q_op|.
e.g., for Unix: "r/tmp". Case is ignored. Maximum length of
each 'r' argument is 50 characters.
*viminfo-s*
s Maximum size of an item in Kbyte. If zero then registers are
not saved. Currently only applies to registers. The default
"s10" will exclude registers with more than 10 Kbyte of text.
Also see the '<' item above: line count limit.
s Maximum size of an item contents in KiB. If zero then nothing
is saved. Unlike Vim this applies to all items, except for
the buffer list and header. Full item size is off by three
unsigned integers: with `s10` maximum item size may be 1 byte
(type: 7-bit integer) + 9 bytes (timestamp: up to 64-bit
integer) + 3 bytes (item size: up to 16-bit integer because
2^8 < 10240 < 2^16) + 10240 bytes (requested maximum item
contents size) = 10253 bytes.
Example: >
:set viminfo='50,<1000,s100,:0,n~/vim/viminfo
......@@ -6782,7 +6786,8 @@ A jump table for the options with a short description can be found at |Q_op|.
edited.
<1000 Contents of registers (up to 1000 lines each) will be
remembered.
s100 Registers with more than 100 Kbyte text are skipped.
s100 Items with contents occupying more then 100 KiB are
skipped.
:0 Command-line history will not be saved.
n~/vim/viminfo The name of the file to use is "~/vim/viminfo".
no / Since '/' is not specified, the default will be used,
......
#!/usr/bin/env python3.4
import sys
import codecs
from enum import Enum
from datetime import datetime
from functools import reduce
import msgpack
class EntryTypes(Enum):
Unknown = -1
Missing = 0
Header = 1
SearchPattern = 2
SubString = 3
HistoryEntry = 4
Register = 5
Variable = 6
GlobalMark = 7
Jump = 8
BufferList = 9
LocalMark = 10
def strtrans_errors(e):
if not isinstance(e, UnicodeDecodeError):
raise NotImplementedError('don’t know how to handle {0} error'.format(
e.__class__.__name__))
return '<{0:x}>'.format(reduce((lambda a, b: a*0x100+b),
list(e.object[e.start:e.end]))), e.end
codecs.register_error('strtrans', strtrans_errors)
def idfunc(o):
return o
class CharInt(int):
def __repr__(self):
return super(CharInt, self).__repr__() + ' (\'%s\')' % chr(self)
ctable = {
bytes: lambda s: s.decode('utf-8', 'strtrans'),
dict: lambda d: dict((mnormalize(k), mnormalize(v)) for k, v in d.items()),
list: lambda l: list(mnormalize(i) for i in l),
int: lambda n: CharInt(n) if 0x20 <= n <= 0x7E else n,
}
def mnormalize(o):
return ctable.get(type(o), idfunc)(o)
with open(sys.argv[1], 'rb') as fp:
unpacker = msgpack.Unpacker(file_like=fp)
while True:
try:
typ = EntryTypes(unpacker.unpack())
except msgpack.OutOfData:
break
else:
timestamp = unpacker.unpack()
time = datetime.fromtimestamp(timestamp)
length = unpacker.unpack()
entry = unpacker.unpack()
print('{0:13} {1} {2:5} {3!r}'.format(
typ.name, time.isoformat(), length, mnormalize(entry)))
......@@ -69,6 +69,8 @@
#define ADD(array, item) \
kv_push(Object, array, item)
#define STATIC_CSTR_AS_STRING(s) ((String) {.data = s, .size = sizeof(s) - 1})
// Helpers used by the generated msgpack-rpc api wrappers
#define api_init_boolean
#define api_init_integer
......
......@@ -84,7 +84,7 @@ return {
'User', -- user defined autocommand
'VimEnter', -- after starting Vim
'VimLeave', -- before exiting Vim
'VimLeavePre', -- before exiting Vim and writing .viminfo
'VimLeavePre', -- before exiting Vim and writing ShaDa file
'VimResized', -- after Vim window was resized
'WinEnter', -- after entering a window
'WinLeave', -- before leaving a window
......
......@@ -73,6 +73,7 @@
#include "nvim/undo.h"
#include "nvim/version.h"
#include "nvim/window.h"
#include "nvim/shada.h"
#include "nvim/os/os.h"
#include "nvim/os/time.h"
#include "nvim/os/input.h"
......@@ -555,6 +556,12 @@ static void free_buffer(buf_T *buf)
free_buffer_stuff(buf, TRUE);
unref_var_dict(buf->b_vars);
aubuflocal_remove(buf);
free_fmark(buf->b_last_cursor);
free_fmark(buf->b_last_insert);
free_fmark(buf->b_last_change);
for (size_t i = 0; i < NMARKS; i++) {
free_fmark(buf->b_namedm[i]);
}
if (autocmd_busy) {
// Do not free the buffer structure while autocommands are executing,
// it's still needed. Free it when autocmd_busy is reset.
......@@ -4164,93 +4171,6 @@ chk_modeline (
return retval;
}
int read_viminfo_bufferlist(vir_T *virp, int writing)
{
char_u *tab;
linenr_T lnum;
colnr_T col;
buf_T *buf;
char_u *sfname;
char_u *xline;
/* Handle long line and escaped characters. */
xline = viminfo_readstring(virp, 1, FALSE);
/* don't read in if there are files on the command-line or if writing: */
if (xline != NULL && !writing && ARGCOUNT == 0
&& find_viminfo_parameter('%') != NULL) {
/* Format is: <fname> Tab <lnum> Tab <col>.
* Watch out for a Tab in the file name, work from the end. */
lnum = 0;
col = 0;
tab = vim_strrchr(xline, '\t');
if (tab != NULL) {
*tab++ = '\0';
col = (colnr_T)atoi((char *)tab);
tab = vim_strrchr(xline, '\t');
if (tab != NULL) {
*tab++ = '\0';
lnum = atol((char *)tab);
}
}
/* Expand "~/" in the file name at "line + 1" to a full path.
* Then try shortening it by comparing with the current directory */
expand_env(xline, NameBuff, MAXPATHL);
sfname = path_shorten_fname_if_possible(NameBuff);
buf = buflist_new(NameBuff, sfname, (linenr_T)0, BLN_LISTED);
if (buf != NULL) { /* just in case... */
buf->b_last_cursor.lnum = lnum;
buf->b_last_cursor.col = col;
buflist_setfpos(buf, curwin, lnum, col, FALSE);
}
}
xfree(xline);
return viminfo_readline(virp);
}
void write_viminfo_bufferlist(FILE *fp)
{
char_u *line;
int max_buffers;
if (find_viminfo_parameter('%') == NULL)
return;
/* Without a number -1 is returned: do all buffers. */
max_buffers = get_viminfo_parameter('%');
/* Allocate room for the file name, lnum and col. */
#define LINE_BUF_LEN (MAXPATHL + 40)
line = xmalloc(LINE_BUF_LEN);
FOR_ALL_TAB_WINDOWS(tp, win) {
set_last_cursor(win);
}
fputs(_("\n# Buffer list:\n"), fp);
FOR_ALL_BUFFERS(buf) {
if (buf->b_fname == NULL
|| !buf->b_p_bl
|| bt_quickfix(buf)
|| removable(buf->b_ffname))
continue;
if (max_buffers-- == 0)
break;
putc('%', fp);
home_replace(NULL, buf->b_ffname, line, MAXPATHL, TRUE);
vim_snprintf_add((char *)line, LINE_BUF_LEN, "\t%" PRId64 "\t%d",
(int64_t)buf->b_last_cursor.lnum,
buf->b_last_cursor.col);
viminfo_writestring(fp, line);
}
xfree(line);
}
/*
* Return special buffer name.
* Returns NULL when the buffer has a normal file name.
......
......@@ -327,15 +327,6 @@ typedef struct {
bool vc_fail; /* fail for invalid char, don't use '?' */
} vimconv_T;
/*
* Structure used for reading from the viminfo file.
*/
typedef struct {
char_u *vir_line; /* text of the current line */
FILE *vir_fd; /* file descriptor */
vimconv_T vir_conv; /* encoding conversion */
} vir_T;
#define CONV_NONE 0
#define CONV_TO_UTF8 1
#define CONV_9_TO_UTF8 2
......@@ -515,16 +506,16 @@ struct file_buffer {
uint64_t b_orig_size; /* size of original file in bytes */
int b_orig_mode; /* mode of original file */
pos_T b_namedm[NMARKS]; /* current named marks (mark.c) */
fmark_T b_namedm[NMARKS]; /* current named marks (mark.c) */
/* These variables are set when VIsual_active becomes FALSE */
visualinfo_T b_visual;
int b_visual_mode_eval; /* b_visual.vi_mode for visualmode() */
pos_T b_last_cursor; /* cursor position when last unloading this
fmark_T b_last_cursor; /* cursor position when last unloading this
buffer */
pos_T b_last_insert; /* where Insert mode was left */
pos_T b_last_change; /* position of last change: '. mark */
fmark_T b_last_insert; /* where Insert mode was left */
fmark_T b_last_change; /* position of last change: '. mark */
/*
* the changelist contains old change positions
......@@ -553,7 +544,7 @@ struct file_buffer {
pos_T b_op_start_orig; // used for Insstart_orig
pos_T b_op_end;
bool b_marks_read; /* Have we read viminfo marks yet? */
bool b_marks_read; /* Have we read ShaDa marks yet? */
/*
* The following only used in undo.c.
......
......@@ -60,6 +60,7 @@
#include "nvim/undo.h"
#include "nvim/window.h"
#include "nvim/event/loop.h"
#include "nvim/mark.h"
#include "nvim/os/input.h"
#include "nvim/os/time.h"
......@@ -6991,8 +6992,9 @@ ins_esc (
curwin->w_set_curswant = TRUE;
/* Remember the last Insert position in the '^ mark. */
if (!cmdmod.keepjumps)
curbuf->b_last_insert = curwin->w_cursor;
if (!cmdmod.keepjumps) {
RESET_FMARK(&curbuf->b_last_insert, curwin->w_cursor, curbuf->b_fnum);
}
/*
* The cursor should end up on the last inserted character.
......
......@@ -354,7 +354,7 @@ typedef struct {
typedef enum {
VAR_FLAVOUR_DEFAULT, /* doesn't start with uppercase */
VAR_FLAVOUR_SESSION, /* starts with uppercase, some lower */
VAR_FLAVOUR_VIMINFO /* all uppercase */
VAR_FLAVOUR_SHADA /* all uppercase */
} var_flavour_T;
/* values for vv_flags: */
......@@ -10482,6 +10482,7 @@ static void f_has(typval_T *argvars, typval_T *rettv)
"scrollbind",
"showcmd",
"cmdline_info",
"shada",
"signs",
"smartindent",
"startuptime",
......@@ -10498,7 +10499,6 @@ static void f_has(typval_T *argvars, typval_T *rettv)
"title",
"user-commands", /* was accidentally included in 5.4 */
"user_commands",
"viminfo",
"vertsplit",
"virtualedit",
"visual",
......@@ -20712,107 +20712,62 @@ static var_flavour_T var_flavour(char_u *varname)
while (*(++p))
if (ASCII_ISLOWER(*p))
return VAR_FLAVOUR_SESSION;
return VAR_FLAVOUR_VIMINFO;
return VAR_FLAVOUR_SHADA;
} else
return VAR_FLAVOUR_DEFAULT;
}
/*
* Restore global vars that start with a capital from the viminfo file
*/
int read_viminfo_varlist(vir_T *virp, int writing)
{
char_u *tab;
int type = VAR_NUMBER;
typval_T tv;
if (!writing && (find_viminfo_parameter('!') != NULL)) {
tab = vim_strchr(virp->vir_line + 1, '\t');
if (tab != NULL) {
*tab++ = NUL; /* isolate the variable name */
switch (*tab) {
case 'S': type = VAR_STRING; break;
case 'F': type = VAR_FLOAT; break;
case 'D': type = VAR_DICT; break;
case 'L': type = VAR_LIST; break;
}
tab = vim_strchr(tab, '\t');
if (tab != NULL) {
tv.v_type = type;
if (type == VAR_STRING || type == VAR_DICT || type == VAR_LIST)
tv.vval.v_string = viminfo_readstring(virp,
(int)(tab - virp->vir_line + 1), TRUE);
else if (type == VAR_FLOAT)
(void)string2float(tab + 1, &tv.vval.v_float);
else
tv.vval.v_number = atol((char *)tab + 1);
if (type == VAR_DICT || type == VAR_LIST) {
typval_T *etv = eval_expr(tv.vval.v_string, NULL);
if (etv == NULL)
/* Failed to parse back the dict or list, use it as a
* string. */
tv.v_type = VAR_STRING;
else {
xfree(tv.vval.v_string);
tv = *etv;
xfree(etv);
}
}
set_var(virp->vir_line + 1, &tv, FALSE);
if (tv.v_type == VAR_STRING)
xfree(tv.vval.v_string);
else if (tv.v_type == VAR_DICT || tv.v_type == VAR_LIST)
clear_tv(&tv);
}
/// Iterate over global variables
///
/// @warning No modifications to global variable dictionary must be performed
/// while iteration is in progress.
///
/// @param[in] iter Iterator. Pass NULL to start iteration.
/// @param[out] name Variable name.
/// @param[out] rettv Variable value.
///
/// @return Pointer that needs to be passed to next `var_shada_iter` invocation
/// or NULL to indicate that iteration is over.
const void *var_shada_iter(const void *const iter, const char **const name,
typval_T *rettv)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(2, 3)
{
const hashitem_T *hi;
const hashitem_T *hifirst = globvarht.ht_array;
const size_t hinum = (size_t) globvarht.ht_mask + 1;
*name = NULL;
if (iter == NULL) {
hi = globvarht.ht_array;
while ((HASHITEM_EMPTY(hi)
|| var_flavour(HI2DI(hi)->di_key) != VAR_FLAVOUR_SHADA)
&& (size_t) (hi - hifirst) < hinum) {
hi++;
}
if (HASHITEM_EMPTY(hi)
|| var_flavour(HI2DI(hi)->di_key) != VAR_FLAVOUR_SHADA) {
*rettv = (typval_T) {.v_type = VAR_UNKNOWN};
return NULL;
}
} else {
hi = (const hashitem_T *) iter;
}
return viminfo_readline(virp);
*name = (char *) HI2DI(hi)->di_key;
copy_tv(&(HI2DI(hi)->di_tv), rettv);
while ((size_t) (++hi - hifirst) < hinum) {
if (!HASHITEM_EMPTY(hi)
&& var_flavour(HI2DI(hi)->di_key) == VAR_FLAVOUR_SHADA) {
return hi;
}
}
return NULL;
}
/*
* Write global vars that start with a capital to the viminfo file
*/
void write_viminfo_varlist(FILE *fp)
void var_set_global(const char *const name, typval_T vartv)
{
hashitem_T *hi;
dictitem_T *this_var;
int todo;
char *s;
char_u *p;
if (find_viminfo_parameter('!') == NULL)
return;
fputs(_("\n# global variables:\n"), fp);
todo = (int)globvarht.ht_used;
for (hi = globvarht.ht_array; todo > 0; ++hi) {
if (!HASHITEM_EMPTY(hi)) {
--todo;
this_var = HI2DI(hi);
if (var_flavour(this_var->di_key) == VAR_FLAVOUR_VIMINFO) {
switch (this_var->di_tv.v_type) {
case VAR_STRING: s = "STR"; break;
case VAR_NUMBER: s = "NUM"; break;
case VAR_FLOAT: s = "FLO"; break;
case VAR_DICT: s = "DIC"; break;
case VAR_LIST: s = "LIS"; break;
default: continue;
}
fprintf(fp, "!%s\t%s\t", this_var->di_key, s);
p = (char_u *) echo_string(&this_var->di_tv, NULL);
if (p != NULL) {
viminfo_writestring(fp, p);
}
xfree(p);
}
}
}
funccall_T *const saved_current_funccal = current_funccal;
current_funccal = NULL;
set_var((char_u *) name, &vartv, false);
current_funccal = saved_current_funccal;
}
int store_session_globals(FILE *fd)
......
This diff is collapsed.
......@@ -3,6 +3,9 @@
#include <stdbool.h>
#include "nvim/os/time.h"
#include "nvim/api/private/defs.h"
/* flags for do_ecmd() */
#define ECMD_HIDE 0x01 /* don't free the current buffer */
#define ECMD_SET_HELP 0x02 /* set b_help flag of (new) buffer before
......@@ -16,11 +19,12 @@
#define ECMD_LAST (linenr_T)-1 /* use last position in all files */
#define ECMD_ONE (linenr_T)1 /* use first line */
/* flags for read_viminfo() and children */
#define VIF_WANT_INFO 1 /* load non-mark info */
#define VIF_WANT_MARKS 2 /* load file marks */
#define VIF_FORCEIT 4 /* overwrite info already read */
#define VIF_GET_OLDFILES 8 /* load v:oldfiles */
/// Previous :substitute replacement string definition
typedef struct {
char *sub; ///< Previous replacement string.
Timestamp timestamp; ///< Time when it was last set.
Array *additional_elements; ///< Additional data left from ShaDa file.
} SubReplacementString;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ex_cmds.h.generated.h"
......
......@@ -75,6 +75,7 @@
#include "nvim/mouse.h"
#include "nvim/event/rstream.h"
#include "nvim/event/wstream.h"
#include "nvim/shada.h"
static int quitmore = 0;
static int ex_pressedreturn = FALSE;
......@@ -9149,11 +9150,11 @@ static void ex_viminfo(exarg_T *eap)
if (*p_viminfo == NUL)
p_viminfo = (char_u *)"'100";
if (eap->cmdidx == CMD_rviminfo) {
if (read_viminfo(eap->arg, VIF_WANT_INFO | VIF_WANT_MARKS
| (eap->forceit ? VIF_FORCEIT : 0)) == FAIL)
EMSG(_("E195: Cannot open viminfo file for reading"));
} else
write_viminfo(eap->arg, eap->forceit);
if (shada_read_everything((char *) eap->arg, eap->forceit) == FAIL)
EMSG(_("E195: Cannot open ShaDa file for reading"));
} else {
shada_write_file((char *) eap->arg, eap->forceit);
}
p_viminfo = save_viminfo;
}
......
This diff is collapsed.
......@@ -35,6 +35,15 @@
typedef char_u *(*CompleteListItemGetter)(expand_T *, int);
/// History entry definition
typedef struct hist_entry {
int hisnum; ///< Entry identifier number.
bool viminfo; ///< If true, indicates that entry comes from viminfo.
char_u *hisstr; ///< Actual entry, separator char after the NUL.
Timestamp timestamp; ///< Time when entry was added.
Array *additional_elements; ///< Additional entries from ShaDa file.
} histentry_T;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ex_getln.h.generated.h"
#endif
......
......@@ -57,6 +57,7 @@
#include "nvim/types.h"
#include "nvim/undo.h"
#include "nvim/window.h"
#include "nvim/shada.h"
#include "nvim/os/os.h"
#include "nvim/os/time.h"
#include "nvim/os/input.h"
......@@ -2166,14 +2167,15 @@ readfile_charconvert (
/*
* Read marks for the current buffer from the viminfo file, when we support
* Read marks for the current buffer from the ShaDa file, when we support
* buffer marks and the buffer has a name.
*/
static void check_marks_read(void)
{
if (!curbuf->b_marks_read && get_viminfo_parameter('\'') > 0
&& curbuf->b_ffname != NULL)
read_viminfo(NULL, VIF_WANT_MARKS);
&& curbuf->b_ffname != NULL) {
shada_read_marks();
}
/* Always set b_marks_read; needed when 'viminfo' is changed to include
* the ' parameter after opening a buffer. */
......
......@@ -892,7 +892,7 @@ EXTERN int skip_redraw INIT(= FALSE); /* skip redraw once */
EXTERN int do_redraw INIT(= FALSE); /* extra redraw once */
EXTERN int need_highlight_changed INIT(= TRUE);
EXTERN char_u *use_viminfo INIT(= NULL); /* name of viminfo file to use */
EXTERN char *used_shada_file INIT(= NULL); /* name of viminfo file to use */
#define NSCRIPT 15
EXTERN FILE *scriptin[NSCRIPT]; /* streams to read script from */
......
......@@ -49,6 +49,7 @@
#include "nvim/ops.h"
#include "nvim/option.h"
#include "nvim/os_unix.h"
#include "nvim/os/os_defs.h"
#include "nvim/path.h"
#include "nvim/profile.h"
#include "nvim/quickfix.h"
......@@ -58,6 +59,7 @@
#include "nvim/ui.h"
#include "nvim/version.h"
#include "nvim/window.h"
#include "nvim/shada.h"
#include "nvim/os/input.h"
#include "nvim/os/os.h"
#include "nvim/os/time.h"
......@@ -377,12 +379,12 @@ int main(int argc, char **argv)
}
/*
* Read in registers, history etc, but not marks, from the viminfo file.
* Read in registers, history etc, but not marks, from the ShaDa file.
* This is where v:oldfiles gets filled.
*/
if (*p_viminfo != NUL) {
read_viminfo(NULL, VIF_WANT_INFO | VIF_GET_OLDFILES);
TIME_MSG("reading viminfo");
(void) shada_read_file(NULL, kShaDaWantInfo|kShaDaGetOldfiles);
TIME_MSG("reading ShaDa");
}
/* It's better to make v:oldfiles an empty list than NULL. */
if (get_vim_var_list(VV_OLDFILES) == NULL)
......@@ -803,9 +805,10 @@ void getout(int exitval)
apply_autocmds(EVENT_VIMLEAVEPRE, NULL, NULL, FALSE, curbuf);
}
if (p_viminfo && *p_viminfo != NUL)
/* Write out the registers, history, marks etc, to the viminfo file */
write_viminfo(NULL, FALSE);
if (p_viminfo && *p_viminfo != NUL) {
// Write out the registers, history, marks etc, to the viminfo file
shada_write_file(NULL, false);
}
if (get_vim_var_nr(VV_DYING) <= 1)
apply_autocmds(EVENT_VIMLEAVE, NULL, NULL, FALSE, curbuf);
......@@ -1164,7 +1167,7 @@ static void command_line_scan(mparm_T *parmp)
}
/*FALLTHROUGH*/
case 'S': /* "-S {file}" execute Vim script */
case 'i': /* "-i {viminfo}" use for viminfo */
case 'i': /* "-i {shada}" use for ShaDa file */
case 'u': /* "-u {vimrc}" vim inits file */
case 'U': /* "-U {gvimrc}" gvim inits file */
case 'W': /* "-W {scriptout}" overwrite */
......@@ -1235,8 +1238,8 @@ static void command_line_scan(mparm_T *parmp)
parmp->use_ef = (char_u *)argv[0];
break;
case 'i': /* "-i {viminfo}" use for viminfo */
use_viminfo = (char_u *)argv[0];
case 'i': /* "-i {shada}" use for shada */
used_shada_file = argv[0];
break;
case 's': /* "-s {scriptin}" read from script file */
......@@ -2039,7 +2042,7 @@ static void usage(void)
mch_msg(_(" -r, -L List swap files and exit\n"));
mch_msg(_(" -r <file> Recover crashed session\n"));
mch_msg(_(" -u <nvimrc> Use <nvimrc> instead of the default\n"));
mch_msg(_(" -i <nviminfo> Use <nviminfo> instead of the default\n"));
mch_msg(_(" -i <shada> Use <shada> instead of the default " SHADA_FILE "\n"));
mch_msg(_(" --noplugin Don't load plugin scripts\n"));
mch_msg(_(" -o[N] Open N windows (default: one for each file)\n"));
mch_msg(_(" -O[N] Like -o but split vertically\n"));
......
This diff is collapsed.
......@@ -4,6 +4,22 @@
#include "nvim/buffer_defs.h"
#include "nvim/mark_defs.h"
#include "nvim/pos.h"
#include "nvim/os/time.h"
/// Free and set fmark using given value
#define RESET_FMARK(fmarkp_, mark_, fnum_) \
do { \
fmark_T *const fmarkp__ = fmarkp_; \
free_fmark(*fmarkp__); \
fmarkp__->mark = mark_; \
fmarkp__->fnum = fnum_; \
fmarkp__->timestamp = os_time(); \
fmarkp__->additional_data = NULL; \
} while (0)
/// Clear given fmark
#define CLEAR_FMARK(fmarkp_) \
RESET_FMARK(fmarkp_, ((pos_T) {0, 0, 0}), 0)
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "mark.h.generated.h"
......
......@@ -2,25 +2,41 @@
#define NVIM_MARK_DEFS_H
#include "nvim/pos.h"
#include "nvim/os/time.h"
#include "nvim/api/private/defs.h"
/*
* marks: positions in a file
* (a normal mark is a lnum/col pair, the same as a file position)
*/
#define NMARKS ('z' - 'a' + 1) /* max. # of named marks */
#define JUMPLISTSIZE 100 /* max. # of marks in jump list */
#define TAGSTACKSIZE 20 /* max. # of tags in tag stack */
/// Number of possible numbered global marks
#define EXTRA_MARKS ('9' - '0' + 1)
/// Maximum possible number of letter marks
#define NMARKS ('z' - 'a' + 1)
/// Total possible number of global marks
#define NGLOBALMARKS (NMARKS + EXTRA_MARKS)
/// Maximum number of marks in jump list
#define JUMPLISTSIZE 100
/// Maximum number of tags in tag stack
#define TAGSTACKSIZE 20
/// Structure defining single local mark
typedef struct filemark {
pos_T mark; /* cursor position */
int fnum; /* file number */
pos_T mark; ///< Cursor position.
int fnum; ///< File number.
Timestamp timestamp; ///< Time when this mark was last set.
Dictionary *additional_data; ///< Additional data from ShaDa file.
} fmark_T;
/* Xtended file mark: also has a file name */
/// Structure defining extended mark (mark with file name attached)
typedef struct xfilemark {
fmark_T fmark;
char_u *fname; /* file name, used when fnum == 0 */
fmark_T fmark; ///< Actual mark.