Mercurial > vim
comparison src/textprop.c @ 29560:14b139cbec49 v9.0.0121
patch 9.0.0121: cannot put virtual text after or below a line
Commit: https://github.com/vim/vim/commit/b7963df98f9dbbb824713acad2f47c9989fcf8f3
Author: Bram Moolenaar <Bram@vim.org>
Date: Sun Jul 31 17:12:43 2022 +0100
patch 9.0.0121: cannot put virtual text after or below a line
Problem: Cannot put virtual text after or below a line.
Solution: Add "text_align" and "text_wrap" arguments.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sun, 31 Jul 2022 18:15:03 +0200 |
parents | 89a97f70e8eb |
children | 4a79bca8a76e |
comparison
equal
deleted
inserted
replaced
29559:69ceb540c619 | 29560:14b139cbec49 |
---|---|
161 || check_for_dict_arg(argvars, 2) == FAIL)) | 161 || check_for_dict_arg(argvars, 2) == FAIL)) |
162 return; | 162 return; |
163 | 163 |
164 start_lnum = tv_get_number(&argvars[0]); | 164 start_lnum = tv_get_number(&argvars[0]); |
165 start_col = tv_get_number(&argvars[1]); | 165 start_col = tv_get_number(&argvars[1]); |
166 if (start_col < 1) | |
167 { | |
168 semsg(_(e_invalid_column_number_nr), (long)start_col); | |
169 return; | |
170 } | |
171 if (argvars[2].v_type != VAR_DICT) | 166 if (argvars[2].v_type != VAR_DICT) |
172 { | 167 { |
173 emsg(_(e_dictionary_required)); | 168 emsg(_(e_dictionary_required)); |
174 return; | 169 return; |
175 } | 170 } |
188 prop_add_one( | 183 prop_add_one( |
189 buf_T *buf, | 184 buf_T *buf, |
190 char_u *type_name, | 185 char_u *type_name, |
191 int id, | 186 int id, |
192 char_u *text_arg, | 187 char_u *text_arg, |
188 int text_flags, | |
193 linenr_T start_lnum, | 189 linenr_T start_lnum, |
194 linenr_T end_lnum, | 190 linenr_T end_lnum, |
195 colnr_T start_col, | 191 colnr_T start_col, |
196 colnr_T end_col) | 192 colnr_T end_col) |
197 { | 193 { |
254 | 250 |
255 if (lnum == start_lnum) | 251 if (lnum == start_lnum) |
256 col = start_col; | 252 col = start_col; |
257 else | 253 else |
258 col = 1; | 254 col = 1; |
259 if (col - 1 > (colnr_T)textlen) | 255 if (col - 1 > (colnr_T)textlen && !(col == 0 && text_arg != NULL)) |
260 { | 256 { |
261 semsg(_(e_invalid_column_number_nr), (long)start_col); | 257 semsg(_(e_invalid_column_number_nr), (long)start_col); |
262 goto theend; | 258 goto theend; |
263 } | 259 } |
264 | 260 |
269 if (length > (long)textlen) | 265 if (length > (long)textlen) |
270 length = (int)textlen; // can include the end-of-line | 266 length = (int)textlen; // can include the end-of-line |
271 if (length < 0) | 267 if (length < 0) |
272 length = 0; // zero-width property | 268 length = 0; // zero-width property |
273 | 269 |
270 if (text_arg != NULL) | |
271 { | |
272 length = 1; // text is placed on one character | |
273 if (col == 0) | |
274 col = MAXCOL; // after the line | |
275 } | |
276 | |
274 // Allocate the new line with space for the new property. | 277 // Allocate the new line with space for the new property. |
275 newtext = alloc(buf->b_ml.ml_line_len + sizeof(textprop_T)); | 278 newtext = alloc(buf->b_ml.ml_line_len + sizeof(textprop_T)); |
276 if (newtext == NULL) | 279 if (newtext == NULL) |
277 goto theend; | 280 goto theend; |
278 // Copy the text, including terminating NUL. | 281 // Copy the text, including terminating NUL. |
294 | 297 |
295 tmp_prop.tp_col = col; | 298 tmp_prop.tp_col = col; |
296 tmp_prop.tp_len = length; | 299 tmp_prop.tp_len = length; |
297 tmp_prop.tp_id = id; | 300 tmp_prop.tp_id = id; |
298 tmp_prop.tp_type = type->pt_id; | 301 tmp_prop.tp_type = type->pt_id; |
299 tmp_prop.tp_flags = (lnum > start_lnum ? TP_FLAG_CONT_PREV : 0) | 302 tmp_prop.tp_flags = text_flags |
300 | (lnum < end_lnum ? TP_FLAG_CONT_NEXT : 0); | 303 | (lnum > start_lnum ? TP_FLAG_CONT_PREV : 0) |
304 | (lnum < end_lnum ? TP_FLAG_CONT_NEXT : 0); | |
301 mch_memmove(newprops + i * sizeof(textprop_T), &tmp_prop, | 305 mch_memmove(newprops + i * sizeof(textprop_T), &tmp_prop, |
302 sizeof(textprop_T)); | 306 sizeof(textprop_T)); |
303 | 307 |
304 if (i < proplen) | 308 if (i < proplen) |
305 mch_memmove(newprops + (i + 1) * sizeof(textprop_T), | 309 mch_memmove(newprops + (i + 1) * sizeof(textprop_T), |
388 || end_lnum <= 0 || end_col <= 0) | 392 || end_lnum <= 0 || end_col <= 0) |
389 { | 393 { |
390 emsg(_(e_invalid_argument)); | 394 emsg(_(e_invalid_argument)); |
391 return; | 395 return; |
392 } | 396 } |
393 if (prop_add_one(buf, type_name, id, NULL, start_lnum, end_lnum, | 397 if (prop_add_one(buf, type_name, id, NULL, 0, start_lnum, end_lnum, |
394 start_col, end_col) == FAIL) | 398 start_col, end_col) == FAIL) |
395 return; | 399 return; |
396 } | 400 } |
397 | 401 |
398 redraw_buf_later(buf, VALID); | 402 redraw_buf_later(buf, VALID); |
426 colnr_T end_col; | 430 colnr_T end_col; |
427 char_u *type_name; | 431 char_u *type_name; |
428 buf_T *buf = default_buf; | 432 buf_T *buf = default_buf; |
429 int id = 0; | 433 int id = 0; |
430 char_u *text = NULL; | 434 char_u *text = NULL; |
435 int flags = 0; | |
431 | 436 |
432 if (dict == NULL || !dict_has_key(dict, "type")) | 437 if (dict == NULL || !dict_has_key(dict, "type")) |
433 { | 438 { |
434 emsg(_(e_missing_property_type_name)); | 439 emsg(_(e_missing_property_type_name)); |
435 goto theend; | 440 goto theend; |
481 text = dict_get_string(dict, "text", TRUE); | 486 text = dict_get_string(dict, "text", TRUE); |
482 if (text == NULL) | 487 if (text == NULL) |
483 goto theend; | 488 goto theend; |
484 // use a default length of 1 to make multiple props show up | 489 // use a default length of 1 to make multiple props show up |
485 end_col = start_col + 1; | 490 end_col = start_col + 1; |
491 | |
492 if (dict_has_key(dict, "text_align")) | |
493 { | |
494 char_u *p = dict_get_string(dict, "text_align", FALSE); | |
495 | |
496 if (p == NULL) | |
497 goto theend; | |
498 if (STRCMP(p, "right") == 0) | |
499 flags |= TP_FLAG_ALIGN_RIGHT; | |
500 else if (STRCMP(p, "below") == 0) | |
501 flags |= TP_FLAG_ALIGN_BELOW; | |
502 else if (STRCMP(p, "after") != 0) | |
503 { | |
504 semsg(_(e_invalid_value_for_argument_str_str), "text_align", p); | |
505 goto theend; | |
506 } | |
507 } | |
508 | |
509 if (dict_has_key(dict, "text_wrap")) | |
510 { | |
511 char_u *p = dict_get_string(dict, "text_wrap", FALSE); | |
512 if (p == NULL) | |
513 goto theend; | |
514 if (STRCMP(p, "wrap") == 0) | |
515 flags |= TP_FLAG_WRAP; | |
516 else if (STRCMP(p, "truncate") != 0) | |
517 { | |
518 semsg(_(e_invalid_value_for_argument_str_str), "text_wrap", p); | |
519 goto theend; | |
520 } | |
521 } | |
522 } | |
523 | |
524 // Column must be 1 or more for a normal text property; when "text" is | |
525 // present zero means it goes after the line. | |
526 if (start_col < (text == NULL ? 1 : 0)) | |
527 { | |
528 semsg(_(e_invalid_column_number_nr), (long)start_col); | |
529 goto theend; | |
486 } | 530 } |
487 | 531 |
488 if (dict_arg != NULL && get_bufnr_from_arg(dict_arg, &buf) == FAIL) | 532 if (dict_arg != NULL && get_bufnr_from_arg(dict_arg, &buf) == FAIL) |
489 goto theend; | 533 goto theend; |
490 | 534 |
499 // This must be done _before_ we add the property because property changes | 543 // This must be done _before_ we add the property because property changes |
500 // trigger buffer (memline) reorganisation, which needs this flag to be | 544 // trigger buffer (memline) reorganisation, which needs this flag to be |
501 // correctly set. | 545 // correctly set. |
502 buf->b_has_textprop = TRUE; // this is never reset | 546 buf->b_has_textprop = TRUE; // this is never reset |
503 | 547 |
504 prop_add_one(buf, type_name, id, text, | 548 prop_add_one(buf, type_name, id, text, flags, |
505 start_lnum, end_lnum, start_col, end_col); | 549 start_lnum, end_lnum, start_col, end_col); |
506 text = NULL; | 550 text = NULL; |
507 | 551 |
508 redraw_buf_later(buf, VALID); | 552 redraw_buf_later(buf, VALID); |
509 | 553 |
1736 * "flags" can have: | 1780 * "flags" can have: |
1737 * APC_SUBSTITUTE: Text is replaced, not inserted. | 1781 * APC_SUBSTITUTE: Text is replaced, not inserted. |
1738 */ | 1782 */ |
1739 static adjustres_T | 1783 static adjustres_T |
1740 adjust_prop( | 1784 adjust_prop( |
1741 textprop_T *prop, | 1785 textprop_T *prop, |
1742 colnr_T col, | 1786 colnr_T col, |
1743 int added, | 1787 int added, |
1744 int flags) | 1788 int flags) |
1745 { | 1789 { |
1746 proptype_T *pt = text_prop_type_by_id(curbuf, prop->tp_type); | 1790 proptype_T *pt; |
1747 int start_incl = (pt != NULL | 1791 int start_incl; |
1748 && (pt->pt_flags & PT_FLAG_INS_START_INCL)) | 1792 int end_incl; |
1793 int droppable; | |
1794 adjustres_T res = {TRUE, FALSE}; | |
1795 | |
1796 // prop after end of the line doesn't move | |
1797 if (prop->tp_col == MAXCOL) | |
1798 { | |
1799 res.dirty = FALSE; | |
1800 return res; | |
1801 } | |
1802 | |
1803 pt = text_prop_type_by_id(curbuf, prop->tp_type); | |
1804 start_incl = (pt != NULL && (pt->pt_flags & PT_FLAG_INS_START_INCL)) | |
1749 || (flags & APC_SUBSTITUTE) | 1805 || (flags & APC_SUBSTITUTE) |
1750 || (prop->tp_flags & TP_FLAG_CONT_PREV); | 1806 || (prop->tp_flags & TP_FLAG_CONT_PREV); |
1751 int end_incl = (pt != NULL | 1807 end_incl = (pt != NULL && (pt->pt_flags & PT_FLAG_INS_END_INCL)) |
1752 && (pt->pt_flags & PT_FLAG_INS_END_INCL)) | |
1753 || (prop->tp_flags & TP_FLAG_CONT_NEXT); | 1808 || (prop->tp_flags & TP_FLAG_CONT_NEXT); |
1754 // Do not drop zero-width props if they later can increase in size. | 1809 // do not drop zero-width props if they later can increase in size |
1755 int droppable = !(start_incl || end_incl); | 1810 droppable = !(start_incl || end_incl); |
1756 adjustres_T res = {TRUE, FALSE}; | |
1757 | 1811 |
1758 if (added > 0) | 1812 if (added > 0) |
1759 { | 1813 { |
1760 if (col + 1 <= prop->tp_col | 1814 if (col + 1 <= prop->tp_col |
1761 - (start_incl || (prop->tp_len == 0 && end_incl))) | 1815 - (start_incl || (prop->tp_len == 0 && end_incl))) |