mirror of
https://github.com/neovim/neovim.git
synced 2025-09-29 06:28:35 +00:00
refactor(decorations): break up Decoration struct into smaller pieces
Remove the monolithic Decoration struct. Before this change, each extmark could either represent just a hl_id + priority value as a inline decoration, or it would take a pointer to this monolitic 112 byte struct which has to be allocated. This change separates the decorations into two pieces: DecorSignHighlight for signs, highlights and simple set-flag decorations (like spell, ui-watched), and DecorVirtText for virtual text and lines. The main separation here is whether they are expected to allocate more memory. Currently this is not really true as sign text has to be an allocated string, but the plan is to get rid of this eventually (it can just be an array of two schar_T:s). Further refactors are expected to improve the representation of each decoration kind individually. The goal of this particular PR is to get things started by cutting the Gordian knot which was the monolithic struct Decoration. Now, each extmark can either contain chained indicies/pointers to these kinds of objects, or it can fit a subset of DecorSignHighlight inline. The point of this change is not only to make decorations smaller in memory. In fact, the main motivation is to later allow them to grow _larger_, but on a dynamic, on demand fashion. As a simple example, it would be possible to augment highlights to take a list of multiple `hl_group`:s, which then would trivially map to a chain of multiple DecorSignHighlight entries. One small feature improvement included with this refactor itself, is that the restriction that extmarks cannot be removed inside a decoration provider has been lifted. These are instead safely lifetime extended on a "to free" list until the current iteration of screen drawing is done. NB: flags is a mess. but DecorLevel is useless, this slightly less so
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "klib/kvec.h"
|
||||
#include "nvim/assert.h"
|
||||
#include "nvim/decoration_defs.h"
|
||||
#include "nvim/garray.h"
|
||||
#include "nvim/map.h"
|
||||
#include "nvim/pos.h"
|
||||
@@ -47,6 +48,8 @@ typedef struct {
|
||||
} MarkTreeIter;
|
||||
|
||||
#define marktree_itr_valid(itr) ((itr)->x != NULL)
|
||||
// accces raw key: flags in MT_FLAG_EXTERNAL_MASK and decor_data are safe to modify.
|
||||
#define mt_itr_rawkey(itr) ((itr)->x->key[(itr)->i])
|
||||
|
||||
// Internal storage
|
||||
//
|
||||
@@ -56,10 +59,8 @@ typedef struct {
|
||||
MTPos pos;
|
||||
uint32_t ns;
|
||||
uint32_t id;
|
||||
int32_t hl_id;
|
||||
uint16_t flags;
|
||||
uint16_t priority;
|
||||
Decoration *decor_full;
|
||||
DecorInlineData decor_data; // "ext" tag in flags
|
||||
} MTKey;
|
||||
|
||||
typedef struct {
|
||||
@@ -68,28 +69,40 @@ typedef struct {
|
||||
bool end_right_gravity;
|
||||
} MTPair;
|
||||
|
||||
#define MT_INVALID_KEY (MTKey) { { -1, -1 }, 0, 0, 0, 0, 0, NULL }
|
||||
#define MT_INVALID_KEY (MTKey) { { -1, -1 }, 0, 0, 0, { .hl = DECOR_HIGHLIGHT_INLINE_INIT } }
|
||||
|
||||
#define MT_FLAG_REAL (((uint16_t)1) << 0)
|
||||
#define MT_FLAG_END (((uint16_t)1) << 1)
|
||||
#define MT_FLAG_PAIRED (((uint16_t)1) << 2)
|
||||
// orphaned: the other side of this paired mark was deleted. this mark must be deleted very soon!
|
||||
#define MT_FLAG_ORPHANED (((uint16_t)1) << 3)
|
||||
#define MT_FLAG_HL_EOL (((uint16_t)1) << 4)
|
||||
#define MT_FLAG_NO_UNDO (((uint16_t)1) << 5)
|
||||
#define MT_FLAG_INVALIDATE (((uint16_t)1) << 6)
|
||||
#define MT_FLAG_INVALID (((uint16_t)1) << 7)
|
||||
#define MT_FLAG_NO_UNDO (((uint16_t)1) << 4)
|
||||
#define MT_FLAG_INVALIDATE (((uint16_t)1) << 5)
|
||||
#define MT_FLAG_INVALID (((uint16_t)1) << 6)
|
||||
// discriminant for union
|
||||
#define MT_FLAG_DECOR_EXT (((uint16_t)1) << 7)
|
||||
|
||||
#define DECOR_LEVELS 4
|
||||
#define MT_FLAG_DECOR_OFFSET 8
|
||||
#define MT_FLAG_DECOR_MASK (((uint16_t)(DECOR_LEVELS - 1)) << MT_FLAG_DECOR_OFFSET)
|
||||
// TODO(bfredl): flags for decorations. These cover the cases where we quickly needs
|
||||
// to skip over irrelevant marks internally. When we refactor this more, also make all info
|
||||
// for ExtmarkType included here
|
||||
#define MT_FLAG_DECOR_HL (((uint16_t)1) << 8)
|
||||
#define MT_FLAG_DECOR_SIGNTEXT (((uint16_t)1) << 9)
|
||||
// TODO(bfredl): for now this means specifically number_hl, line_hl, cursorline_hl
|
||||
// needs to clean up the name.
|
||||
#define MT_FLAG_DECOR_SIGNHL (((uint16_t)1) << 10)
|
||||
#define MT_FLAG_DECOR_VIRT_LINES (((uint16_t)1) << 11)
|
||||
#define MT_FLAG_DECOR_VIRT_TEXT_INLINE (((uint16_t)1) << 12)
|
||||
|
||||
// These _must_ be last to preserve ordering of marks
|
||||
#define MT_FLAG_RIGHT_GRAVITY (((uint16_t)1) << 14)
|
||||
#define MT_FLAG_LAST (((uint16_t)1) << 15)
|
||||
|
||||
#define MT_FLAG_EXTERNAL_MASK (MT_FLAG_DECOR_MASK | MT_FLAG_RIGHT_GRAVITY | MT_FLAG_HL_EOL \
|
||||
| MT_FLAG_NO_UNDO | MT_FLAG_INVALIDATE | MT_FLAG_INVALID)
|
||||
#define MT_FLAG_DECOR_MASK (MT_FLAG_DECOR_EXT| MT_FLAG_DECOR_HL | MT_FLAG_DECOR_SIGNTEXT \
|
||||
| MT_FLAG_DECOR_SIGNHL | MT_FLAG_DECOR_VIRT_LINES \
|
||||
| MT_FLAG_DECOR_VIRT_TEXT_INLINE)
|
||||
|
||||
#define MT_FLAG_EXTERNAL_MASK (MT_FLAG_DECOR_MASK | MT_FLAG_NO_UNDO \
|
||||
| MT_FLAG_INVALIDATE | MT_FLAG_INVALID)
|
||||
|
||||
// this is defined so that start and end of the same range have adjacent ids
|
||||
#define MARKTREE_END_FLAG ((uint64_t)1)
|
||||
@@ -143,20 +156,22 @@ static inline bool mt_invalid(MTKey key)
|
||||
return key.flags & MT_FLAG_INVALID;
|
||||
}
|
||||
|
||||
static inline uint8_t marktree_decor_level(MTKey key)
|
||||
static inline bool mt_decor_any(MTKey key)
|
||||
{
|
||||
return (uint8_t)((key.flags&MT_FLAG_DECOR_MASK) >> MT_FLAG_DECOR_OFFSET);
|
||||
return key.flags & MT_FLAG_DECOR_MASK;
|
||||
}
|
||||
|
||||
static inline uint16_t mt_flags(bool right_gravity, bool hl_eol, bool no_undo, bool invalidate,
|
||||
uint8_t decor_level)
|
||||
static inline bool mt_decor_sign(MTKey key)
|
||||
{
|
||||
return key.flags & (MT_FLAG_DECOR_SIGNTEXT | MT_FLAG_DECOR_SIGNHL);
|
||||
}
|
||||
|
||||
static inline uint16_t mt_flags(bool right_gravity, bool no_undo, bool invalidate, bool decor_ext)
|
||||
{
|
||||
assert(decor_level < DECOR_LEVELS);
|
||||
return (uint16_t)((right_gravity ? MT_FLAG_RIGHT_GRAVITY : 0)
|
||||
| (hl_eol ? MT_FLAG_HL_EOL : 0)
|
||||
| (no_undo ? MT_FLAG_NO_UNDO : 0)
|
||||
| (invalidate ? MT_FLAG_INVALIDATE : 0)
|
||||
| (decor_level << MT_FLAG_DECOR_OFFSET));
|
||||
| (decor_ext ? MT_FLAG_DECOR_EXT : 0));
|
||||
}
|
||||
|
||||
static inline MTPair mtpair_from(MTKey start, MTKey end)
|
||||
@@ -164,6 +179,11 @@ static inline MTPair mtpair_from(MTKey start, MTKey end)
|
||||
return (MTPair){ .start = start, .end_pos = end.pos, .end_right_gravity = mt_right(end) };
|
||||
}
|
||||
|
||||
static inline DecorInline mt_decor(MTKey key)
|
||||
{
|
||||
return (DecorInline){ .ext = key.flags & MT_FLAG_DECOR_EXT, .data = key.decor_data };
|
||||
}
|
||||
|
||||
typedef kvec_withinit_t(uint64_t, 4) Intersection;
|
||||
|
||||
struct mtnode_s {
|
||||
@@ -186,8 +206,6 @@ static inline uint64_t mt_dbg_id(uint64_t id)
|
||||
typedef struct {
|
||||
MTNode *root;
|
||||
size_t n_keys, n_nodes;
|
||||
// TODO(bfredl): the pointer to node could be part of the larger
|
||||
// Map(uint64_t, ExtmarkItem) essentially;
|
||||
PMap(uint64_t) id2node[1];
|
||||
} MarkTree;
|
||||
|
||||
|
Reference in New Issue
Block a user