diff options
-rw-r--r-- | Filelist | 2 | ||||
-rw-r--r-- | runtime/doc/Makefile | 2 | ||||
-rw-r--r-- | runtime/doc/eval.txt | 211 | ||||
-rw-r--r-- | runtime/doc/textprop.txt | 114 | ||||
-rw-r--r-- | src/Make_all.mak | 1 | ||||
-rw-r--r-- | src/Make_cyg_ming.mak | 4 | ||||
-rw-r--r-- | src/Make_mvc.mak | 4 | ||||
-rw-r--r-- | src/Makefile | 17 | ||||
-rw-r--r-- | src/buffer.c | 3 | ||||
-rw-r--r-- | src/edit.c | 3 | ||||
-rw-r--r-- | src/evalfunc.c | 14 | ||||
-rw-r--r-- | src/ex_getln.c | 15 | ||||
-rw-r--r-- | src/feature.h | 7 | ||||
-rw-r--r-- | src/memline.c | 106 | ||||
-rw-r--r-- | src/misc1.c | 30 | ||||
-rw-r--r-- | src/misc2.c | 3 | ||||
-rw-r--r-- | src/proto.h | 3 | ||||
-rw-r--r-- | src/proto/memline.pro | 1 | ||||
-rw-r--r-- | src/proto/textprop.pro | 17 | ||||
-rw-r--r-- | src/screen.c | 104 | ||||
-rw-r--r-- | src/structs.h | 39 | ||||
-rw-r--r-- | src/testdir/Make_all.mak | 1 | ||||
-rw-r--r-- | src/testdir/test_textprop.vim | 200 | ||||
-rw-r--r-- | src/textprop.c | 869 | ||||
-rw-r--r-- | src/userfunc.c | 2 | ||||
-rw-r--r-- | src/version.c | 21 |
26 files changed, 1747 insertions, 46 deletions
@@ -91,6 +91,7 @@ SRC_ALL = \ src/terminal.c \ src/term.h \ src/termlib.c \ + src/textprop.c \ src/ui.c \ src/undo.c \ src/userfunc.c \ @@ -198,6 +199,7 @@ SRC_ALL = \ 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 \ diff --git a/runtime/doc/Makefile b/runtime/doc/Makefile index e4b2b5b055..7dbb2bae1a 100644 --- a/runtime/doc/Makefile +++ b/runtime/doc/Makefile @@ -102,6 +102,7 @@ DOCS = \ tagsrch.txt \ term.txt \ terminal.txt \ + textprop.txt \ tips.txt \ todo.txt \ uganda.txt \ @@ -238,6 +239,7 @@ HTMLS = \ tagsrch.html \ term.html \ terminal.html \ + textprop.html \ tips.html \ todo.html \ uganda.html \ diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 21fc43aaae..4e80f4a971 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1,4 +1,4 @@ -*eval.txt* For Vim version 8.1. Last change: 2018 Dec 09 +*eval.txt* For Vim version 8.1. Last change: 2018 Dec 13 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1104,7 +1104,7 @@ Or, if you don't want to write them in as floating-point literals, you can also use functions, like the following: > :let pi = acos(-1.0) :let e = exp(1.0) - +< *floating-point-precision* The precision and range of floating points numbers depends on what "double" means in the library Vim was compiled with. There is no way to change this at @@ -2317,6 +2317,22 @@ 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 @@ -3142,8 +3158,9 @@ ch_logfile({fname} [, {mode}]) *ch_logfile()* When {mode} is omitted or "a" append to the file. When {mode} is "w" start with an empty file. - The file is flushed after every message, on Unix you can use - "tail -f" to see what is going on in real time. + Use |ch_log()| to write log messages. The file is flushed + after every message, on Unix you can use "tail -f" to see what + is going on in real time. This function is not available in the |sandbox|. NOTE: the channel communication is stored in the file, be @@ -6656,6 +6673,191 @@ prompt_setprompt({buf}, {text}) *prompt_setprompt()* 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()* @@ -9609,6 +9811,7 @@ terminal Compiled with |terminal| support. terminfo Compiled with terminfo instead of termcap. termresponse Compiled with support for |t_RV| and |v:termresponse|. textobjects Compiled with support for |text-objects|. +textprop Compiled with support for |text-properties|. tgetent Compiled with tgetent support, able to use a termcap or terminfo file. timers Compiled with |timer_start()| support. diff --git a/runtime/doc/textprop.txt b/runtime/doc/textprop.txt new file mode 100644 index 0000000000..c88ca37b8c --- /dev/null +++ b/runtime/doc/textprop.txt @@ -0,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: diff --git a/src/Make_all.mak b/src/Make_all.mak index 466f17e9e2..4aa30b862c 100644 --- a/src/Make_all.mak +++ b/src/Make_all.mak @@ -186,6 +186,7 @@ NEW_TESTS = \ test_terminal_fail \ test_textformat \ test_textobjects \ + test_textprop \ test_timers \ test_true_false \ test_undo \ diff --git a/src/Make_cyg_ming.mak b/src/Make_cyg_ming.mak index 1f62d86ee8..79bff50118 100644 --- a/src/Make_cyg_ming.mak +++ b/src/Make_cyg_ming.mak @@ -751,6 +751,7 @@ OBJ = \ $(OUTDIR)/syntax.o \ $(OUTDIR)/tag.o \ $(OUTDIR)/term.o \ + $(OUTDIR)/textprop.o \ $(OUTDIR)/ui.o \ $(OUTDIR)/undo.o \ $(OUTDIR)/userfunc.o \ @@ -1090,6 +1091,9 @@ $(OUTDIR)/regexp.o: regexp.c regexp_nfa.c $(INCL) $(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 \ diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak index e281c89a36..a35708d8dd 100644 --- a/src/Make_mvc.mak +++ b/src/Make_mvc.mak @@ -754,6 +754,7 @@ OBJ = \ $(OUTDIR)\syntax.obj \ $(OUTDIR)\tag.obj \ $(OUTDIR)\term.obj \ + $(OUTDIR)\textprop.obj \ $(OUTDIR)\ui.obj \ $(OUTDIR)\undo.obj \ $(OUTDIR)\userfunc.obj \ @@ -1529,6 +1530,8 @@ $(OUTDIR)/tag.obj: $(OUTDIR) tag.c $(INCL) $(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,6 +1670,7 @@ proto.h: \ proto/syntax.pro \ proto/tag.pro \ proto/term.pro \ + proto/textprop.pro \ proto/ui.pro \ proto/undo.pro \ proto/userfunc.pro \ diff --git a/src/Makefile b/src/Makefile index ad0b718287..aca1236d08 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1577,8 +1577,6 @@ include Make_all.mak # 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 \ @@ -1636,6 +1634,7 @@ BASIC_SRC = \ tag.c \ term.c \ terminal.c \ + textprop.c \ ui.c \ undo.c \ userfunc.c \ @@ -1657,7 +1656,8 @@ SRC = $(BASIC_SRC) \ $(WORKSHOP_SRC) \ $(WSDEBUG_SRC) -TAGS_SRC = *.c *.cpp if_perl.xs +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,6 +1747,7 @@ OBJ_COMMON = \ objects/tag.o \ objects/term.o \ objects/terminal.o \ + objects/textprop.o \ objects/ui.o \ objects/undo.o \ objects/userfunc.o \ @@ -1881,6 +1882,7 @@ PRO_AUTO = \ term.pro \ terminal.pro \ termlib.pro \ + textprop.pro \ ui.pro \ undo.pro \ userfunc.pro \ @@ -2092,7 +2094,7 @@ notags: # Motif and Athena GUI # You can ignore error messages for missing files. tags TAGS: notags - $(TAGPRG) $(TAGS_SRC) $(TAGS_INCL) $(TERM_SRC) $(TERM_DEPS) + $(TAGPRG) $(TAGS_SRC) $(TAGS_INCL) # Make a highlight file for types. Requires Exuberant ctags and awk types: types.vim @@ -3211,6 +3213,9 @@ objects/term.o: term.c 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,6 +3607,10 @@ objects/terminal.o: terminal.c vim.h protodef.h auto/config.h feature.h os_unix. 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 \ diff --git a/src/buffer.c b/src/buffer.c index 8235a4fcaa..bb940691c3 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -823,6 +823,9 @@ buf_freeall(buf_T *buf, int flags) #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 */ } diff --git a/src/edit.c b/src/edit.c index 6b5bc0f631..205dc65de7 100644 --- a/src/edit.c +++ b/src/edit.c @@ -10302,6 +10302,9 @@ ins_tab(void) 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()) diff --git a/src/evalfunc.c b/src/evalfunc.c index d3b2da7c46..6e687554ed 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -772,6 +772,17 @@ static struct fst {"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,6 +6489,9 @@ f_has(typval_T *argvars, typval_T *rettv) #ifdef FEAT_TEXTOBJ "textobjects", #endif +#ifdef FEAT_TEXT_PROP + "textprop", +#endif #ifdef HAVE_TGETENT "tgetent", #endif diff --git a/src/ex_getln.c b/src/ex_getln.c index bfda942783..4ea8bfa9d3 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -769,6 +769,21 @@ may_add_char_to_search(int firstc, int *c, incsearch_state_T *is_state) 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; } } diff --git a/src/feature.h b/src/feature.h index 9e87345dc0..9615a9fa49 100644 --- a/src/feature.h +++ b/src/feature.h @@ -502,6 +502,13 @@ #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). diff --git a/src/memline.c b/src/memline.c index 1d65a44d8f..59e4502601 100644 --- a/src/memline.c +++ b/src/memline.c @@ -2487,7 +2487,6 @@ ml_get_buf( { bhdr_T *hp; DATA_BL *dp; - char_u *ptr; static int recursive = 0; if (lnum > buf->b_ml.ml_line_count) /* invalid line number */ @@ -2518,6 +2517,10 @@ errorret: */ if (buf->b_ml.ml_line_lnum != lnum || mf_dont_release) { + unsigned start, end; + colnr_T len; + int idx; + ml_flush_line(buf); /* @@ -2540,8 +2543,18 @@ errorret: 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; + 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,20 +2627,21 @@ ml_append_buf( 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 */ + 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 line_count; // number of indexes in current block int offset; int from, to; - int space_needed; /* space needed for new line */ + int space_needed; // space needed for new line int page_size; int page_count; - int db_idx; /* index for lnum in data block */ + int db_idx; // index for lnum in data block bhdr_T *hp; memfile_T *mfp; DATA_BL *dp; @@ -2642,8 +2656,8 @@ ml_append_int( 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 */ + 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,7 +2742,8 @@ ml_append_int( dp->db_index[i + 1] = dp->db_index[i] - len; dp->db_index[db_idx + 1] = offset - len; } - else /* add line at the end */ + else + // add line at the end (which is the start of the text) dp->db_index[db_idx + 1] = dp->db_txt_start; /* @@ -3128,6 +3143,19 @@ ml_append_int( 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,7 +3163,7 @@ ml_replace(linenr_T lnum, char_u *line, int copy) if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL, 0) == FAIL) return FAIL; - if (copy && (line = vim_strsave(line)) == NULL) /* allocate memory */ + if (copy && (line = vim_strnsave(line, len)) == NULL) /* allocate memory */ return FAIL; #ifdef FEAT_NETBEANS_INTG if (netbeans_active()) @@ -3144,11 +3172,48 @@ ml_replace(linenr_T lnum, char_u *line, int copy) 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 */ + 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,7 +3555,7 @@ ml_flush_line(buf_T *buf) 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; + new_len = buf->b_ml.ml_line_len; extra = new_len - old_len; /* negative if lines gets smaller */ /* @@ -5009,8 +5074,7 @@ ml_updatechunk( */ 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; + buf->b_ml.ml_chunksize[0].mlcs_totalsize = (long)buf->b_ml.ml_line_len; return; } diff --git a/src/misc1.c b/src/misc1.c index f1f0074787..40d6f93c50 100644 --- a/src/misc1.c +++ b/src/misc1.c @@ -2631,9 +2631,10 @@ del_bytes( { 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 was_alloced; + int alloc_newp; long movelen; int fixpos = fixpos_arg; @@ -2710,6 +2711,7 @@ del_bytes( count = oldlen - col; movelen = 1; } |