summaryrefslogtreecommitdiffstats
path: root/src/textprop.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-07-25 18:13:54 +0100
committerBram Moolenaar <Bram@vim.org>2022-07-25 18:13:54 +0100
commit7f9969c559b51446632ac7e8f76cde07e7d0078d (patch)
tree77868549433487dbadb8833a1b6a63d522adaa72 /src/textprop.c
parentb529cfbd04c02e31cfa88f2c8d88b5ff532d4f7d (diff)
patch 9.0.0067: cannot show virtual textv9.0.0067
Problem: Cannot show virtual text. Solution: Initial changes for virtual text support, using text properties.
Diffstat (limited to 'src/textprop.c')
-rw-r--r--src/textprop.c102
1 files changed, 80 insertions, 22 deletions
diff --git a/src/textprop.c b/src/textprop.c
index 5c07195f4f..d7db7aa3e1 100644
--- a/src/textprop.c
+++ b/src/textprop.c
@@ -150,7 +150,7 @@ get_bufnr_from_arg(typval_T *arg, buf_T **buf)
* prop_add({lnum}, {col}, {props})
*/
void
-f_prop_add(typval_T *argvars, typval_T *rettv UNUSED)
+f_prop_add(typval_T *argvars, typval_T *rettv)
{
linenr_T start_lnum;
colnr_T start_col;
@@ -174,20 +174,22 @@ f_prop_add(typval_T *argvars, typval_T *rettv UNUSED)
return;
}
- prop_add_common(start_lnum, start_col, argvars[2].vval.v_dict,
- curbuf, &argvars[2]);
+ rettv->vval.v_number = prop_add_common(start_lnum, start_col,
+ argvars[2].vval.v_dict, curbuf, &argvars[2]);
}
/*
* Attach a text property 'type_name' to the text starting
* at [start_lnum, start_col] and ending at [end_lnum, end_col] in
- * the buffer 'buf' and assign identifier 'id'.
+ * the buffer "buf" and assign identifier "id".
+ * When "text" is not NULL add it to buf->b_textprop_text[-id - 1].
*/
static int
prop_add_one(
buf_T *buf,
char_u *type_name,
int id,
+ char_u *text_arg,
linenr_T start_lnum,
linenr_T end_lnum,
colnr_T start_col,
@@ -202,26 +204,43 @@ prop_add_one(
char_u *newtext;
int i;
textprop_T tmp_prop;
+ char_u *text = text_arg;
+ int res = FAIL;
type = lookup_prop_type(type_name, buf);
if (type == NULL)
- return FAIL;
+ goto theend;
if (start_lnum < 1 || start_lnum > buf->b_ml.ml_line_count)
{
semsg(_(e_invalid_line_number_nr), (long)start_lnum);
- return FAIL;
+ goto theend;
}
if (end_lnum < start_lnum || end_lnum > buf->b_ml.ml_line_count)
{
semsg(_(e_invalid_line_number_nr), (long)end_lnum);
- return FAIL;
+ goto theend;
}
if (buf->b_ml.ml_mfp == NULL)
{
emsg(_(e_cannot_add_text_property_to_unloaded_buffer));
- return FAIL;
+ goto theend;
+ }
+
+ if (text != NULL)
+ {
+ garray_T *gap = &buf->b_textprop_text;
+
+ // double check we got the right ID
+ if (-id - 1 != gap->ga_len)
+ iemsg("text prop ID mismatch");
+ if (gap->ga_growsize == 0)
+ ga_init2(gap, sizeof(char *), 50);
+ if (ga_grow(gap, 1) == FAIL)
+ goto theend;
+ ((char_u **)gap->ga_data)[gap->ga_len++] = text;
+ text = NULL;
}
for (lnum = start_lnum; lnum <= end_lnum; ++lnum)
@@ -240,7 +259,7 @@ prop_add_one(
if (col - 1 > (colnr_T)textlen)
{
semsg(_(e_invalid_column_number_nr), (long)start_col);
- return FAIL;
+ goto theend;
}
if (lnum == end_lnum)
@@ -255,7 +274,7 @@ prop_add_one(
// Allocate the new line with space for the new property.
newtext = alloc(buf->b_ml.ml_line_len + sizeof(textprop_T));
if (newtext == NULL)
- return FAIL;
+ goto theend;
// Copy the text, including terminating NUL.
mch_memmove(newtext, buf->b_ml.ml_line_ptr, textlen);
@@ -295,7 +314,11 @@ prop_add_one(
}
changed_lines_buf(buf, start_lnum, end_lnum + 1, 0);
- return OK;
+ res = OK;
+
+theend:
+ vim_free(text);
+ return res;
}
/*
@@ -367,7 +390,7 @@ f_prop_add_list(typval_T *argvars, typval_T *rettv UNUSED)
emsg(_(e_invalid_argument));
return;
}
- if (prop_add_one(buf, type_name, id, start_lnum, end_lnum,
+ if (prop_add_one(buf, type_name, id, NULL, start_lnum, end_lnum,
start_col, end_col) == FAIL)
return;
}
@@ -376,11 +399,22 @@ f_prop_add_list(typval_T *argvars, typval_T *rettv UNUSED)
}
/*
+ * Get the next ID to use for a textprop with text in buffer "buf".
+ */
+ static int
+get_textprop_id(buf_T *buf)
+{
+ // TODO: recycle deleted entries
+ return -(buf->b_textprop_text.ga_len + 1);
+}
+
+/*
* Shared between prop_add() and popup_create().
* "dict_arg" is the function argument of a dict containing "bufnr".
* it is NULL for popup_create().
+ * Returns the "id" used for "text" or zero.
*/
- void
+ int
prop_add_common(
linenr_T start_lnum,
colnr_T start_col,
@@ -393,11 +427,12 @@ prop_add_common(
char_u *type_name;
buf_T *buf = default_buf;
int id = 0;
+ char_u *text = NULL;
if (dict == NULL || !dict_has_key(dict, "type"))
{
emsg(_(e_missing_property_type_name));
- return;
+ goto theend;
}
type_name = dict_get_string(dict, "type", FALSE);
@@ -407,7 +442,7 @@ prop_add_common(
if (end_lnum < start_lnum)
{
semsg(_(e_invalid_value_for_argument_str), "end_lnum");
- return;
+ goto theend;
}
}
else
@@ -420,7 +455,7 @@ prop_add_common(
if (length < 0 || end_lnum > start_lnum)
{
semsg(_(e_invalid_value_for_argument_str), "length");
- return;
+ goto theend;
}
end_col = start_col + length;
}
@@ -430,7 +465,7 @@ prop_add_common(
if (end_col <= 0)
{
semsg(_(e_invalid_value_for_argument_str), "end_col");
- return;
+ goto theend;
}
}
else if (start_lnum == end_lnum)
@@ -441,17 +476,40 @@ prop_add_common(
if (dict_has_key(dict, "id"))
id = dict_get_number(dict, "id");
+ if (dict_has_key(dict, "text"))
+ {
+ text = dict_get_string(dict, "text", TRUE);
+ if (text == NULL)
+ goto theend;
+ // use a default length of 1 to make multiple props show up
+ end_col = start_col + 1;
+ }
+
if (dict_arg != NULL && get_bufnr_from_arg(dict_arg, &buf) == FAIL)
- return;
+ goto theend;
+
+ if (id < 0 && buf->b_textprop_text.ga_len > 0)
+ {
+ emsg(_(e_cannot_use_negative_id_after_adding_textprop_with_text));
+ goto theend;
+ }
+ if (text != NULL)
+ id = get_textprop_id(buf);
// This must be done _before_ we add the property because property changes
// trigger buffer (memline) reorganisation, which needs this flag to be
// correctly set.
buf->b_has_textprop = TRUE; // this is never reset
- prop_add_one(buf, type_name, id, start_lnum, end_lnum, start_col, end_col);
+ prop_add_one(buf, type_name, id, text,
+ start_lnum, end_lnum, start_col, end_col);
+ text = NULL;
redraw_buf_later(buf, VALID);
+
+theend:
+ vim_free(text);
+ return id;
}
/*
@@ -954,9 +1012,9 @@ get_props_in_line(
if ((prop_types == NULL
|| prop_type_or_id_in_list(prop_types, prop_types_len,
prop.tp_type))
- && (prop_ids == NULL ||
- prop_type_or_id_in_list(prop_ids, prop_ids_len,
- prop.tp_id)))
+ && (prop_ids == NULL
+ || prop_type_or_id_in_list(prop_ids, prop_ids_len,
+ prop.tp_id)))
{
dict_T *d = dict_alloc();