/* vi:set ts=8 sts=4 sw=4 noet:
*
* VIM - Vi IMproved by Bram Moolenaar
*
* Do ":help uganda" in Vim to read copying and usage conditions.
* Do ":help credits" in Vim to see a list of people who contributed.
* See README.txt for an overview of the Vim source code.
*/
/*
* Text properties implementation. See ":help text-properties".
*
* TODO:
* - Adjust text property column and length when text is inserted/deleted.
* -> :substitute with multiple matches, issue #4427
* -> a :substitute with a multi-line match
* -> search for changed_bytes() from misc1.c
* -> search for mark_col_adjust()
* - Perhaps we only need TP_FLAG_CONT_NEXT and can drop TP_FLAG_CONT_PREV?
* - Add an arrray for global_proptypes, to quickly lookup a prop type by ID
* - Add an arrray for b_proptypes, to quickly lookup a prop type by ID
* - Checking the text length to detect text properties is slow. Use a flag in
* the index, like DB_MARKED?
* - Also test line2byte() with many lines, so that ml_updatechunk() is taken
* into account.
* - Perhaps have a window-local option to disable highlighting from text
* properties?
*/
#include "vim.h"
#if defined(FEAT_TEXT_PROP) || defined(PROTO)
/*
* In a hashtable item "hi_key" points to "pt_name" in a proptype_T.
* This avoids adding a pointer to the hashtable item.
* PT2HIKEY() converts a proptype pointer to a hashitem key pointer.
* HIKEY2PT() converts a hashitem key pointer to a proptype pointer.
* HI2PT() converts a hashitem pointer to a proptype pointer.
*/
#define PT2HIKEY(p) ((p)->pt_name)
#define HIKEY2PT(p) ((proptype_T *)((p) - offsetof(proptype_T, pt_name)))
#define HI2PT(hi) HIKEY2PT((hi)->hi_key)
// The global text property types.
static hashtab_T *global_proptypes = NULL;
// The last used text property type ID.
static int proptype_id = 0;
static char_u e_type_not_exist[] = N_("E971: Property type %s does not exist");
static char_u e_invalid_col[] = N_("E964: Invalid column number: %ld");
static char_u e_invalid_lnum[] = N_("E966: Invalid line number: %ld");
/*
* Find a property type by name, return the hashitem.
* Returns NULL if the item can't be found.
*/
static hashitem_T *
find_prop_hi(char_u *name, buf_T *buf)
{
hashtab_T *ht;
hashitem_T *hi;
if (*name == NUL)
return NULL;
if (buf == NULL)
ht = global_proptypes;
else
ht = buf->b_proptypes;
if (ht == NULL)
return NULL;
hi = hash_find(ht, name);
if (HASHITEM_EMPTY(hi))
return NULL;
return hi;
}
/*
* Like find_prop_hi() but return the property type.
*/
static proptype_T *
find_prop(char_u *name, buf_T *buf)
{
hashitem_T *hi = find_prop_hi(name, buf);
if (hi == NULL)
return NULL;
return HI2PT(hi);
}
/*
* Lookup a property type by name. First in "buf" and when not found in the
* global types.
* When not found gives an error message and returns NULL.
*/
static proptype_T *
lookup_prop_type(char_u *name, buf_T *buf)
{
proptype_T *type = find_prop(name, buf);
if (type == NULL)
type = find_prop(name, NULL);
if (type == NULL)
semsg(_(e_type_not_exist), name);
return type;
}
/*
* Get an optional "bufnr" item from the dict in "arg".
* When the argument is not used or "bufnr" is not present then "buf" is
* unchanged.
* If "bufnr" is valid or not present return OK.
* When "arg" is not a dict or "bufnr" is invalide return FAIL.
*/
static int
get_bufnr_from_arg(typval_T *arg, buf_T **buf)
{
dictitem_T *di;
if (arg->v_type != VAR_DICT)
{
emsg(_(e_dictreq));
return FAIL;
}
if (arg