Files
neovim/src/nvim/mark.h
Javier Lopez 565f72b968 feat(marks): restore viewport on jump #15831
** Refactor

Previously most functions used to "get" a mark returned a position,
changed the line number and sometimes changed even the current buffer.

Now functions return a {x}fmark_T making calling context aware whether
the mark is in another buffer without arcane casting. A new function is
provided for switching to the mark buffer and returning a flag style
Enum to convey what happen in the movement. If the cursor changed, line,
columns, if it changed buffer, etc.

The function to get named mark was split into multiple functions.

- mark_get() -> fmark_T
- mark_get_global() -> xfmark_T
- mark_get_local() -> fmark_T
  - mark_get_motion() -> fmark_T
  - mark_get_visual() -> fmark_T

Functions that manage the changelist and jumplist were also modified to
return mark types.

- get_jumplist -> fmark_T
- get_changelist -> fmark_T

The refactor is also seen mainly on normal.c, where all the mark
movement has been siphoned through one function nv_gomark, while the
other functions handle getting the mark and setting their movement
flags. To handle whether context marks should be left, etc.

** Mark View

While doing the refactor the concept of a mark view was also
implemented:

The view of a mark currently implemented as the number of lines between
the mark position on creation and the window topline. This allows for
moving not only back to the position of a mark but having the window
look similar to when the mark was defined. This is done by carrying and
extra element in the fmark_T struct, which can be extended later to also
restore horizontal shift.

*** User space features

1. There's a new option, jumpoptions+=view enables the mark view restoring
automatically when using the jumplist, changelist, alternate-file and
mark motions. <C-O> <C-I> g; g, <C-^> '[mark] `[mark]

** Limitations

- The view information is not saved in shada.
- Calls to get_mark should copy the value in the pointer since we are
  using pos_to_mark() to wrap and provide a homogeneous interfaces. This
  was also a limitation in the previous state of things.
2022-06-30 05:59:52 -07:00

125 lines
3.3 KiB
C

#ifndef NVIM_MARK_H
#define NVIM_MARK_H
#include "nvim/ascii.h"
#include "nvim/buffer_defs.h"
#include "nvim/ex_cmds_defs.h" // for exarg_T
#include "nvim/extmark_defs.h"
#include "nvim/func_attr.h"
#include "nvim/macros.h"
#include "nvim/mark_defs.h"
#include "nvim/memory.h"
#include "nvim/os/time.h"
#include "nvim/pos.h"
/// Set fmark using given value
#define SET_FMARK(fmarkp_, mark_, fnum_, view_) \
do { \
fmark_T *const fmarkp__ = fmarkp_; \
fmarkp__->mark = mark_; \
fmarkp__->fnum = fnum_; \
fmarkp__->timestamp = os_time(); \
fmarkp__->view = view_; \
fmarkp__->additional_data = NULL; \
} while (0)
/// Free and set fmark using given value
#define RESET_FMARK(fmarkp_, mark_, fnum_, view_) \
do { \
fmark_T *const fmarkp___ = fmarkp_; \
free_fmark(*fmarkp___); \
SET_FMARK(fmarkp___, mark_, fnum_, view_); \
} while (0)
/// Clear given fmark
#define CLEAR_FMARK(fmarkp_) \
RESET_FMARK(fmarkp_, ((pos_T) { 0, 0, 0 }), 0, ((fmarkv_T) { 0 }))
/// Set given extended mark (regular mark + file name)
#define SET_XFMARK(xfmarkp_, mark_, fnum_, view_, fname_) \
do { \
xfmark_T *const xfmarkp__ = xfmarkp_; \
xfmarkp__->fname = fname_; \
SET_FMARK(&(xfmarkp__->fmark), mark_, fnum_, view_); \
} while (0)
/// Free and set given extended mark (regular mark + file name)
#define RESET_XFMARK(xfmarkp_, mark_, fnum_, view_, fname_) \
do { \
xfmark_T *const xfmarkp__ = xfmarkp_; \
free_xfmark(*xfmarkp__); \
xfmarkp__->fname = fname_; \
SET_FMARK(&(xfmarkp__->fmark), mark_, fnum_, view_); \
} while (0)
/// Convert mark name to the offset
static inline int mark_global_index(const char name)
FUNC_ATTR_CONST
{
return (ASCII_ISUPPER(name)
? (name - 'A')
: (ascii_isdigit(name)
? (NMARKS + (name - '0'))
: -1));
}
/// Convert local mark name to the offset
static inline int mark_local_index(const char name)
FUNC_ATTR_CONST
{
return (ASCII_ISLOWER(name)
? (name - 'a')
: (name == '"'
? NMARKS
: (name == '^'
? NMARKS + 1
: (name == '.'
? NMARKS + 2
: -1))));
}
static inline bool lt(pos_T, pos_T) REAL_FATTR_CONST REAL_FATTR_ALWAYS_INLINE;
static inline bool equalpos(pos_T, pos_T)
REAL_FATTR_CONST REAL_FATTR_ALWAYS_INLINE;
static inline bool ltoreq(pos_T, pos_T)
REAL_FATTR_CONST REAL_FATTR_ALWAYS_INLINE;
static inline void clearpos(pos_T *)
REAL_FATTR_ALWAYS_INLINE;
/// Return true if position a is before (less than) position b.
static inline bool lt(pos_T a, pos_T b)
{
if (a.lnum != b.lnum) {
return a.lnum < b.lnum;
} else if (a.col != b.col) {
return a.col < b.col;
} else {
return a.coladd < b.coladd;
}
}
/// Return true if position a and b are equal.
static inline bool equalpos(pos_T a, pos_T b)
{
return (a.lnum == b.lnum) && (a.col == b.col) && (a.coladd == b.coladd);
}
/// Return true if position a is less than or equal to b.
static inline bool ltoreq(pos_T a, pos_T b)
{
return lt(a, b) || equalpos(a, b);
}
/// Clear the pos_T structure pointed to by a.
static inline void clearpos(pos_T *a)
{
a->lnum = 0;
a->col = 0;
a->coladd = 0;
}
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "mark.h.generated.h"
#endif
#endif // NVIM_MARK_H