diff options
Diffstat (limited to 'data/vim/patches/8.1.0579')
-rw-r--r-- | data/vim/patches/8.1.0579 | 2526 |
1 files changed, 2526 insertions, 0 deletions
diff --git a/data/vim/patches/8.1.0579 b/data/vim/patches/8.1.0579 new file mode 100644 index 000000000..421d0328f --- /dev/null +++ b/data/vim/patches/8.1.0579 @@ -0,0 +1,2526 @@ +To: vim_dev@googlegroups.com +Subject: Patch 8.1.0580 +Fcc: outbox +From: Bram Moolenaar <Bram@moolenaar.net> +Mime-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit +------------ + +Patch 8.1.0580 +Problem: Cannot attach properties to text. +Solution: First part of adding text properties. +Files: Filelist, runtime/doc/Makefile, runtime/doc/eval.txt, + runtime/doc/textprop.txt, src/Make_all.mak, src/Make_cyg_ming.mak, + src/Make_mvc.mak, src/Makefile, src/buffer.c, src/edit.c, + src/evalfunc.c, src/feature.h, src/memline.c, src/misc1.c, + src/misc2.c, src/proto.h, src/proto/memline.pro, + src/proto/textprop.pro, src/screen.c, src/structs.h, + src/testdir/Make_all.mak, src/testdir/test_textprop.vim, + src/textprop.c, src/userfunc.c, src/version.c + + +*** ../vim-8.1.0578/Filelist 2018-10-25 16:52:46.839887739 +0200 +--- Filelist 2018-12-13 19:59:08.647713430 +0100 +*************** +*** 91,96 **** +--- 91,97 ---- + src/terminal.c \ + src/term.h \ + src/termlib.c \ ++ src/textprop.c \ + src/ui.c \ + src/undo.c \ + src/userfunc.c \ +*************** +*** 198,203 **** +--- 199,205 ---- + src/proto/term.pro \ + src/proto/terminal.pro \ + src/proto/termlib.pro \ ++ src/proto/textprop.pro \ + src/proto/ui.pro \ + src/proto/undo.pro \ + src/proto/userfunc.pro \ +*** ../vim-8.1.0578/runtime/doc/Makefile 2017-11-24 20:49:13.000000000 +0100 +--- runtime/doc/Makefile 2018-12-13 20:01:21.774863565 +0100 +*************** +*** 102,107 **** +--- 102,108 ---- + tagsrch.txt \ + term.txt \ + terminal.txt \ ++ textprop.txt \ + tips.txt \ + todo.txt \ + uganda.txt \ +*************** +*** 238,243 **** +--- 239,245 ---- + tagsrch.html \ + term.html \ + terminal.html \ ++ textprop.html \ + tips.html \ + todo.html \ + uganda.html \ +*** ../vim-8.1.0578/runtime/doc/eval.txt 2018-11-22 03:07:30.940596247 +0100 +--- runtime/doc/eval.txt 2018-12-13 22:11:02.636894993 +0100 +*************** +*** 2300,2309 **** + pow({x}, {y}) Float {x} to the power of {y} + prevnonblank({lnum}) Number line nr of non-blank line <= {lnum} + printf({fmt}, {expr1}...) String format text +- prompt_addtext({buf}, {expr}) none add text to a prompt buffer + prompt_setcallback({buf}, {expr}) none set prompt callback function + prompt_setinterrupt({buf}, {text}) none set prompt interrupt function + prompt_setprompt({buf}, {text}) none set prompt text + pumvisible() Number whether popup menu is visible + pyeval({expr}) any evaluate |Python| expression + py3eval({expr}) any evaluate |python3| expression +--- 2314,2338 ---- + pow({x}, {y}) Float {x} to the power of {y} + prevnonblank({lnum}) Number line nr of non-blank line <= {lnum} + printf({fmt}, {expr1}...) String format text + prompt_setcallback({buf}, {expr}) none set prompt callback function + prompt_setinterrupt({buf}, {text}) none set prompt interrupt function + prompt_setprompt({buf}, {text}) none set prompt text ++ prop_add({lnum}, {col}, {props}) none add a text property ++ prop_clear({lnum} [, {lnum_end} [, {bufnr}]]) ++ none remove all text properties ++ prop_find({props} [, {direction}]) ++ Dict search for a text property ++ prop_list({lnum} [, {props}) List text properties in {lnum} ++ prop_remove({props} [, {lnum} [, {lnum_end}]]) ++ Number remove a text property ++ prop_type_add({name}, {props}) none define a new property type ++ prop_type_change({name}, {props}) ++ none change an existing property type ++ prop_type_delete({name} [, {props}]) ++ none delete a property type ++ prop_type_get([{name} [, {props}]) ++ Dict get property type values ++ prop_type_list([{props}]) List get list of property types + pumvisible() Number whether popup menu is visible + pyeval({expr}) any evaluate |Python| expression + py3eval({expr}) any evaluate |python3| expression +*************** +*** 6642,6647 **** +--- 6673,6863 ---- + The result is only visible if {buf} has 'buftype' set to + "prompt". Example: > + call prompt_setprompt(bufnr(''), 'command: ') ++ < ++ *prop_add()* *E965* ++ prop_add({lnum}, {col}, {props}) ++ Attach a text property at position {lnum}, {col}. Use one for ++ the first column. ++ If {lnum} is invalid an error is given. *E966* ++ If {col} is invalid an error is given. *E964* ++ ++ {props} is a dictionary with these fields: ++ "length" - length of text in characters, can only be ++ used for a property that does not ++ continue in another line ++ "end_lnum" - line number for end of text ++ "end_col" - column for end of text; not used when ++ "length" is present ++ "bufnr - buffer to add the property to; when ++ omitted the current buffer is used ++ "id" - user defined ID for the property; when ++ omitted zero is used ++ "type" - name of the text property type ++ All fields except "type" are optional. ++ ++ It is an error when both "length" and "end_lnum" or "end_col" ++ are passed. Either use "length" or "end_col" for a property ++ within one line, or use "end_lnum" and "end_col" for a ++ property that spans more than one line. ++ When neither "length" or "end_col" are passed the property ++ will apply to one character. ++ ++ "type" will first be looked up in the buffer the property is ++ added to. When not found, the global property types are used. ++ If not found an error is given. ++ ++ See |text-properties| for information about text properties. ++ ++ ++ prop_clear({lnum} [, {lnum_end} [, {props}]]) *prop_clear()* ++ Remove all text properties from line {lnum}. ++ When {lnum_end} is given, remove all text properties from line ++ {lnum} to {lnum_end} (inclusive). ++ ++ When {props} contains a "bufnr" item use this buffer, ++ otherwise use the current buffer. ++ ++ See |text-properties| for information about text properties. ++ ++ *prop_find()* ++ prop_find({props} [, {direction}]) ++ NOT IMPLEMENTED YET ++ Search for a text property as specified with {props}: ++ "id" property with this ID ++ "type" property with this type name ++ "bufnr buffer to search in; when present a ++ start position with "lnum" and "col" ++ must be given; when omitted the ++ current buffer is used ++ "lnum" start in this line (when omitted start ++ at the cursor) ++ "col" start at this column (when omitted ++ and "lnum" is given: use column 1, ++ otherwise start at the cursor) ++ "skipstart" do not look for a match at the start ++ position ++ ++ {direction} can be "f" for forward and "b" for backward. When ++ omitted forward search is performed. ++ ++ If a match is found then a Dict is returned with the entries ++ as with prop_list(), and additionally an "lnum" entry. ++ If no match is found then an empty Dict is returned. ++ ++ See |text-properties| for information about text properties. ++ ++ ++ prop_list({lnum} [, {props}]) *prop_list()* ++ Return a List with all text properties in line {lnum}. ++ ++ When {props} contains a "bufnr" item, use this buffer instead ++ of the current buffer. ++ ++ The properties are ordered by starting column and priority. ++ Each property is a Dict with these entries: ++ "col" starting column ++ "length" length in bytes ++ "id" property ID ++ "type" name of the property type, omitted if ++ the type was deleted ++ "start" when TRUE property starts in this line ++ "end" when TRUE property ends in this line ++ ++ When "start" is zero the property started in a previous line, ++ the current one is a continuation. ++ When "end" is zero the property continues in the next line. ++ The line break after this line is included. ++ ++ See |text-properties| for information about text properties. ++ ++ ++ *prop_remove()* *E968* ++ prop_remove({props} [, {lnum} [, {lnum_end}]]) ++ Remove a matching text property from line {lnum}. When ++ {lnum_end} is given, remove matching text properties from line ++ {lnum} to {lnum_end} (inclusive). ++ When {lnum} is omitted remove matching text properties from ++ all lines. ++ ++ {props} is a dictionary with these fields: ++ "id" - remove text properties with this ID ++ "type" - remove text properties with this type name ++ "bufnr" - use this buffer instead of the current one ++ "all" - when TRUE remove all matching text ++ properties, not just the first one ++ A property matches when either "id" or "type" matches. ++ ++ Returns the number of properties that were removed. ++ ++ See |text-properties| for information about text properties. ++ ++ ++ prop_type_add({name}, {props}) *prop_type_add()* *E969* *E970* ++ Add a text property type {name}. If a property type with this ++ name already exists an error is given. ++ {props} is a dictionary with these optional fields: ++ "bufnr" - define the property only for this ++ buffer; this avoids name collisions and ++ automatically clears the property types ++ when the buffer is deleted. ++ "highlight" - name of highlight group to use ++ "priority" - when a character has multiple text ++ properties the one with the highest ++ priority will be used; negative values ++ can be used, the default priority is ++ zero ++ "start_incl" - when TRUE inserts at the start ++ position will be included in the text ++ property ++ "end_incl" - when TRUE inserts at the end ++ position will be included in the text ++ property ++ ++ See |text-properties| for information about text properties. ++ ++ ++ prop_type_change({name}, {props}) *prop_type_change()* ++ Change properties of an existing text property type. If a ++ property with this name does not exist an error is given. ++ The {props} argument is just like |prop_type_add()|. ++ ++ See |text-properties| for information about text properties. ++ ++ ++ prop_type_delete({name} [, {props}]) *prop_type_delete()* ++ Remove the text property type {name}. When text properties ++ using the type {name} are still in place, they will not have ++ an effect and can no longer be removed by name. ++ ++ {props} can contain a "bufnr" item. When it is given, delete ++ a property type from this buffer instead of from the global ++ property types. ++ ++ When text property type {name} is not found there is no error. ++ ++ See |text-properties| for information about text properties. ++ ++ ++ prop_type_get([{name} [, {props}]) *prop_type_get()* ++ Returns the properties of property type {name}. This is a ++ dictionary with the same fields as was given to ++ prop_type_add(). ++ When the property type {name} does not exist, an empty ++ dictionary is returned. ++ ++ {props} can contain a "bufnr" item. When it is given, use ++ this buffer instead of the global property types. ++ ++ See |text-properties| for information about text properties. ++ ++ ++ prop_type_list([{props}]) *prop_type_list()* ++ Returns a list with all property type names. ++ ++ {props} can contain a "bufnr" item. When it is given, use ++ this buffer instead of the global property types. ++ ++ See |text-properties| for information about text properties. + + + pumvisible() *pumvisible()* +*** ../vim-8.1.0578/runtime/doc/textprop.txt 2018-12-13 22:11:43.932591369 +0100 +--- runtime/doc/textprop.txt 2018-12-13 21:59:47.042285684 +0100 +*************** +*** 0 **** +--- 1,114 ---- ++ *textprop.txt* For Vim version 8.1. Last change: 2018 Dec 13 ++ ++ ++ VIM REFERENCE MANUAL by Bram Moolenaar ++ ++ ++ Displaying text with properties attached. *text-properties* ++ ++ THIS IS UNDER DEVELOPMENT - ANYTHING MAY STILL CHANGE *E967* ++ ++ What is not working yet: ++ - Adjusting column/length when inserting text ++ - Text properties spanning more than one line ++ - prop_find() ++ - callbacks when text properties are outdated ++ ++ ++ 1. Introduction |text-prop-intro| ++ 2. Functions |text-prop-functions| ++ ++ ++ {Vi does not have text properties} ++ {not able to use text properties when the |+textprop| feature was ++ disabled at compile time} ++ ++ ============================================================================== ++ 1. Introduction *text-prop-intro* ++ ++ Text properties can be attached to text in a buffer. They will move with the ++ text: If lines are deleted or inserted the properties move with the text they ++ are attached to. Also when inserting/deleting text in the line before the ++ text property. And when inserting/deleting text inside the text property, it ++ will increase/decrease in size. ++ ++ The main use for text properties is to highlight text. This can be seen as a ++ replacement for syntax highlighting. Instead of defining patterns to match ++ the text, the highlighting is set by a script, possibly using the output of an ++ external parser. This only needs to be done once, not every time when ++ redrawing the screen, thus can be much faster, after the initial cost of ++ attaching the text properties. ++ ++ Text properties can also be used for other purposes to identify text. For ++ example, add a text property on a function name, so that a search can be ++ defined to jump to the next/previous function. ++ ++ A text property is attached at a specific line and column, and has a specified ++ length. The property can span multiple lines. ++ ++ A text property has these fields: ++ "id" a number to be used as desired ++ "type" the name of a property type ++ ++ ++ Property Types ~ ++ *E971* ++ A text property normally has the name of a property type, which defines ++ how to highlight the text. The property type can have these entries: ++ "highlight" name of the highlight group to use ++ "priority" when properties overlap, the one with the highest ++ priority will be used. ++ "start_incl" when TRUE inserts at the start position will be ++ included in the text property ++ "end_incl" when TRUE inserts at the end position will be ++ included in the text property ++ ++ ++ Example ~ ++ ++ Suppose line 11 in a buffer has this text (excluding the indent): ++ ++ The number 123 is smaller than 4567. ++ ++ To highlight the numbers: > ++ call prop_type_add('number', {'highlight': 'Constant'}) ++ call prop_add(11, 12, {'length': 3, 'type': 'number}) ++ call prop_add(11, 32, {'length': 4, 'type': 'number}) ++ ++ Setting "start_incl" and "end_incl" is useful when white space surrounds the ++ text, e.g. for a function name. Using false is useful when the text starts ++ and/or ends with a specific character, such as the quote surrounding a string. ++ ++ func FuncName(arg) ~ ++ ^^^^^^^^ property with start_incl and end_incl set ++ ++ var = "text"; ~ ++ ^^^^^^ property with start_incl and end_incl not set ++ ++ Nevertheless, when text is inserted or deleted the text may need to be parsed ++ and the text properties updated. But this can be done asynchrnously. ++ ++ ============================================================================== ++ 2. Functions *text-prop-functions* ++ ++ Manipulating text property types: ++ ++ prop_type_add({name}, {props}) define a new property type ++ prop_type_change({name}, {props}) change an existing property type ++ prop_type_delete({name} [, {props}]) delete a property type ++ prop_type_get([{name} [, {props}]) get property type values ++ prop_type_list([{props}]) get list of property types ++ ++ ++ Manipulating text properties: ++ ++ prop_add({lnum}, {col}, {props}) add a text property ++ prop_clear({lnum} [, {lnum_end} [, {bufnr}]]) ++ remove all text properties ++ prop_find({props} [, {direction}]) search for a text property ++ prop_list({lnum} [, {props}) text properties in {lnum} ++ prop_remove({props} [, {lnum} [, {lnum_end}]]) ++ remove a text property ++ ++ ++ vim:tw=78:ts=8:noet:ft=help:norl: +*** ../vim-8.1.0578/src/Make_all.mak 2018-11-30 22:40:09.098211991 +0100 +--- src/Make_all.mak 2018-12-13 20:05:00.737457532 +0100 +*************** +*** 186,191 **** +--- 186,192 ---- + test_terminal_fail \ + test_textformat \ + test_textobjects \ ++ test_textprop \ + test_timers \ + test_true_false \ + test_undo \ +*** ../vim-8.1.0578/src/Make_cyg_ming.mak 2018-10-21 22:45:39.117688669 +0200 +--- src/Make_cyg_ming.mak 2018-12-13 20:06:02.481059654 +0100 +*************** +*** 751,756 **** +--- 751,757 ---- + $(OUTDIR)/syntax.o \ + $(OUTDIR)/tag.o \ + $(OUTDIR)/term.o \ ++ $(OUTDIR)/textprop.o \ + $(OUTDIR)/ui.o \ + $(OUTDIR)/undo.o \ + $(OUTDIR)/userfunc.o \ +*************** +*** 1090,1095 **** +--- 1091,1099 ---- + $(OUTDIR)/terminal.o: terminal.c $(INCL) $(TERM_DEPS) + $(CC) -c $(CFLAGS) terminal.c -o $(OUTDIR)/terminal.o + ++ $(OUTDIR)/textprop.o: textprop.c $(INCL) ++ $(CC) -c $(CFLAGS) textprop.c -o $(OUTDIR)/textprop.o ++ + + CCCTERM = $(CC) -c $(CFLAGS) -Ilibvterm/include -DINLINE="" \ + -DVSNPRINTF=vim_vsnprintf \ +*** ../vim-8.1.0578/src/Make_mvc.mak 2018-11-12 21:42:20.678152930 +0100 +--- src/Make_mvc.mak 2018-12-13 20:07:31.472486033 +0100 +*************** +*** 754,759 **** +--- 754,760 ---- + $(OUTDIR)\syntax.obj \ + $(OUTDIR)\tag.obj \ + $(OUTDIR)\term.obj \ ++ $(OUTDIR)\textprop.obj \ + $(OUTDIR)\ui.obj \ + $(OUTDIR)\undo.obj \ + $(OUTDIR)\userfunc.obj \ +*************** +*** 1529,1534 **** +--- 1530,1537 ---- + + $(OUTDIR)/term.obj: $(OUTDIR) term.c $(INCL) + ++ $(OUTDIR)/textprop.obj: $(OUTDIR) textprop.c $(INCL) ++ + $(OUTDIR)/ui.obj: $(OUTDIR) ui.c $(INCL) + + $(OUTDIR)/undo.obj: $(OUTDIR) undo.c $(INCL) +*************** +*** 1667,1672 **** +--- 1670,1676 ---- + proto/syntax.pro \ + proto/tag.pro \ + proto/term.pro \ ++ proto/textprop.pro \ + proto/ui.pro \ + proto/undo.pro \ + proto/userfunc.pro \ +*** ../vim-8.1.0578/src/Makefile 2018-12-12 20:34:06.072356129 +0100 +--- src/Makefile 2018-12-13 20:08:00.680336028 +0100 +*************** +*** 1577,1584 **** + # TAGS_INCL: include files used for make tags + # ALL_SRC: source files used for make depend and make lint + +- TAGS_INCL = *.h +- + BASIC_SRC = \ + arabic.c \ + beval.c \ +--- 1579,1584 ---- +*************** +*** 1636,1641 **** +--- 1636,1642 ---- + tag.c \ + term.c \ + terminal.c \ ++ textprop.c \ + ui.c \ + undo.c \ + userfunc.c \ +*************** +*** 1657,1663 **** + $(WORKSHOP_SRC) \ + $(WSDEBUG_SRC) + +! TAGS_SRC = *.c *.cpp if_perl.xs + + EXTRA_SRC = hangulin.c if_lua.c if_mzsch.c auto/if_perl.c if_perlsfio.c \ + if_python.c if_python3.c if_tcl.c if_ruby.c \ +--- 1658,1665 ---- + $(WORKSHOP_SRC) \ + $(WSDEBUG_SRC) + +! TAGS_SRC = *.c *.cpp $(PERL_SRC) $(TERM_SRC) $(XDIFF_SRC) +! TAGS_INCL = *.h $(TERM_DEPS) $(XDIFF_INCL) + + EXTRA_SRC = hangulin.c if_lua.c if_mzsch.c auto/if_perl.c if_perlsfio.c \ + if_python.c if_python3.c if_tcl.c if_ruby.c \ +*************** +*** 1747,1752 **** +--- 1749,1755 ---- + objects/tag.o \ + objects/term.o \ + objects/terminal.o \ ++ objects/textprop.o \ + objects/ui.o \ + objects/undo.o \ + objects/userfunc.o \ +*************** +*** 1881,1886 **** +--- 1884,1890 ---- + term.pro \ + terminal.pro \ + termlib.pro \ ++ textprop.pro \ + ui.pro \ + undo.pro \ + userfunc.pro \ +*************** +*** 2092,2098 **** + # Motif and Athena GUI + # You can ignore error messages for missing files. + tags TAGS: notags +! $(TAGPRG) $(TAGS_SRC) $(TAGS_INCL) $(TERM_SRC) $(TERM_DEPS) + + # Make a highlight file for types. Requires Exuberant ctags and awk + types: types.vim +--- 2096,2102 ---- + # Motif and Athena GUI + # You can ignore error messages for missing files. + tags TAGS: notags +! $(TAGPRG) $(TAGS_SRC) $(TAGS_INCL) + + # Make a highlight file for types. Requires Exuberant ctags and awk + types: types.vim +*************** +*** 3211,3216 **** +--- 3215,3223 ---- + objects/terminal.o: terminal.c $(TERM_DEPS) + $(CCC) -o $@ terminal.c + ++ objects/textprop.o: textprop.c ++ $(CCC) -o $@ textprop.c ++ + objects/ui.o: ui.c + $(CCC) -o $@ ui.c + +*************** +*** 3602,3607 **** +--- 3609,3618 ---- + proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \ + proto.h globals.h farsi.h arabic.h libvterm/include/vterm.h \ + libvterm/include/vterm_keycodes.h ++ objects/textprop.o: textprop.c vim.h protodef.h auto/config.h feature.h os_unix.h \ ++ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \ ++ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \ ++ proto.h globals.h farsi.h arabic.h + objects/ui.o: ui.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \ +*** ../vim-8.1.0578/src/buffer.c 2018-11-20 13:32:30.276983764 +0100 +--- src/buffer.c 2018-12-13 20:09:44.819785821 +0100 +*************** +*** 823,828 **** +--- 823,831 ---- + #ifdef FEAT_SYN_HL + syntax_clear(&buf->b_s); /* reset syntax info */ + #endif ++ #ifdef FEAT_TEXT_PROP ++ clear_buf_prop_types(buf); ++ #endif + buf->b_flags &= ~BF_READERR; /* a read error is no longer relevant */ + } + +*** ../vim-8.1.0578/src/edit.c 2018-11-22 03:07:30.944596219 +0100 +--- src/edit.c 2018-12-13 20:09:58.939709543 +0100 +*************** +*** 10302,10307 **** +--- 10302,10310 ---- + if ((State & REPLACE_FLAG) && !(State & VREPLACE_FLAG)) + for (temp = i; --temp >= 0; ) + replace_join(repl_off); ++ #ifdef FEAT_TEXT_PROP ++ curbuf->b_ml.ml_line_len -= i; ++ #endif + } + #ifdef FEAT_NETBEANS_INTG + if (netbeans_active()) +*** ../vim-8.1.0578/src/evalfunc.c 2018-12-08 13:57:38.553692769 +0100 +--- src/evalfunc.c 2018-12-13 22:04:35.855854438 +0100 +*************** +*** 772,777 **** +--- 772,788 ---- + {"prompt_setinterrupt", 2, 2, f_prompt_setinterrupt}, + {"prompt_setprompt", 2, 2, f_prompt_setprompt}, + #endif ++ #ifdef FEAT_TEXT_PROP ++ {"prop_add", 3, 3, f_prop_add}, ++ {"prop_clear", 1, 3, f_prop_clear}, ++ {"prop_list", 1, 2, f_prop_list}, ++ {"prop_remove", 2, 3, f_prop_remove}, ++ {"prop_type_add", 2, 2, f_prop_type_add}, ++ {"prop_type_change", 2, 2, f_prop_type_change}, ++ {"prop_type_delete", 1, 2, f_prop_type_delete}, ++ {"prop_type_get", 1, 2, f_prop_type_get}, ++ {"prop_type_list", 0, 1, f_prop_type_list}, ++ #endif + {"pumvisible", 0, 0, f_pumvisible}, + #ifdef FEAT_PYTHON3 + {"py3eval", 1, 1, f_py3eval}, +*************** +*** 6478,6483 **** +--- 6489,6497 ---- + #ifdef FEAT_TEXTOBJ + "textobjects", + #endif ++ #ifdef FEAT_TEXT_PROP ++ "textprop", ++ #endif + #ifdef HAVE_TGETENT + "tgetent", + #endif +*** ../vim-8.1.0578/src/ex_getln.c 2018-11-30 21:57:50.719861887 +0100 +--- src/ex_getln.c 2018-12-12 22:31:57.398336802 +0100 +*************** +*** 769,774 **** +--- 769,789 ---- + stuffcharReadbuff(*c); + *c = '\\'; + } ++ #ifdef FEAT_MBYTE ++ // add any composing characters ++ if (mb_char2len(*c) != mb_ptr2len(ml_get_cursor())) ++ { ++ int save_c = *c; ++ ++ while (mb_char2len(*c) != mb_ptr2len(ml_get_cursor())) ++ { ++ curwin->w_cursor.col += mb_char2len(*c); ++ *c = gchar_cursor(); ++ stuffcharReadbuff(*c); ++ } ++ *c = save_c; ++ } ++ #endif + return FAIL; + } + } +*** ../vim-8.1.0578/src/feature.h 2018-12-12 20:34:06.072356129 +0100 +--- src/feature.h 2018-12-13 20:12:33.566852272 +0100 +*************** +*** 502,507 **** +--- 502,514 ---- + #endif + + /* ++ * +textprop Text properties ++ */ ++ #if defined(FEAT_EVAL) && defined(FEAT_SYN_HL) ++ # define FEAT_TEXT_PROP ++ #endif ++ ++ /* + * +spell spell checking + * + * Disabled for EBCDIC: * Doesn't work (SIGSEGV). +*** ../vim-8.1.0578/src/memline.c 2018-10-30 22:15:51.591158966 +0100 +--- src/memline.c 2018-12-13 20:17:24.645156343 +0100 +*************** +*** 2487,2493 **** + { + bhdr_T *hp; + DATA_BL *dp; +- char_u *ptr; + static int recursive = 0; + + if (lnum > buf->b_ml.ml_line_count) /* invalid line number */ +--- 2487,2492 ---- +*************** +*** 2518,2523 **** +--- 2517,2526 ---- + */ + if (buf->b_ml.ml_line_lnum != lnum || mf_dont_release) + { ++ unsigned start, end; ++ colnr_T len; ++ int idx; ++ + ml_flush_line(buf); + + /* +*************** +*** 2540,2547 **** + + dp = (DATA_BL *)(hp->bh_data); + +! ptr = (char_u *)dp + ((dp->db_index[lnum - buf->b_ml.ml_locked_low]) & DB_INDEX_MASK); +! buf->b_ml.ml_line_ptr = ptr; + buf->b_ml.ml_line_lnum = lnum; + buf->b_ml.ml_flags &= ~ML_LINE_DIRTY; + } +--- 2543,2560 ---- + + dp = (DATA_BL *)(hp->bh_data); + +! idx = lnum - buf->b_ml.ml_locked_low; +! start = ((dp->db_index[idx]) & DB_INDEX_MASK); +! // The text ends where the previous line starts. The first line ends +! // at the end of the block. +! if (idx == 0) +! end = dp->db_txt_end; +! else +! end = ((dp->db_index[idx - 1]) & DB_INDEX_MASK); +! len = end - start; +! +! buf->b_ml.ml_line_ptr = (char_u *)dp + start; +! buf->b_ml.ml_line_len = len; + buf->b_ml.ml_line_lnum = lnum; + buf->b_ml.ml_flags &= ~ML_LINE_DIRTY; + } +*************** +*** 2614,2633 **** + static int + ml_append_int( + buf_T *buf, +! linenr_T lnum, /* append after this line (can be 0) */ +! char_u *line, /* text of the new line */ +! colnr_T len, /* length of line, including NUL, or 0 */ +! int newfile, /* flag, see above */ +! int mark) /* mark the new line */ + { + int i; +! int line_count; /* number of indexes in current block */ + int offset; + int from, to; +! int space_needed; /* space needed for new line */ + int page_size; + int page_count; +! int db_idx; /* index for lnum in data block */ + bhdr_T *hp; + memfile_T *mfp; + DATA_BL *dp; +--- 2627,2647 ---- + static int + ml_append_int( + buf_T *buf, +! linenr_T lnum, // append after this line (can be 0) +! char_u *line, // text of the new line +! colnr_T len_arg, // length of line, including NUL, or 0 +! int newfile, // flag, see above +! int mark) // mark the new line + { ++ colnr_T len = len_arg; // length of line, including NUL, or 0 + int i; +! int line_count; // number of indexes in current block + int offset; + int from, to; +! int space_needed; // space needed for new line + int page_size; + int page_count; +! int db_idx; // index for lnum in data block + bhdr_T *hp; + memfile_T *mfp; + DATA_BL *dp; +*************** +*** 2642,2649 **** + lowest_marked = lnum + 1; + + if (len == 0) +! len = (colnr_T)STRLEN(line) + 1; /* space needed for the text */ +! space_needed = len + INDEX_SIZE; /* space needed for text + index */ + + mfp = buf->b_ml.ml_mfp; + page_size = mfp->mf_page_size; +--- 2656,2663 ---- + lowest_marked = lnum + 1; + + if (len == 0) +! len = (colnr_T)STRLEN(line) + 1; // space needed for the text +! space_needed = len + INDEX_SIZE; // space needed for text + index + + mfp = buf->b_ml.ml_mfp; + page_size = mfp->mf_page_size; +*************** +*** 2728,2734 **** + dp->db_index[i + 1] = dp->db_index[i] - len; + dp->db_index[db_idx + 1] = offset - len; + } +! else /* add line at the end */ + dp->db_index[db_idx + 1] = dp->db_txt_start; + + /* +--- 2742,2749 ---- + dp->db_index[i + 1] = dp->db_index[i] - len; + dp->db_index[db_idx + 1] = offset - len; + } +! else +! // add line at the end (which is the start of the text) + dp->db_index[db_idx + 1] = dp->db_txt_start; + + /* +*************** +*** 3128,3133 **** +--- 3143,3161 ---- + int + ml_replace(linenr_T lnum, char_u *line, int copy) + { ++ colnr_T len = -1; ++ ++ if (line != NULL) ++ len = STRLEN(line); ++ return ml_replace_len(lnum, line, len, copy); ++ } ++ ++ int ++ ml_replace_len(linenr_T lnum, char_u *line_arg, colnr_T len_arg, int copy) ++ { ++ char_u *line = line_arg; ++ colnr_T len = len_arg; ++ + if (line == NULL) /* just checking... */ + return FAIL; + +*************** +*** 3135,3141 **** + if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL, 0) == FAIL) + return FAIL; + +! if (copy && (line = vim_strsave(line)) == NULL) /* allocate memory */ + return FAIL; + #ifdef FEAT_NETBEANS_INTG + if (netbeans_active()) +--- 3163,3169 ---- + if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL, 0) == FAIL) + return FAIL; + +! if (copy && (line = vim_strnsave(line, len)) == NULL) /* allocate memory */ + return FAIL; + #ifdef FEAT_NETBEANS_INTG + if (netbeans_active()) +*************** +*** 3144,3154 **** + netbeans_inserted(curbuf, lnum, 0, line, (int)STRLEN(line)); + } + #endif +! if (curbuf->b_ml.ml_line_lnum != lnum) /* other line buffered */ +! ml_flush_line(curbuf); /* flush it */ +! else if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY) /* same line allocated */ + vim_free(curbuf->b_ml.ml_line_ptr); /* free it */ + curbuf->b_ml.ml_line_ptr = line; + curbuf->b_ml.ml_line_lnum = lnum; + curbuf->b_ml.ml_flags = (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY; + +--- 3172,3219 ---- + netbeans_inserted(curbuf, lnum, 0, line, (int)STRLEN(line)); + } + #endif +! if (curbuf->b_ml.ml_line_lnum != lnum) +! { +! // another line is buffered, flush it +! ml_flush_line(curbuf); +! +! #ifdef FEAT_TEXT_PROP +! curbuf->b_ml.ml_flags &= ~ML_LINE_DIRTY; +! if (has_any_text_properties(curbuf)) +! // Need to fetch the old line to copy over any text properties. +! ml_get_buf(curbuf, lnum, TRUE); +! #endif +! } +! +! #ifdef FEAT_TEXT_PROP +! if (has_any_text_properties(curbuf)) +! { +! size_t oldtextlen = STRLEN(curbuf->b_ml.ml_line_ptr) + 1; +! +! if (oldtextlen < (size_t)curbuf->b_ml.ml_line_len) +! { +! char_u *newline; +! size_t textproplen = curbuf->b_ml.ml_line_len - oldtextlen; +! +! // Need to copy over text properties, stored after the text. +! newline = alloc(len + 1 + textproplen); +! if (newline != NULL) +! { +! mch_memmove(newline, line, len + 1); +! mch_memmove(newline + len + 1, curbuf->b_ml.ml_line_ptr + oldtextlen, textproplen); +! vim_free(line); +! line = newline; +! len += textproplen; +! } +! } +! } +! #endif +! +! if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY) /* same line allocated */ + vim_free(curbuf->b_ml.ml_line_ptr); /* free it */ ++ + curbuf->b_ml.ml_line_ptr = line; ++ curbuf->b_ml.ml_line_len = len + 1; + curbuf->b_ml.ml_line_lnum = lnum; + curbuf->b_ml.ml_flags = (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY; + +*************** +*** 3490,3496 **** + old_len = dp->db_txt_end - start; + else /* text of previous line follows */ + old_len = (dp->db_index[idx - 1] & DB_INDEX_MASK) - start; +! new_len = (colnr_T)STRLEN(new_line) + 1; + extra = new_len - old_len; /* negative if lines gets smaller */ + + /* +--- 3555,3561 ---- + old_len = dp->db_txt_end - start; + else /* text of previous line follows */ + old_len = (dp->db_index[idx - 1] & DB_INDEX_MASK) - start; +! new_len = buf->b_ml.ml_line_len; + extra = new_len - old_len; /* negative if lines gets smaller */ + + /* +*************** +*** 5009,5016 **** + */ + buf->b_ml.ml_usedchunks = 1; + buf->b_ml.ml_chunksize[0].mlcs_numlines = 1; +! buf->b_ml.ml_chunksize[0].mlcs_totalsize = +! (long)STRLEN(buf->b_ml.ml_line_ptr) + 1; + return; + } + +--- 5074,5080 ---- + */ + buf->b_ml.ml_usedchunks = 1; + buf->b_ml.ml_chunksize[0].mlcs_numlines = 1; +! buf->b_ml.ml_chunksize[0].mlcs_totalsize = (long)buf->b_ml.ml_line_len; + return; + } + +*** ../vim-8.1.0578/src/misc1.c 2018-12-09 15:00:47.985798600 +0100 +--- src/misc1.c 2018-12-13 20:18:19.228829748 +0100 +*************** +*** 2631,2639 **** + { + char_u *oldp, *newp; + colnr_T oldlen; + linenr_T lnum = curwin->w_cursor.lnum; + colnr_T col = curwin->w_cursor.col; +! int was_alloced; + long movelen; + int fixpos = fixpos_arg; + +--- 2631,2640 ---- + { + char_u *oldp, *newp; + colnr_T oldlen; ++ colnr_T newlen; + linenr_T lnum = curwin->w_cursor.lnum; + colnr_T col = curwin->w_cursor.col; +! int alloc_newp; + long movelen; + int fixpos = fixpos_arg; + +*************** +*** 2710,2715 **** +--- 2711,2717 ---- + count = oldlen - col; + movelen = 1; + } ++ newlen = oldlen - count; + + /* + * If the old line has been allocated the deletion can be done in the +*************** +*** 2720,2743 **** + */ + #ifdef FEAT_NETBEANS_INTG + if (netbeans_active()) +! was_alloced = FALSE; + else + #endif +! was_alloced = ml_line_alloced(); /* check if oldp was allocated */ +! if (was_alloced) +! newp = oldp; /* use same allocated memory */ + else +! { /* need to allocate a new line */ +! newp = alloc((unsigned)(oldlen + 1 - count)); + if (newp == NULL) + return FAIL; + mch_memmove(newp, oldp, (size_t)col); + } + mch_memmove(newp + col, oldp + col + count, (size_t)movelen); +! if (!was_alloced) + ml_replace(lnum, newp, FALSE); + +! /* mark the buffer as changed and prepare for displaying */ + changed_bytes(lnum, curwin->w_cursor.col); + + return OK; +--- 2722,2755 ---- + */ + #ifdef FEAT_NETBEANS_INTG + if (netbeans_active()) +! alloc_newp = TRUE; + else + #endif +! alloc_newp = !ml_line_alloced(); // check if oldp was allocated +! if (!alloc_newp) +! newp = oldp; // use same allocated memory + else +! { // need to allocate a new line +! newp = alloc((unsigned)(newlen + 1)); + if (newp == NULL) + return FAIL; + mch_memmove(newp, oldp, (size_t)col); + } + mch_memmove(newp + col, oldp + col + count, (size_t)movelen); +! if (alloc_newp) + ml_replace(lnum, newp, FALSE); ++ #ifdef FEAT_TEXT_PROP ++ else ++ { ++ // Also move any following text properties. ++ if (oldlen + 1 < curbuf->b_ml.ml_line_len) ++ mch_memmove(newp + newlen + 1, oldp + oldlen + 1, ++ (size_t)curbuf->b_ml.ml_line_len - oldlen - 1); ++ curbuf->b_ml.ml_line_len -= count; ++ } ++ #endif + +! // mark the buffer as changed and prepare for displaying + changed_bytes(lnum, curwin->w_cursor.col); + + return OK; +*** ../vim-8.1.0578/src/misc2.c 2018-11-11 15:20:32.436704418 +0100 +--- src/misc2.c 2018-12-13 20:19:36.988360977 +0100 +*************** +*** 1191,1196 **** +--- 1191,1199 ---- + # ifdef FEAT_CMDHIST + init_history(); + # endif ++ #ifdef FEAT_TEXT_PROP ++ clear_global_prop_types(); ++ #endif + + #ifdef FEAT_QUICKFIX + { +*** ../vim-8.1.0578/src/proto.h 2018-07-01 16:43:59.850736541 +0200 +--- src/proto.h 2018-12-13 20:19:51.208274841 +0100 +*************** +*** 183,188 **** +--- 183,191 ---- + # if defined(HAVE_TGETENT) && (defined(AMIGA) || defined(VMS)) + # include "termlib.pro" + # endif ++ # ifdef FEAT_TEXT_PROP ++ # include "textprop.pro" ++ # endif + # include "ui.pro" + # include "undo.pro" + # include "userfunc.pro" +*** ../vim-8.1.0578/src/proto/memline.pro 2018-08-21 20:28:49.888006612 +0200 +--- src/proto/memline.pro 2018-12-13 20:20:02.860204177 +0100 +*************** +*** 24,29 **** +--- 24,30 ---- + int ml_append(linenr_T lnum, char_u *line, colnr_T len, int newfile); + int ml_append_buf(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, int newfile); + int ml_replace(linenr_T lnum, char_u *line, int copy); ++ int ml_replace_len(linenr_T lnum, char_u *line_arg, colnr_T len_arg, int copy); + int ml_delete(linenr_T lnum, int message); + void ml_setmarked(linenr_T lnum); + linenr_T ml_firstmarked(void); +*** ../vim-8.1.0578/src/proto/textprop.pro 2018-12-13 22:11:44.012590783 +0100 +--- src/proto/textprop.pro 2018-12-13 20:25:39.330136512 +0100 +*************** +*** 0 **** +--- 1,17 ---- ++ /* textprop.c */ ++ void f_prop_add(typval_T *argvars, typval_T *rettv); ++ int has_any_text_properties(buf_T *buf); ++ int get_text_props(buf_T *buf, linenr_T lnum, char_u **props, int will_change); ++ proptype_T *text_prop_type_by_id(buf_T *buf, int id); ++ void f_prop_clear(typval_T *argvars, typval_T *rettv); ++ void f_prop_list(typval_T *argvars, typval_T *rettv); ++ void f_prop_remove(typval_T *argvars, typval_T *rettv); ++ void prop_type_set(typval_T *argvars, int add); ++ void f_prop_type_add(typval_T *argvars, typval_T *rettv); ++ void f_prop_type_change(typval_T *argvars, typval_T *rettv); ++ void f_prop_type_delete(typval_T *argvars, typval_T *rettv); ++ void f_prop_type_get(typval_T *argvars, typval_T *rettv); ++ void f_prop_type_list(typval_T *argvars, typval_T *rettv); ++ void clear_global_prop_types(void); ++ void clear_buf_prop_types(buf_T *buf); ++ /* vim: set ft=c : */ +*** ../vim-8.1.0578/src/screen.c 2018-11-16 16:21:01.633310065 +0100 +--- src/screen.c 2018-12-13 20:20:43.287958416 +0100 +*************** +*** 3128,3133 **** +--- 3128,3142 ---- + int draw_color_col = FALSE; /* highlight colorcolumn */ + int *color_cols = NULL; /* pointer to according columns array */ + #endif ++ #ifdef FEAT_TEXT_PROP ++ int text_prop_count; ++ int text_prop_next = 0; // next text property to use ++ textprop_T *text_props = NULL; ++ int *text_prop_idxs = NULL; ++ int text_props_active = 0; ++ proptype_T *text_prop_type = NULL; ++ int text_prop_attr = 0; ++ #endif + #ifdef FEAT_SPELL + int has_spell = FALSE; /* this buffer has spell checking */ + # define SPWORDLEN 150 +*************** +*** 3144,3150 **** + static linenr_T capcol_lnum = 0; /* line number where "cap_col" used */ + int cur_checked_col = 0; /* checked column for current line */ + #endif +! int extra_check = 0; // has syntax or linebreak + #ifdef FEAT_MBYTE + int multi_attr = 0; /* attributes desired by multibyte */ + int mb_l = 1; /* multi-byte byte length */ +--- 3153,3159 ---- + static linenr_T capcol_lnum = 0; /* line number where "cap_col" used */ + int cur_checked_col = 0; /* checked column for current line */ + #endif +! int extra_check = 0; // has extra highlighting + #ifdef FEAT_MBYTE + int multi_attr = 0; /* attributes desired by multibyte */ + int mb_l = 1; /* multi-byte byte length */ +*************** +*** 3784,3789 **** +--- 3793,3822 ---- + } + #endif + ++ #ifdef FEAT_TEXT_PROP ++ { ++ char_u *prop_start; ++ ++ text_prop_count = get_text_props(wp->w_buffer, lnum, ++ &prop_start, FALSE); ++ if (text_prop_count > 0) ++ { ++ // Make a copy of the properties, so that they are properly ++ // aligned. ++ text_props = (textprop_T *)alloc( ++ text_prop_count * sizeof(textprop_T)); ++ if (text_props != NULL) ++ mch_memmove(text_props, prop_start, ++ text_prop_count * sizeof(textprop_T)); ++ ++ // Allocate an array for the indexes. ++ text_prop_idxs = (int *)alloc(text_prop_count * sizeof(int)); ++ area_highlighting = TRUE; ++ extra_check = TRUE; ++ } ++ } ++ #endif ++ + off = (unsigned)(current_ScreenLine - ScreenLines); + col = 0; + #ifdef FEAT_RIGHTLEFT +*************** +*** 4283,4288 **** +--- 4316,4326 ---- + else + { + attr_pri = FALSE; ++ #ifdef FEAT_TEXT_PROP ++ if (text_prop_type != NULL) ++ char_attr = text_prop_attr; ++ else ++ #endif + #ifdef FEAT_SYN_HL + if (has_syntax) + char_attr = syntax_attr; +*************** +*** 4663,4668 **** +--- 4701,4766 ---- + } + #endif + ++ #ifdef FEAT_TEXT_PROP ++ if (text_props != NULL) ++ { ++ int pi; ++ ++ // Check if any active property ends. ++ for (pi = 0; pi < text_props_active; ++pi) ++ { ++ int tpi = text_prop_idxs[pi]; ++ ++ if (col >= text_props[tpi].tp_col - 1 ++ + text_props[tpi].tp_len) ++ { ++ if (pi + 1 < text_props_active) ++ mch_memmove(text_prop_idxs + pi, ++ text_prop_idxs + pi + 1, ++ sizeof(int) ++ * (text_props_active - (pi + 1))); ++ --text_props_active; ++ --pi; ++ } ++ } ++ ++ // Add any text property that starts in this column. ++ while (text_prop_next < text_prop_count ++ && col >= text_props[text_prop_next].tp_col - 1) ++ text_prop_idxs[text_props_active++] = text_prop_next++; ++ ++ text_prop_type = NULL; ++ if (text_props_active > 0) ++ { ++ int max_priority = INT_MIN; ++ int max_col = 0; ++ ++ // Get the property type with the highest priority ++ // and/or starting last. ++ for (pi = 0; pi < text_props_active; ++pi) ++ { ++ int tpi = text_prop_idxs[pi]; ++ proptype_T *pt; ++ ++ pt = text_prop_type_by_id( ++ curwin->w_buffer, text_props[tpi].tp_type); ++ if (pt != NULL ++ && (pt->pt_priority > max_priority ++ || (pt->pt_priority == max_priority ++ && text_props[tpi].tp_col >= max_col))) ++ { ++ text_prop_type = pt; ++ max_priority = pt->pt_priority; ++ max_col = text_props[tpi].tp_col; ++ } ++ } ++ if (text_prop_type != NULL) ++ text_prop_attr = ++ syn_id2attr(text_prop_type->pt_hl_id); ++ } ++ } ++ #endif ++ + #ifdef FEAT_SPELL + /* Check spelling (unless at the end of the line). + * Only do this when there is no syntax highlighting, the +*************** +*** 6025,6030 **** +--- 6123,6132 ---- + cap_col = 0; + } + #endif ++ #ifdef FEAT_TEXT_PROP ++ vim_free(text_props); ++ vim_free(text_prop_idxs); ++ #endif + + vim_free(p_extra_free); + return row; +*** ../vim-8.1.0578/src/structs.h 2018-11-10 17:33:23.087518814 +0100 +--- src/structs.h 2018-12-13 20:21:41.959600249 +0100 +*************** +*** 684,689 **** +--- 684,690 ---- + + linenr_T ml_line_lnum; /* line number of cached line, 0 if not valid */ + char_u *ml_line_ptr; /* pointer to cached line */ ++ colnr_T ml_line_len; /* length of the cached line, including NUL */ + + bhdr_T *ml_locked; /* block used by last ml_get */ + linenr_T ml_locked_low; /* first line in ml_locked */ +*************** +*** 696,701 **** +--- 697,737 ---- + #endif + } memline_T; + ++ ++ /* ++ * Structure defining text properties. These stick with the text. ++ * When stored in memline they are after the text, ml_line_len is larger than ++ * STRLEN(ml_line_ptr) + 1. ++ */ ++ typedef struct textprop_S ++ { ++ colnr_T tp_col; // start column ++ colnr_T tp_len; // length in bytes ++ int tp_id; // identifier ++ int tp_type; // property type ++ int tp_flags; // TP_FLAG_ values ++ } textprop_T; ++ ++ #define TP_FLAG_CONT_NEXT 1 // property continues in next line ++ #define TP_FLAG_CONT_PREV 2 // property was continued from prev line ++ ++ /* ++ * Structure defining a property type. ++ */ ++ typedef struct proptype_S ++ { ++ int pt_id; // value used for tp_id ++ int pt_type; // number used for tp_type ++ int pt_hl_id; // highlighting ++ int pt_priority; // priority ++ int pt_flags; // PT_FLAG_ values ++ char_u pt_name[1]; // property type name, actually longer ++ } proptype_T; ++ ++ #define PT_FLAG_INS_START_INCL 1 // insert at start included in property ++ #define PT_FLAG_INS_END_INCL 2 // insert at end included in property ++ ++ + #if defined(FEAT_SIGNS) || defined(PROTO) + typedef struct signlist signlist_T; + +*************** +*** 2358,2363 **** +--- 2394,2402 ---- + dictitem_T b_bufvar; /* variable for "b:" Dictionary */ + dict_T *b_vars; /* internal variables, local to buffer */ + #endif ++ #ifdef FEAT_TEXT_PROP ++ hashtab_T *b_proptypes; /* text property types local to buffer */ ++ #endif + + #if defined(FEAT_BEVAL) && defined(FEAT_EVAL) + char_u *b_p_bexpr; /* 'balloonexpr' local value */ +*** ../vim-8.1.0578/src/testdir/Make_all.mak 2018-11-30 22:40:09.098211991 +0100 +--- src/testdir/Make_all.mak 2018-12-13 20:22:10.699424209 +0100 +*************** +*** 177,182 **** +--- 177,183 ---- + test_terminal_fail.res \ + test_textformat.res \ + test_textobjects.res \ ++ test_textprop.res \ + test_undo.res \ + test_user_func.res \ + test_usercommands.res \ +*** ../vim-8.1.0578/src/testdir/test_textprop.vim 2018-12-13 22:12:34.396222668 +0100 +--- src/testdir/test_textprop.vim 2018-12-13 22:05:57.999204140 +0100 +*************** +*** 0 **** +--- 1,200 ---- ++ " Tests for defining text property types and adding text properties to the ++ " buffer. ++ ++ if !has('textprop') ++ finish ++ endif ++ ++ func Test_proptype_global() ++ call prop_type_add('comment', {'highlight': 'Directory', 'priority': 123, 'start_incl': 1, 'end_incl': 1}) ++ let proptypes = prop_type_list() ++ call assert_equal(1, len(proptypes)) ++ call assert_equal('comment', proptypes[0]) ++ ++ let proptype = prop_type_get('comment') ++ call assert_equal('Directory', proptype['highlight']) ++ call assert_equal(123, proptype['priority']) ++ call assert_equal(1, proptype['start_incl']) ++ call assert_equal(1, proptype['end_incl']) ++ ++ call prop_type_delete('comment') ++ call assert_equal(0, len(prop_type_list())) ++ ++ call prop_type_add('one', {}) ++ call assert_equal(1, len(prop_type_list())) ++ let proptype = prop_type_get('one') ++ call assert_false(has_key(proptype, 'highlight')) ++ call assert_equal(0, proptype['priority']) ++ call assert_equal(0, proptype['start_incl']) ++ call assert_equal(0, proptype['end_incl']) ++ ++ call prop_type_add('two', {}) ++ call assert_equal(2, len(prop_type_list())) ++ call prop_type_delete('one') ++ call assert_equal(1, len(prop_type_list())) ++ call prop_type_delete('two') ++ call assert_equal(0, len(prop_type_list())) ++ endfunc ++ ++ func Test_proptype_buf() ++ let bufnr = bufnr('') ++ call prop_type_add('comment', {'bufnr': bufnr, 'highlight': 'Directory', 'priority': 123, 'start_incl': 1, 'end_incl': 1}) ++ let proptypes = prop_type_list({'bufnr': bufnr}) ++ call assert_equal(1, len(proptypes)) ++ call assert_equal('comment', proptypes[0]) ++ ++ let proptype = prop_type_get('comment', {'bufnr': bufnr}) ++ call assert_equal('Directory', proptype['highlight']) ++ call assert_equal(123, proptype['priority']) ++ call assert_equal(1, proptype['start_incl']) ++ call assert_equal(1, proptype['end_incl']) ++ ++ call prop_type_delete('comment', {'bufnr': bufnr}) ++ call assert_equal(0, len(prop_type_list({'bufnr': bufnr}))) ++ ++ call prop_type_add('one', {'bufnr': bufnr}) ++ let proptype = prop_type_get('one', {'bufnr': bufnr}) ++ call assert_false(has_key(proptype, 'highlight')) ++ call assert_equal(0, proptype['priority']) ++ call assert_equal(0, proptype['start_incl']) ++ call assert_equal(0, proptype['end_incl']) ++ ++ call prop_type_add('two', {'bufnr': bufnr}) ++ call assert_equal(2, len(prop_type_list({'bufnr': bufnr}))) ++ call prop_type_delete('one', {'bufnr': bufnr}) ++ call assert_equal(1, len(prop_type_list({'bufnr': bufnr}))) ++ call prop_type_delete('two', {'bufnr': bufnr}) ++ call assert_equal(0, len(prop_type_list({'bufnr': bufnr}))) ++ endfunc ++ ++ func AddPropTypes() ++ call prop_type_add('one', {}) ++ call prop_type_add('two', {}) ++ call prop_type_add('three', {}) ++ call prop_type_add('whole', {}) ++ endfunc ++ ++ func DeletePropTypes() ++ call prop_type_delete('one') ++ call prop_type_delete('two') ++ call prop_type_delete('three') ++ call prop_type_delete('whole') ++ endfunc ++ ++ func SetupPropsInFirstLine() ++ call setline(1, 'one two three') ++ call prop_add(1, 1, {'length': 3, 'id': 11, 'type': 'one'}) ++ call prop_add(1, 5, {'length': 3, 'id': 12, 'type': 'two'}) ++ call prop_add(1, 8, {'length': 5, 'id': 13, 'type': 'three'}) ++ call prop_add(1, 1, {'length': 13, 'id': 14, 'type': 'whole'}) ++ endfunc ++ ++ let s:expected_props = [{'col': 1, 'length': 13, 'id': 14, 'type': 'whole', 'start': 1, 'end': 1}, ++ \ {'col': 1, 'length': 3, 'id': 11, 'type': 'one', 'start': 1, 'end': 1}, ++ \ {'col': 5, 'length': 3, 'id': 12, 'type': 'two', 'start': 1, 'end': 1}, ++ \ {'col': 8, 'length': 5, 'id': 13, 'type': 'three', 'start': 1, 'end': 1}, ++ \ ] ++ ++ func Test_prop_add() ++ new ++ call AddPropTypes() ++ call SetupPropsInFirstLine() ++ call assert_equal(s:expected_props, prop_list(1)) ++ call assert_fails("call prop_add(10, 1, {'length': 1, 'id': 14, 'type': 'whole'})", 'E966:') ++ call assert_fails("call prop_add(1, 22, {'length': 1, 'id': 14, 'type': 'whole'})", 'E964:') ++ ++ " Insert a line above, text props must still be there. ++ call append(0, 'empty') ++ call assert_equal(s:expected_props, prop_list(2)) ++ " Delete a line above, text props must still be there. ++ 1del ++ call assert_equal(s:expected_props, prop_list(1)) ++ ++ call DeletePropTypes() ++ bwipe! ++ endfunc ++ ++ func Test_prop_remove() ++ new ++ call AddPropTypes() ++ call SetupPropsInFirstLine() ++ let props = deepcopy(s:expected_props) ++ call assert_equal(props, prop_list(1)) ++ ++ " remove by id ++ call prop_remove({'id': 12}, 1) ++ unlet props[2] ++ call assert_equal(props, prop_list(1)) ++ ++ " remove by type ++ call prop_remove({'type': 'one'}, 1) ++ unlet props[1] ++ call assert_equal(props, prop_list(1)) ++ ++ call DeletePropTypes() ++ bwipe! ++ endfunc ++ ++ func Test_prop_add_remove_buf() ++ new ++ let bufnr = bufnr('') ++ call AddPropTypes() ++ call setline(1, 'one two three') ++ wincmd w ++ call prop_add(1, 1, {'length': 3, 'id': 11, 'type': 'one', 'bufnr': bufnr}) ++ call prop_add(1, 5, {'length': 3, 'id': 12, 'type': 'two', 'bufnr': bufnr}) ++ call prop_add(1, 11, {'length': 3, 'id': 13, 'type': 'three', 'bufnr': bufnr}) ++ ++ let props = [ ++ \ {'col': 1, 'length': 3, 'id': 11, 'type': 'one', 'start': 1, 'end': 1}, ++ \ {'col': 5, 'length': 3, 'id': 12, 'type': 'two', 'start': 1, 'end': 1}, ++ \ {'col': 11, 'length': 3, 'id': 13, 'type': 'three', 'start': 1, 'end': 1}, ++ \] ++ call assert_equal(props, prop_list(1, {'bufnr': bufnr})) ++ ++ " remove by id ++ call prop_remove({'id': 12, 'bufnr': bufnr}, 1) ++ unlet props[1] ++ call assert_equal(props, prop_list(1, {'bufnr': bufnr})) ++ ++ " remove by type ++ call prop_remove({'type': 'one', 'bufnr': bufnr}, 1) ++ unlet props[0] ++ call assert_equal(props, prop_list(1, {'bufnr': bufnr})) ++ ++ call DeletePropTypes() ++ wincmd w ++ bwipe! ++ endfunc ++ ++ ++ func Test_prop_clear() ++ new ++ call AddPropTypes() ++ call SetupPropsInFirstLine() ++ call assert_equal(s:expected_props, prop_list(1)) ++ ++ call prop_clear(1) ++ call assert_equal([], prop_list(1)) ++ ++ call DeletePropTypes() ++ bwipe! ++ endfunc ++ ++ func Test_prop_clear_buf() ++ new ++ call AddPropTypes() ++ call SetupPropsInFirstLine() ++ let bufnr = bufnr('') ++ wincmd w ++ call assert_equal(s:expected_props, prop_list(1, {'bufnr': bufnr})) ++ ++ call prop_clear(1, 1, {'bufnr': bufnr}) ++ call assert_equal([], prop_list(1, {'bufnr': bufnr})) ++ ++ wincmd w ++ call DeletePropTypes() ++ bwipe! ++ endfunc ++ ++ " TODO: screenshot test with highlighting +*** ../vim-8.1.0578/src/textprop.c 2018-12-13 22:12:34.400222638 +0100 +--- src/textprop.c 2018-12-13 22:08:34.554000272 +0100 +*************** +*** 0 **** +--- 1,869 ---- ++ /* 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. ++ * ++ * Text properties are attached to the text. They move with the text when ++ * text is inserted/deleted. ++ * ++ * Text properties have a user specified ID number, which can be unique. ++ * Text properties have a type, which can be used to specify highlighting. ++ * ++ * TODO: ++ * - Add an arrray for global_proptypes, to quickly lookup a proptype by ID ++ * - Add an arrray for b_proptypes, to quickly lookup a proptype by ID ++ * - adjust property column when text is inserted/deleted ++ * - support properties that continue over a line break ++ * - add mechanism to keep track of changed lines. ++ */ ++ ++ #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"); ++ ++ /* ++ * 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) ++ EMSG2(_(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->vval.v_dict == NULL) ++ return OK; // NULL dict is like an empty dict ++ di = dict_find(arg->vval.v_dict, (char_u *)"bufnr", -1); ++ if (di != NULL) ++ { ++ *buf = get_buf_tv(&di->di_tv, FALSE); ++ if (*buf == NULL) ++ return FAIL; ++ } ++ return OK; ++ } ++ ++ /* ++ * prop_add({lnum}, {col}, {props}) ++ */ ++ void ++ f_prop_add(typval_T *argvars, typval_T *rettv UNUSED) ++ { ++ linenr_T lnum; ++ colnr_T col; ++ dict_T *dict; ++ colnr_T length = 1; ++ char_u *type_name; ++ proptype_T *type; ++ buf_T *buf = curbuf; ++ int id = 0; ++ char_u *newtext; ++ int proplen; ++ size_t textlen; ++ char_u *props; ++ char_u *newprops; ++ static textprop_T tmp_prop; // static to get it aligned. ++ int i; ++ ++ lnum = get_tv_number(&argvars[0]); ++ col = get_tv_number(&argvars[1]); ++ if (col < 1) ++ { ++ EMSGN(_(e_invalid_col), (long)col); ++ return; ++ } ++ if (argvars[2].v_type != VAR_DICT) ++ { ++ EMSG(_(e_dictreq)); ++ return; ++ } ++ dict = argvars[2].vval.v_dict; ++ ++ if (dict == NULL || dict_find(dict, (char_u *)"type", -1) == NULL) ++ { ++ EMSG(_("E965: missing property type name")); ++ return; ++ } ++ type_name = get_dict_string(dict, (char_u *)"type", FALSE); ++ ++ if (dict_find(dict, (char_u *)"end_lnum", -1) != NULL) ++ { ++ // TODO: handle end_lnum ++ EMSG("Sorry, end_lnum not supported yet"); ++ return; ++ } ++ ++ if (dict_find(dict, (char_u *)"length", -1) != NULL) ++ length = get_dict_number(dict, (char_u *)"length"); ++ else if (dict_find(dict, (char_u *)"end_col", -1) != NULL) ++ { ++ length = get_dict_number(dict, (char_u *)"end_col") - col; ++ if (length <= 0) ++ { ++ EMSG2(_(e_invargval), "end_col"); ++ return; ++ } ++ } ++ ++ if (dict_find(dict, (char_u *)"id", -1) != NULL) ++ id = get_dict_number(dict, (char_u *)"id"); ++ ++ if (get_bufnr_from_arg(&argvars[2], &buf) == FAIL) ++ return; ++ ++ type = lookup_prop_type(type_name, buf); ++ if (type == NULL) ++ return; ++ ++ if (lnum < 1 || lnum > buf->b_ml.ml_line_count) ++ { ++ EMSGN(_("E966: Invalid line number: %ld"), (long)lnum); ++ return; ++ } ++ ++ // Fetch the line to get the ml_line_len field updated. ++ proplen = get_text_props(buf, lnum, &props, TRUE); ++ ++ if (col >= (colnr_T)STRLEN(buf->b_ml.ml_line_ptr)) ++ { ++ EMSGN(_(e_invalid_col), (long)col); ++ return; ++ } ++ ++ // Allocate the new line with space for the new proprety. ++ newtext = alloc(buf->b_ml.ml_line_len + sizeof(textprop_T)); ++ if (newtext == NULL) ++ return; ++ // Copy the text, including terminating NUL. ++ textlen = buf->b_ml.ml_line_len - proplen * sizeof(textprop_T); ++ mch_memmove(newtext, buf->b_ml.ml_line_ptr, textlen); ++ ++ // Find the index where to insert the new property. ++ // Since the text properties are not aligned properly when stored with the ++ // text, we need to copy them as bytes before using it as a struct. ++ for (i = 0; i < proplen; ++i) ++ { ++ mch_memmove(&tmp_prop, props + i * sizeof(proptype_T), ++ sizeof(proptype_T)); ++ if (tmp_prop.tp_col >= col) ++ break; ++ } ++ newprops = newtext + textlen; ++ if (i > 0) ++ mch_memmove(newprops, props, sizeof(textprop_T) * i); ++ ++ tmp_prop.tp_col = col; ++ tmp_prop.tp_len = length; ++ tmp_prop.tp_id = id; ++ tmp_prop.tp_type = type->pt_id; ++ tmp_prop.tp_flags = 0; ++ mch_memmove(newprops + i * sizeof(textprop_T), &tmp_prop, ++ sizeof(textprop_T)); ++ ++ if (i < proplen) ++ mch_memmove(newprops + (i + 1) * sizeof(textprop_T), ++ props + i * sizeof(textprop_T), ++ sizeof(textprop_T) * (proplen - i)); ++ ++ if (buf->b_ml.ml_flags & ML_LINE_DIRTY) ++ vim_free(buf->b_ml.ml_line_ptr); ++ buf->b_ml.ml_line_ptr = newtext; ++ buf->b_ml.ml_line_len += sizeof(textprop_T); ++ buf->b_ml.ml_flags |= ML_LINE_DIRTY; ++ ++ redraw_buf_later(buf, NOT_VALID); ++ } ++ ++ /* ++ * Return TRUE if any text properties are defined globally or for buffer ++ * 'buf". ++ */ ++ int ++ has_any_text_properties(buf_T *buf) ++ { ++ return buf->b_proptypes != NULL || global_proptypes != NULL; ++ } ++ ++ /* ++ * Fetch the text properties for line "lnum" in buffer 'buf". ++ * Returns the number of text properties and, when non-zero, a pointer to the ++ * first one in "props" (note that it is not aligned, therefore the char_u ++ * pointer). ++ */ ++ int ++ get_text_props(buf_T *buf, linenr_T lnum, char_u **props, int will_change) ++ { ++ char_u *text; ++ size_t textlen; ++ size_t proplen; ++ ++ // Be quick when no text property types are defined. ++ if (!has_any_text_properties(buf)) ++ return 0; ++ ++ // Fetch the line to get the ml_line_len field updated. ++ text = ml_get_buf(buf, lnum, will_change); ++ textlen = STRLEN(text) + 1; ++ proplen = buf->b_ml.ml_line_len - textlen; ++ if (proplen % sizeof(textprop_T) != 0) ++ { ++ IEMSG(_("E967: text property info corrupted")); ++ return 0; ++ } ++ if (proplen > 0) ++ *props = text + textlen; ++ return proplen / sizeof(textprop_T); ++ } ++ ++ static proptype_T * ++ find_type_by_id(hashtab_T *ht, int id) ++ { ++ long todo; ++ hashitem_T *hi; ++ ++ if (ht == NULL) ++ return NULL; ++ ++ // TODO: Make this faster by keeping a list of types sorted on ID and use ++ // a binary search. ++ ++ todo = (long)ht->ht_used; ++ for (hi = ht->ht_array; todo > 0; ++hi) ++ { ++ if (!HASHITEM_EMPTY(hi)) ++ { ++ proptype_T *prop = HI2PT(hi); ++ ++ if (prop->pt_id == id) ++ return prop; ++ --todo; ++ } ++ } ++ return NULL; ++ } ++ ++ /* ++ * Find a property type by ID in "buf" or globally. ++ * Returns NULL if not found. ++ */ ++ proptype_T * ++ text_prop_type_by_id(buf_T *buf, int id) ++ { ++ proptype_T *type; ++ ++ type = find_type_by_id(buf->b_proptypes, id); ++ if (type == NULL) ++ type = find_type_by_id(global_proptypes, id); ++ return type; ++ } ++ ++ /* ++ * prop_clear({lnum} [, {lnum_end} [, {bufnr}]]) ++ */ ++ void ++ f_prop_clear(typval_T *argvars, typval_T *rettv UNUSED) ++ { ++ linenr_T start = get_tv_number(&argvars[0]); ++ linenr_T end = start; ++ linenr_T lnum; ++ buf_T *buf = curbuf; ++ ++ if (argvars[1].v_type != VAR_UNKNOWN) ++ { ++ end = get_tv_number(&argvars[1]); ++ if (argvars[2].v_type != VAR_UNKNOWN) ++ { ++ if (get_bufnr_from_arg(&argvars[2], &buf) == FAIL) ++ return; ++ } ++ } ++ if (start < 1 || end < 1) ++ { ++ EMSG(_(e_invrange)); ++ return; ++ } ++ ++ for (lnum = start; lnum <= end; ++lnum) ++ { ++ char_u *text; ++ size_t len; ++ ++ if (lnum > buf->b_ml.ml_line_count) ++ break; ++ text = ml_get_buf(buf, lnum, FALSE); ++ len = STRLEN(text) + 1; ++ if ((size_t)buf->b_ml.ml_line_len > len) ++ { ++ if (!(buf->b_ml.ml_flags & ML_LINE_DIRTY)) ++ { ++ char_u *newtext = vim_strsave(text); ++ ++ // need to allocate the line now ++ if (newtext == NULL) ++ return; ++ buf->b_ml.ml_line_ptr = newtext; ++ buf->b_ml.ml_flags |= ML_LINE_DIRTY; ++ } ++ buf->b_ml.ml_line_len = len; ++ } ++ } ++ redraw_buf_later(buf, NOT_VALID); ++ } ++ ++ /* ++ * prop_list({lnum} [, {bufnr}]) ++ */ ++ void ++ f_prop_list(typval_T *argvars, typval_T *rettv) ++ { ++ linenr_T lnum = get_tv_number(&argvars[0]); ++ buf_T *buf = curbuf; ++ ++ if (argvars[1].v_type != VAR_UNKNOWN) ++ { ++ if (get_bufnr_from_arg(&argvars[1], &buf) == FAIL) ++ return; ++ } ++ if (lnum < 1 || lnum > buf->b_ml.ml_line_count) ++ { ++ EMSG(_(e_invrange)); ++ return; ++ } ++ ++ if (rettv_list_alloc(rettv) == OK) ++ { ++ char_u *text = ml_get_buf(buf, lnum, FALSE); ++ size_t textlen = STRLEN(text) + 1; ++ int count = (buf->b_ml.ml_line_len - textlen) ++ / sizeof(textprop_T); ++ int i; ++ textprop_T prop; ++ proptype_T *pt; ++ ++ for (i = 0; i < count; ++i) ++ { ++ dict_T *d = dict_alloc(); ++ ++ if (d == NULL) ++ break; ++ mch_memmove(&prop, text + textlen + i * sizeof(textprop_T), ++ sizeof(textprop_T)); ++ dict_add_number(d, "col", prop.tp_col); ++ dict_add_number(d, "length", prop.tp_len); ++ dict_add_number(d, "id", prop.tp_id); ++ dict_add_number(d, "start", !(prop.tp_flags & TP_FLAG_CONT_PREV)); ++ dict_add_number(d, "end", !(prop.tp_flags & TP_FLAG_CONT_NEXT)); ++ pt = text_prop_type_by_id(buf, prop.tp_type); ++ if (pt != NULL) ++ dict_add_string(d, "type", pt->pt_name); ++ ++ list_append_dict(rettv->vval.v_list, d); ++ } ++ } ++ } ++ ++ /* ++ * prop_remove({props} [, {lnum} [, {lnum_end}]]) ++ */ ++ void ++ f_prop_remove(typval_T *argvars, typval_T *rettv) ++ { ++ linenr_T start = 1; ++ linenr_T end = 0; ++ linenr_T lnum; ++ dict_T *dict; ++ buf_T *buf = curbuf; ++ dictitem_T *di; ++ int do_all = FALSE; ++ int id = -1; ++ int type_id = -1; ++ ++ rettv->vval.v_number = 0; ++ if (argvars[0].v_type != VAR_DICT || argvars[0].vval.v_dict == NULL) ++ { ++ EMSG(_(e_invarg)); ++ return; ++ } ++ ++ if (argvars[1].v_type != VAR_UNKNOWN) ++ { ++ start = get_tv_number(&argvars[1]); ++ end = start; ++ if (argvars[2].v_type != VAR_UNKNOWN) ++ end = get_tv_number(&argvars[2]); ++ if (start < 1 || end < 1) ++ { ++ EMSG(_(e_invrange)); ++ return; ++ } ++ } ++ ++ dict = argvars[0].vval.v_dict; ++ di = dict_find(dict, (char_u *)"bufnr", -1); ++ if (di != NULL) ++ { ++ buf = get_buf_tv(&di->di_tv, FALSE); ++ if (buf == NULL) ++ return; ++ } ++ ++ di = dict_find(dict, (char_u*)"all", -1); ++ if (di != NULL) ++ do_all = get_dict_number(dict, (char_u *)"all"); ++ ++ if (dict_find(dict, (char_u *)"id", -1) != NULL) ++ id = get_dict_number(dict, (char_u *)"id"); ++ if (dict_find(dict, (char_u *)"type", -1)) ++ { ++ char_u *name = get_dict_string(dict, (char_u *)"type", FALSE); ++ proptype_T *type = lookup_prop_type(name, buf); ++ ++ if (type == NULL) ++ return; ++ type_id = type->pt_id; ++ } ++ if (id == -1 && type_id == -1) ++ { ++ EMSG(_("E968: Need at least one of 'id' or 'type'")); ++ return; ++ } ++ ++ if (end == 0) ++ end = buf->b_ml.ml_line_count; ++ for (lnum = start; lnum <= end; ++lnum) ++ { ++ char_u *text; ++ size_t len; ++ ++ if (lnum > buf->b_ml.ml_line_count) ++ break; ++ text = ml_get_buf(buf, lnum, FALSE); ++ len = STRLEN(text) + 1; ++ if ((size_t)buf->b_ml.ml_line_len > len) ++ { ++ static textprop_T textprop; // static because of alignment ++ unsigned idx; ++ ++ for (idx = 0; idx < (buf->b_ml.ml_line_len - len) ++ / sizeof(textprop_T); ++idx) ++ { ++ char_u *cur_prop = buf->b_ml.ml_line_ptr + len ++ + idx * sizeof(textprop_T); ++ size_t taillen; ++ ++ mch_memmove(&textprop, cur_prop, sizeof(textprop_T)); ++ if (textprop.tp_id == id || textprop.tp_type == type_id) ++ { ++ if (!(buf->b_ml.ml_flags & ML_LINE_DIRTY)) ++ { ++ char_u *newptr = alloc(buf->b_ml.ml_line_len); ++ ++ // need to allocate the line to be able to change it ++ if (newptr == NULL) ++ return; ++ mch_memmove(newptr, buf->b_ml.ml_line_ptr, ++ buf->b_ml.ml_line_len); ++ buf->b_ml.ml_line_ptr = newptr; ++ curbuf->b_ml.ml_flags |= ML_LINE_DIRTY; ++ } ++ ++ taillen = buf->b_ml.ml_line_len - len ++ - (idx + 1) * sizeof(textprop_T); ++ if (taillen > 0) ++ mch_memmove(cur_prop, cur_prop + sizeof(textprop_T), ++ taillen); ++ buf->b_ml.ml_line_len -= sizeof(textprop_T); ++ --idx; ++ ++ ++rettv->vval.v_number; ++ if (!do_all) ++ break; ++ } ++ } ++ } ++ } ++ redraw_buf_later(buf, NOT_VALID); ++ } ++ ++ /* ++ * Common for f_prop_type_add() and f_prop_type_change(). ++ */ ++ void ++ prop_type_set(typval_T *argvars, int add) ++ { ++ char_u *name; ++ buf_T *buf = NULL; ++ dict_T *dict; ++ dictitem_T *di; ++ proptype_T *prop; ++ ++ name = get_tv_string(&argvars[0]); ++ if (*name == NUL) ++ { ++ EMSG(_(e_invarg)); ++ return; ++ } ++ ++ if (get_bufnr_from_arg(&argvars[1], &buf) == FAIL) ++ return; ++ dict = argvars[1].vval.v_dict; ++ ++ prop = find_prop(name, buf); ++ if (add) ++ { ++ hashtab_T **htp; ++ ++ if (prop != NULL) ++ { ++ EMSG2(_("E969: Property type %s already defined"), name); ++ return; ++ } ++ prop = (proptype_T *)alloc_clear(sizeof(proptype_T) + STRLEN(name)); ++ if (prop == NULL) ++ return; ++ STRCPY(prop->pt_name, name); ++ prop->pt_id = ++proptype_id; ++ htp = buf == NULL ? &global_proptypes : &buf->b_proptypes; ++ if (*htp == NULL) ++ { ++ *htp = (hashtab_T *)alloc(sizeof(hashtab_T)); ++ if (*htp == NULL) ++ return; ++ hash_init(*htp); ++ } ++ hash_add(buf == NULL ? global_proptypes : buf->b_proptypes, ++ PT2HIKEY(prop)); ++ } ++ else ++ { ++ if (prop == NULL) ++ { ++ EMSG2(_(e_type_not_exist), name); ++ return; ++ } ++ } ++ ++ if (dict != NULL) ++ { ++ di = dict_find(dict, (char_u *)"highlight", -1); ++ if (di != NULL) ++ { ++ char_u *highlight; ++ int hl_id = 0; ++ ++ highlight = get_dict_string(dict, (char_u *)"highlight", TRUE); ++ if (highlight != NULL && *highlight != NUL) ++ hl_id = syn_name2id(highlight); ++ if (hl_id <= 0) ++ { ++ EMSG2(_("E970: Unknown highlight group name: '%s'"), ++ highlight == NULL ? (char_u *)"" : highlight); ++ return; ++ } ++ prop->pt_hl_id = hl_id; ++ } ++ ++ di = dict_find(dict, (char_u *)"priority", -1); ++ if (di != NULL) ++ prop->pt_priority = get_tv_number(&di->di_tv); ++ ++ di = dict_find(dict, (char_u *)"start_incl", -1); ++ if (di != NULL) ++ { ++ if (get_tv_number(&di->di_tv)) ++ prop->pt_flags |= PT_FLAG_INS_START_INCL; ++ else ++ prop->pt_flags &= ~PT_FLAG_INS_START_INCL; ++ } ++ ++ di = dict_find(dict, (char_u *)"end_incl", -1); ++ if (di != NULL) ++ { ++ if (get_tv_number(&di->di_tv)) ++ prop->pt_flags |= PT_FLAG_INS_END_INCL; ++ else ++ prop->pt_flags &= ~PT_FLAG_INS_END_INCL; ++ } ++ } ++ } ++ ++ /* ++ * prop_type_add({name}, {props}) ++ */ ++ void ++ f_prop_type_add(typval_T *argvars, typval_T *rettv UNUSED) ++ { ++ prop_type_set(argvars, TRUE); ++ } ++ ++ /* ++ * prop_type_change({name}, {props}) ++ */ ++ void ++ f_prop_type_change(typval_T *argvars, typval_T *rettv UNUSED) ++ { ++ prop_type_set(argvars, FALSE); ++ } ++ ++ /* ++ * prop_type_delete({name} [, {bufnr}]) ++ */ ++ void ++ f_prop_type_delete(typval_T *argvars, typval_T *rettv UNUSED) ++ { ++ char_u *name; ++ buf_T *buf = NULL; ++ hashitem_T *hi; ++ ++ name = get_tv_string(&argvars[0]); ++ if (*name == NUL) ++ { ++ EMSG(_(e_invarg)); ++ return; ++ } ++ ++ if (argvars[1].v_type != VAR_UNKNOWN) ++ { ++ if (get_bufnr_from_arg(&argvars[1], &buf) == FAIL) ++ return; ++ } ++ ++ hi = find_prop_hi(name, buf); ++ if (hi != NULL) ++ { ++ hashtab_T *ht; ++ ++ if (buf == NULL) ++ ht = global_proptypes; ++ else ++ ht = buf->b_proptypes; ++ hash_remove(ht, hi); ++ } ++ } ++ ++ /* ++ * prop_type_get({name} [, {bufnr}]) ++ */ ++ void ++ f_prop_type_get(typval_T *argvars, typval_T *rettv UNUSED) ++ { ++ char_u *name = get_tv_string(&argvars[0]); ++ ++ if (*name == NUL) ++ { ++ EMSG(_(e_invarg)); ++ return; ++ } ++ if (rettv_dict_alloc(rettv) == OK) ++ { ++ proptype_T *prop = NULL; ++ buf_T *buf = NULL; ++ ++ if (argvars[1].v_type != VAR_UNKNOWN) ++ { ++ if (get_bufnr_from_arg(&argvars[1], &buf) == FAIL) ++ return; ++ } ++ ++ prop = find_prop(name, buf); ++ if (prop != NULL) ++ { ++ dict_T *d = rettv->vval.v_dict; ++ ++ if (prop->pt_hl_id > 0) ++ dict_add_string(d, "highlight", syn_id2name(prop->pt_hl_id)); ++ dict_add_number(d, "priority", prop->pt_priority); ++ dict_add_number(d, "start_incl", ++ (prop->pt_flags & PT_FLAG_INS_START_INCL) ? 1 : 0); ++ dict_add_number(d, "end_incl", ++ (prop->pt_flags & PT_FLAG_INS_END_INCL) ? 1 : 0); ++ if (buf != NULL) ++ dict_add_number(d, "bufnr", buf->b_fnum); ++ } ++ } ++ } ++ ++ static void ++ list_types(hashtab_T *ht, list_T *l) ++ { ++ long todo; ++ hashitem_T *hi; ++ ++ todo = (long)ht->ht_used; ++ for (hi = ht->ht_array; todo > 0; ++hi) ++ { ++ if (!HASHITEM_EMPTY(hi)) ++ { ++ proptype_T *prop = HI2PT(hi); ++ ++ list_append_string(l, prop->pt_name, -1); ++ --todo; ++ } ++ } ++ } ++ ++ /* ++ * prop_type_list([{bufnr}]) ++ */ ++ void ++ f_prop_type_list(typval_T *argvars, typval_T *rettv UNUSED) ++ { ++ buf_T *buf = NULL; ++ ++ if (rettv_list_alloc(rettv) == OK) ++ { ++ if (argvars[0].v_type != VAR_UNKNOWN) ++ { ++ if (get_bufnr_from_arg(&argvars[0], &buf) == FAIL) ++ return; ++ } ++ if (buf == NULL) ++ { ++ if (global_proptypes != NULL) ++ list_types(global_proptypes, rettv->vval.v_list); ++ } ++ else if (buf->b_proptypes != NULL) ++ list_types(buf->b_proptypes, rettv->vval.v_list); ++ } ++ } ++ ++ /* ++ * Free all property types in "ht". ++ */ ++ static void ++ clear_ht_prop_types(hashtab_T *ht) ++ { ++ long todo; ++ hashitem_T *hi; ++ ++ if (ht == NULL) ++ return; ++ ++ todo = (long)ht->ht_used; ++ for (hi = ht->ht_array; todo > 0; ++hi) ++ { ++ if (!HASHITEM_EMPTY(hi)) ++ { ++ proptype_T *prop = HI2PT(hi); ++ ++ vim_free(prop); ++ --todo; ++ } ++ } ++ ++ hash_clear(ht); ++ vim_free(ht); ++ } ++ ++ #if defined(EXITFREE) || defined(PROTO) ++ /* ++ * Free all property types for "buf". ++ */ ++ void ++ clear_global_prop_types(void) ++ { ++ clear_ht_prop_types(global_proptypes); ++ global_proptypes = NULL; ++ } ++ #endif ++ ++ /* ++ * Free all property types for "buf". ++ */ ++ void ++ clear_buf_prop_types(buf_T *buf) ++ { ++ clear_ht_prop_types(buf->b_proptypes); ++ buf->b_proptypes = NULL; ++ } ++ ++ #endif // FEAT_TEXT_PROP +*** ../vim-8.1.0578/src/userfunc.c 2018-11-10 17:33:23.087518814 +0100 +--- src/userfunc.c 2018-12-13 20:24:32.174552670 +0100 +*************** +*** 25,31 **** + + /* From user function to hashitem and back. */ + #define UF2HIKEY(fp) ((fp)->uf_name) +! #define HIKEY2UF(p) ((ufunc_T *)(p - offsetof(ufunc_T, uf_name))) + #define HI2UF(hi) HIKEY2UF((hi)->hi_key) + + #define FUNCARG(fp, j) ((char_u **)(fp->uf_args.ga_data))[j] +--- 25,31 ---- + + /* From user function to hashitem and back. */ + #define UF2HIKEY(fp) ((fp)->uf_name) +! #define HIKEY2UF(p) ((ufunc_T *)((p) - offsetof(ufunc_T, uf_name))) + #define HI2UF(hi) HIKEY2UF((hi)->hi_key) + + #define FUNCARG(fp, j) ((char_u **)(fp->uf_args.ga_data))[j] +*** ../vim-8.1.0578/src/version.c 2018-12-12 20:34:06.076356104 +0100 +--- src/version.c 2018-12-13 20:39:19.480983935 +0100 +*************** +*** 653,664 **** + # else + "-terminfo", + # endif +- #else /* unix always includes termcap support */ +- # ifdef HAVE_TGETENT +- "+tgetent", +- # else +- "-tgetent", +- # endif + #endif + #ifdef FEAT_TERMRESPONSE + "+termresponse", +--- 653,658 ---- +*************** +*** 670,675 **** +--- 664,682 ---- + #else + "-textobjects", + #endif ++ #ifdef FEAT_TEXT_PROP ++ "+textprop", ++ #else ++ "-textprop", ++ #endif ++ #if !defined(UNIX) ++ /* unix always includes termcap support */ ++ # ifdef HAVE_TGETENT ++ "+tgetent", ++ # else ++ "-tgetent", ++ # endif ++ #endif + #ifdef FEAT_TIMERS + "+timers", + #else +*** ../vim-8.1.0578/src/version.c 2018-12-12 20:34:06.076356104 +0100 +--- src/version.c 2018-12-13 20:39:19.480983935 +0100 +*************** +*** 794,795 **** +--- 801,804 ---- + { /* Add new patch number below this line */ ++ /**/ ++ 579, + /**/ + +-- +EXPERIENCE - experience is a wonderful thing. It enables you to +recognise a mistake when you make it again. + + /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ +/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ +\\\ an exciting new programming language -- http://www.Zimbu.org /// + \\\ help me help AIDS victims -- http://ICCF-Holland.org /// |