diff options
-rw-r--r-- | ci/build.bat | 4 | ||||
-rw-r--r-- | runtime/doc/eval.txt | 294 | ||||
-rw-r--r-- | runtime/doc/job_control.txt | 2 | ||||
-rw-r--r-- | runtime/doc/options.txt | 1 | ||||
-rw-r--r-- | runtime/doc/starting.txt | 10 | ||||
-rw-r--r-- | runtime/doc/vim_diff.txt | 32 | ||||
-rw-r--r-- | src/nvim/README.md | 35 | ||||
-rw-r--r-- | src/nvim/api/vim.c | 5 | ||||
-rw-r--r-- | src/nvim/eval.c | 4 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 6 | ||||
-rw-r--r-- | src/nvim/message.c | 45 | ||||
-rw-r--r-- | src/nvim/option.c | 11 | ||||
-rw-r--r-- | src/nvim/tui/terminfo.c | 87 | ||||
-rw-r--r-- | src/nvim/tui/tui.c | 107 | ||||
-rw-r--r-- | src/nvim/ui_bridge.c | 3 | ||||
-rw-r--r-- | test/functional/eval/null_spec.lua | 16 | ||||
-rw-r--r-- | test/functional/helpers.lua | 7 | ||||
-rw-r--r-- | test/functional/terminal/tui_spec.lua | 65 | ||||
-rw-r--r-- | test/functional/ui/cmdline_spec.lua | 363 | ||||
-rw-r--r-- | test/functional/ui/screen.lua | 4 | ||||
-rw-r--r-- | third-party/cmake/BuildLuarocks.cmake | 13 |
21 files changed, 740 insertions, 374 deletions
diff --git a/ci/build.bat b/ci/build.bat index 6eb22176a9..91eca9ef73 100644 --- a/ci/build.bat +++ b/ci/build.bat @@ -33,6 +33,10 @@ set PATH=C:\Python35;C:\Python27;%PATH% python -c "import neovim; print(str(neovim))" || goto :error python3 -c "import neovim; print(str(neovim))" || goto :error +set PATH=C:\Ruby24\bin;%PATH% +cmd /c gem.cmd install neovim || goto :error +where.exe neovim-ruby-host.bat || goto :error + mkdir .deps cd .deps cmake -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo ..\third-party\ || goto :error diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 2b2fda25e9..e337c5d6d5 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1559,10 +1559,10 @@ v:exception The value of the exception most recently caught and not < Output: "caught oops". *v:false* *false-variable* -v:false Special value used to put "false" in JSON and msgpack. See - |json_encode()|. This value is converted to "v:false" when used - as a String (e.g. in |expr5| with string concatenation - operator) and to zero when used as a Number (e.g. in |expr5| +v:false Special value used to put "false" in JSON and msgpack. See + |json_encode()|. This value is converted to "v:false" when used + as a String (e.g. in |expr5| with string concatenation + operator) and to zero when used as a Number (e.g. in |expr5| or |expr7| when used with numeric operators). Read-only. *v:fcs_reason* *fcs_reason-variable* @@ -1703,16 +1703,16 @@ v:mouse_col Column number for a mouse click obtained with |getchar()|. value is zero when there was no mouse button click. *v:msgpack_types* *msgpack_types-variable* -v:msgpack_types Dictionary containing msgpack types used by |msgpackparse()| - and |msgpackdump()|. All types inside dictionary are fixed - (not editable) empty lists. To check whether some list is one +v:msgpack_types Dictionary containing msgpack types used by |msgpackparse()| + and |msgpackdump()|. All types inside dictionary are fixed + (not editable) empty lists. To check whether some list is one of msgpack types, use |is| operator. *v:null* *null-variable* -v:null Special value used to put "null" in JSON and NIL in msgpack. - See |json_encode()|. This value is converted to "v:null" when - used as a String (e.g. in |expr5| with string concatenation - operator) and to zero when used as a Number (e.g. in |expr5| +v:null Special value used to put "null" in JSON and NIL in msgpack. + See |json_encode()|. This value is converted to "v:null" when + used as a String (e.g. in |expr5| with string concatenation + operator) and to zero when used as a Number (e.g. in |expr5| or |expr7| when used with numeric operators). Read-only. *v:oldfiles* *oldfiles-variable* @@ -1903,10 +1903,10 @@ v:throwpoint The point where the exception most recently caught and not < Output: "Exception from test.vim, line 2" *v:true* *true-variable* -v:true Special value used to put "true" in JSON and msgpack. See - |json_encode()|. This value is converted to "v:true" when used - as a String (e.g. in |expr5| with string concatenation - operator) and to one when used as a Number (e.g. in |expr5| or +v:true Special value used to put "true" in JSON and msgpack. See + |json_encode()|. This value is converted to "v:true" when used + as a String (e.g. in |expr5| with string concatenation + operator) and to one when used as a Number (e.g. in |expr5| or |expr7| when used with numeric operators). Read-only. *v:val* *val-variable* @@ -2492,7 +2492,7 @@ assert_fails({cmd} [, {error}]) *assert_fails()* assert_false({actual} [, {msg}]) *assert_false()* When {actual} is not false an error message is added to |v:errors|, like with |assert_equal()|. - A value is false when it is zero or |v:false|. When "{actual}" + A value is false when it is zero or |v:false|. When "{actual}" is not a number or |v:false| the assert fails. When {msg} is omitted an error in the form "Expected False but got {actual}" is produced. @@ -3182,7 +3182,7 @@ diff_hlID({lnum}, {col}) *diff_hlID()* empty({expr}) *empty()* Return the Number 1 if {expr} is empty, zero otherwise. A |List| or |Dictionary| is empty when it does not have any - items. A Number is empty when its value is zero. Special + items. A Number is empty when its value is zero. Special variable is empty when it is |v:false| or |v:null|. escape({string}, {chars}) *escape()* @@ -4749,7 +4749,7 @@ input({opts}) string, or a blank string (for no prompt). A '\n' can be used in the prompt to start a new line. - In the second form it accepts a single dictionary with the + In the second form it accepts a single dictionary with the following keys, any of which may be omitted: Key Default Description ~ @@ -4757,7 +4757,7 @@ input({opts}) default "" Same as {text} in the first form. completion nothing Same as {completion} in the first form. cancelreturn "" Same as {cancelreturn} from - |inputdialog()|. Also works with + |inputdialog()|. Also works with input(). highlight nothing Highlight handler: |Funcref|. @@ -4833,8 +4833,8 @@ input({opts}) modifier. If the function causes any errors, it will be skipped for the duration of the current input() call. - Currently coloring is disabled when command-line contains - arabic characters. + Highlighting is disabled if command-line contains arabic + characters. NOTE: This function must not be used in a startup file, for the versions that only run in GUI mode (e.g., the Win32 GUI). @@ -4948,19 +4948,19 @@ islocked({expr}) *islocked()* *E786* message. Use |exists()| to check for existence. id({expr}) *id()* - Returns a |String| which is a unique identifier of the - container type (|List|, |Dict| and |Partial|). It is - guaranteed that for the mentioned types `id(v1) ==# id(v2)` - returns true iff `type(v1) == type(v2) && v1 is v2` (note: - |v:_null_list| and |v:_null_dict| have the same `id()` with - different types because they are internally represented as - a NULL pointers). Currently `id()` returns a hexadecimal - representanion of the pointers to the containers (i.e. like - `0x994a40`), same as `printf("%p", {expr})`, but it is advised + Returns a |String| which is a unique identifier of the + container type (|List|, |Dict| and |Partial|). It is + guaranteed that for the mentioned types `id(v1) ==# id(v2)` + returns true iff `type(v1) == type(v2) && v1 is v2` (note: + |v:_null_list| and |v:_null_dict| have the same `id()` with + different types because they are internally represented as + a NULL pointers). Currently `id()` returns a hexadecimal + representanion of the pointers to the containers (i.e. like + `0x994a40`), same as `printf("%p", {expr})`, but it is advised against counting on exact format of return value. - It is not guaranteed that `id(no_longer_existing_container)` - will not be equal to some other `id()`: new containers may + It is not guaranteed that `id(no_longer_existing_container)` + will not be equal to some other `id()`: new containers may reuse identifiers of the garbage-collected ones. items({dict}) *items()* @@ -5071,14 +5071,14 @@ join({list} [, {sep}]) *join()* The opposite function is |split()|. json_decode({expr}) *json_decode()* - Convert {expr} from JSON object. Accepts |readfile()|-style - list as the input, as well as regular string. May output any + Convert {expr} from JSON object. Accepts |readfile()|-style + list as the input, as well as regular string. May output any Vim value. In the following cases it will output |msgpack-special-dict|: 1. Dictionary contains duplicate key. 2. Dictionary contains empty key. - 3. String contains NUL byte. Two special dictionaries: for - dictionary and for string will be emitted in case string + 3. String contains NUL byte. Two special dictionaries: for + dictionary and for string will be emitted in case string with NUL byte was a dictionary key. Note: function treats its input as UTF-8 always. The JSON @@ -5087,14 +5087,14 @@ json_decode({expr}) *json_decode()* Non-UTF-8 characters are an error. json_encode({expr}) *json_encode()* - Convert {expr} into a JSON string. Accepts - |msgpack-special-dict| as the input. Will not convert - |Funcref|s, mappings with non-string keys (can be created as - |msgpack-special-dict|), values with self-referencing - containers, strings which contain non-UTF-8 characters, - pseudo-UTF-8 strings which contain codepoints reserved for - surrogate pairs (such strings are not valid UTF-8 strings). - Non-printable characters are converted into "\u1234" escapes + Convert {expr} into a JSON string. Accepts + |msgpack-special-dict| as the input. Will not convert + |Funcref|s, mappings with non-string keys (can be created as + |msgpack-special-dict|), values with self-referencing + containers, strings which contain non-UTF-8 characters, + pseudo-UTF-8 strings which contain codepoints reserved for + surrogate pairs (such strings are not valid UTF-8 strings). + Non-printable characters are converted into "\u1234" escapes or special escapes like "\t", other are dumped as-is. keys({dict}) *keys()* @@ -5193,7 +5193,7 @@ line({expr}) The result is a Number, which is the line number of the file This autocommand jumps to the last known position in a file just after opening it, if the '" mark is set: > :au BufReadPost * - \ if line("'\"") > 1 && line("'\"") <= line("$") && &ft !~# 'commit' + \ if line("'\"") > 1 && line("'\"") <= line("$") && &ft !~# 'commit' \ | exe "normal! g`\"" \ | endif @@ -5244,7 +5244,7 @@ log10({expr}) *log10()* < -2.0 luaeval({expr}[, {expr}]) - Evaluate Lua expression {expr} and return its result converted + Evaluate Lua expression {expr} and return its result converted to Vim data structures. See |lua-luaeval| for more details. map({expr1}, {expr2}) *map()* @@ -5675,7 +5675,7 @@ mkdir({name} [, {path} [, {prot}]]) :call mkdir($HOME . "/tmp/foo/bar", "p", 0700) < This function is not available in the |sandbox|. - If you try to create an existing directory with {path} set to + If you try to create an existing directory with {path} set to "p" mkdir() will silently exit. *mode()* @@ -5728,78 +5728,76 @@ msgpackdump({list}) {Nvim} *msgpackdump()* 5. Points 3. and 4. do not apply to |msgpack-special-dict|s. msgpackparse({list}) {Nvim} *msgpackparse()* - Convert a |readfile()|-style list to a list of VimL objects. + Convert a |readfile()|-style list to a list of VimL objects. Example: > let fname = expand('~/.config/nvim/shada/main.shada') let mpack = readfile(fname, 'b') let shada_objects = msgpackparse(mpack) -< This will read ~/.config/nvim/shada/main.shada file to +< This will read ~/.config/nvim/shada/main.shada file to `shada_objects` list. Limitations: - 1. Mapping ordering is not preserved unless messagepack - mapping is dumped using generic mapping + 1. Mapping ordering is not preserved unless messagepack + mapping is dumped using generic mapping (|msgpack-special-map|). - 2. Since the parser aims to preserve all data untouched - (except for 1.) some strings are parsed to - |msgpack-special-dict| format which is not convenient to + 2. Since the parser aims to preserve all data untouched + (except for 1.) some strings are parsed to + |msgpack-special-dict| format which is not convenient to use. *msgpack-special-dict* - Some messagepack strings may be parsed to special + Some messagepack strings may be parsed to special dictionaries. Special dictionaries are dictionaries which 1. Contain exactly two keys: `_TYPE` and `_VAL`. - 2. `_TYPE` key is one of the types found in |v:msgpack_types| + 2. `_TYPE` key is one of the types found in |v:msgpack_types| variable. - 3. Value for `_VAL` has the following format (Key column + 3. Value for `_VAL` has the following format (Key column contains name of the key from |v:msgpack_types|): Key Value ~ - nil Zero, ignored when dumping. This value cannot - possibly appear in |msgpackparse()| output in Neovim - versions which have |v:null|. - boolean One or zero. When dumping it is only checked that - value is a |Number|. This value cannot possibly - appear in |msgpackparse()| output in Neovim versions - which have |v:true| and |v:false|. - integer |List| with four numbers: sign (-1 or 1), highest two - bits, number with bits from 62nd to 31st, lowest 31 - bits. I.e. to get actual number one will need to use + nil Zero, ignored when dumping. Not returned by + |msgpackparse()| since |v:null| was introduced. + boolean One or zero. When dumping it is only checked that + value is a |Number|. Not returned by |msgpackparse()| + since |v:true| and |v:false| were introduced. + integer |List| with four numbers: sign (-1 or 1), highest two + bits, number with bits from 62nd to 31st, lowest 31 + bits. I.e. to get actual number one will need to use code like > _VAL[0] * ((_VAL[1] << 62) & (_VAL[2] << 31) & _VAL[3]) -< Special dictionary with this type will appear in - |msgpackparse()| output under one of the following +< Special dictionary with this type will appear in + |msgpackparse()| output under one of the following circumstances: - 1. |Number| is 32-bit and value is either above + 1. |Number| is 32-bit and value is either above INT32_MAX or below INT32_MIN. - 2. |Number| is 64-bit and value is above INT64_MAX. It - cannot possibly be below INT64_MIN because msgpack + 2. |Number| is 64-bit and value is above INT64_MAX. It + cannot possibly be below INT64_MIN because msgpack C parser does not support such values. - float |Float|. This value cannot possibly appear in + float |Float|. This value cannot possibly appear in |msgpackparse()| output. - string |readfile()|-style list of strings. This value will - appear in |msgpackparse()| output if string contains - zero byte or if string is a mapping key and mapping is - being represented as special dictionary for other + string |readfile()|-style list of strings. This value will + appear in |msgpackparse()| output if string contains + zero byte or if string is a mapping key and mapping is + being represented as special dictionary for other reasons. - binary |readfile()|-style list of strings. This value will - appear in |msgpackparse()| output if binary string + binary |readfile()|-style list of strings. This value will + appear in |msgpackparse()| output if binary string contains zero byte. - array |List|. This value cannot appear in |msgpackparse()| + array |List|. This value cannot appear in |msgpackparse()| output. *msgpack-special-map* - map |List| of |List|s with two items (key and value) each. - This value will appear in |msgpackparse()| output if + map |List| of |List|s with two items (key and value) each. + This value will appear in |msgpackparse()| output if parsed mapping contains one of the following keys: - 1. Any key that is not a string (including keys which + 1. Any key that is not a string (including keys which are binary strings). 2. String with NUL byte inside. 3. Duplicate key. 4. Empty key. - ext |List| with two values: first is a signed integer - representing extension type. Second is + ext |List| with two values: first is a signed integer + representing extension type. Second is |readfile()|-style list of strings. nextnonblank({lnum}) *nextnonblank()* @@ -6073,11 +6071,11 @@ pumvisible() *pumvisible()* py3eval({expr}) *py3eval()* Evaluate Python expression {expr} and return its result converted to Vim data structures. - Numbers and strings are returned as they are (strings are - copied though, Unicode strings are additionally converted to + Numbers and strings are returned as they are (strings are + copied though, Unicode strings are additionally converted to UTF-8). Lists are represented as Vim |List| type. - Dictionaries are represented as Vim |Dictionary| type with + Dictionaries are represented as Vim |Dictionary| type with keys converted to strings. {only available when compiled with the |+python3| feature} @@ -6145,7 +6143,7 @@ readfile({fname} [, {binary} [, {max}]]) reltime([{start} [, {end}]]) *reltime()* Return an item that represents a time value. The format of the item depends on the system. It can be passed to - |reltimestr()| to convert it to a string or |reltimefloat()| + |reltimestr()| to convert it to a string or |reltimefloat()| to convert to a float. Without an argument it returns the current "relative time", an @@ -6929,9 +6927,9 @@ setreg({regname}, {value} [, {options}]) :call setreg('a', "1\n2\n3", 'b5') < This example shows using the functions to save and restore a - register (note: you may not reliably restore register value - without using the third argument to |getreg()| as without it - newlines are represented as newlines AND Nul bytes are + register (note: you may not reliably restore register value + without using the third argument to |getreg()| as without it + newlines are represented as newlines AND Nul bytes are represented as newlines as well, see |NL-used-for-Nul|). > :let var_a = getreg('a', 1, 1) :let var_amode = getregtype('a') @@ -7369,20 +7367,20 @@ string({expr}) Return {expr} converted to a String. If {expr} is a Number, {expr} type result ~ String 'string' Number 123 - Float 123.123456 or 1.123456e8 or + Float 123.123456 or 1.123456e8 or `str2float('inf')` Funcref `function('name')` List [item, item] Dictionary {key: value, key: value} Note that in String values the ' character is doubled. Also see |strtrans()|. - Note 2: Output format is mostly compatible with YAML, except - for infinite and NaN floating-point values representations - which use |str2float()|. Strings are also dumped literally, - only single quote is escaped, which does not allow using YAML - for parsing back binary strings. |eval()| should always work for - strings and floats though and this is the only official - method, use |msgpackdump()| or |json_encode()| if you need to + Note 2: Output format is mostly compatible with YAML, except + for infinite and NaN floating-point values representations + which use |str2float()|. Strings are also dumped literally, + only single quote is escaped, which does not allow using YAML + for parsing back binary strings. |eval()| should always work for + strings and floats though and this is the only official + method, use |msgpackdump()| or |json_encode()| if you need to share data with other application. *strlen()* @@ -7630,10 +7628,10 @@ system({cmd} [, {input}]) *system()* *E677* redirection syntax) before input can reach it. Use |jobstart()| instead. - Note: Use |shellescape()| or |::S| with |expand()| or - |fnamemodify()| to escape special characters in a command - argument. Newlines in {cmd} may cause the command to fail. - The characters in 'shellquote' and 'shellxquote' may also + Note: Use |shellescape()| or |::S| with |expand()| or + |fnamemodify()| to escape special characters in a command + argument. Newlines in {cmd} may cause the command to fail. + The characters in 'shellquote' and 'shellxquote' may also cause trouble. The result is a String. Example: > @@ -7660,9 +7658,9 @@ system({cmd} [, {input}]) *system()* *E677* systemlist({cmd} [, {input} [, {keepempty}]]) *systemlist()* - Same as |system()|, but returns a |List| with lines (parts of - output separated by NL) with NULs transformed into NLs. Output - is the same as |readfile()| will output with {binary} argument + Same as |system()|, but returns a |List| with lines (parts of + output separated by NL) with NULs transformed into NLs. Output + is the same as |readfile()| will output with {binary} argument set to "b", except that a final newline is not preserved, unless {keepempty} is non-zero. Note that on MS-Windows you may get trailing CR characters. @@ -7926,7 +7924,7 @@ type({expr}) *type()* :if type(myvar) == type({}) :if type(myvar) == type(0.0) :if type(myvar) == type(v:true) -< In place of checking for |v:null| type it is better to check +< In place of checking for |v:null| type it is better to check for |v:null| directly as it is the only value of this type: > :if myvar is v:null < To check if the v:t_ variables exist use this: > @@ -8243,10 +8241,10 @@ writefile({list}, {fname} [, {flags}]) :call writefile(["foo"], "event.log", "a") :call writefile(["bar"], "event.log", "a") < - When {flags} contains "S" fsync() call is not used, with "s" - it is used, 'fsync' option applies by default. No fsync() - means that writefile() will finish faster, but writes may be - left in OS buffers and not yet written to disk. Such changes + When {flags} contains "S" fsync() call is not used, with "s" + it is used, 'fsync' option applies by default. No fsync() + means that writefile() will finish faster, but writes may be + left in OS buffers and not yet written to disk. Such changes will disappear if system crashes before OS does writing. All NL characters are replaced with a NUL character. @@ -8728,7 +8726,7 @@ like this: > When such a function is called, and it is not defined yet, Vim will search the "autoload" directories in 'runtimepath' for a script file called -"filename.vim". For example "~/.config/nvim/autoload/filename.vim". That +"filename.vim". For example "~/.config/nvim/autoload/filename.vim". That file should then define the function like this: > function filename#funcname() @@ -8889,11 +8887,6 @@ This does NOT work: > value and the global value are changed. Example: > :let &path = &path . ',/usr/local/include' -< This also works for terminal codes in the form t_xx. - But only for alphanumerical names. Example: > - :let &t_k1 = "\<Esc>[234;" -< When the code does not exist yet it will be created as - a terminal key code, there is no error. :let &{option-name} .= {expr1} For a string option: Append {expr1} to the value. @@ -9004,8 +8997,8 @@ This does NOT work: > < *E741* *E940* If you try to change a locked variable you get an error message: "E741: Value is locked: {name}". - If you try to lock or unlock a built-in variable you - will get an error message "E940: Cannot lock or unlock + If you try to lock or unlock a built-in variable you + will get an error message "E940: Cannot lock or unlock variable {name}". [depth] is relevant when locking a |List| or @@ -9264,17 +9257,17 @@ This does NOT work: > with the |:redraw| command. Example: > :new | redraw | echo "there is a new window" < *:echo-self-refer* - When printing nested containers echo prints second - occurrence of the self-referencing container using - "[...@level]" (self-referencing |List|) or + When printing nested containers echo prints second + occurrence of the self-referencing container using + "[...@level]" (self-referencing |List|) or "{...@level}" (self-referencing |Dict|): > :let l = [] :call add(l, l) :let l2 = [] :call add(l2, [l2]) :echo l l2 -< echoes "[[...@0]] [[[...@0]]]". Echoing "[l]" will - echo "[[[...@1]]]" because l first occurs at second +< echoes "[[...@0]] [[[...@0]]]". Echoing "[l]" will + echo "[[[...@1]]]" because l first occurs at second level. *:echon* @@ -10574,19 +10567,18 @@ This is not allowed when the textlock is active: - etc. ============================================================================== -13. Command-line expressions coloring *expr-coloring* +13. Command-line expressions highlighting *expr-highlight* -Expressions entered by user in |i_CTRL-R_=|, |c_CTRL-\_e|, |quote=| are -colored by built-in expressions parser. It uses highlight groups described in -the table below, which may be overriden by user colorschemes, all linked to -some other highlighting group. +Expressions entered by the user in |i_CTRL-R_=|, |c_CTRL-\_e|, |quote=| are +highlighted by the built-in expressions parser. It uses highlight groups +described in the table below, which may be overriden by colorschemes. *hl-NvimInvalid* -In addition to highlighting groups prefixed with Nvim described below there -are highlighting groups prefixed with NvimInvalid which have just the same -meaning, but used to indicate that the relevant token contains an error or -that error had occurred just before it. They have mostly the same hierarchy, -except that by default in place of any non-Nvim-prefixed group NvimInvalid -linking to `Error` is used and some other intermediate groups are present. +Besides the "Nvim"-prefixed highlight groups described below, there are +"NvimInvalid"-prefixed highlight groups which have the same meaning but +indicate that the token contains an error or that an error occurred just +before it. They have mostly the same hierarchy, except that (by default) in +place of any non-Nvim-prefixed group NvimInvalid linking to `Error` is used +and some other intermediate groups are present. Group Default link Colored expression ~ *hl-NvimInternalError* None, red/red Parser bug @@ -10637,24 +10629,24 @@ Group Default link Colored expression ~ *hl-NvimList* NvimContainer `[`/`]` in |list| literal *hl-NvimIdentifier* Identifier Generic identifier -*hl-NvimIdentifierScope* NvimIdentifier Namespace: letter - before `:` in +*hl-NvimIdentifierScope* NvimIdentifier Namespace: letter + before `:` in |internal-variables| *hl-NvimIdentifierScopeDelimiter* NvimIdentifier `:` after namespace letter *hl-NvimIdentifierName* NvimIdentifier Rest of the ident -*hl-NvimIdentifierKey* NvimIdentifier Identifier after +*hl-NvimIdentifierKey* NvimIdentifier Identifier after |expr-entry| *hl-NvimColon* Delimiter `:` in |dict| literal -*hl-NvimComma* Delimiter `,` in |dict|/|list| - literal or +*hl-NvimComma* Delimiter `,` in |dict|/|list| + literal or |expr-function| *hl-NvimArrow* Delimiter `->` in |lambda| *hl-NvimRegister* SpecialChar |expr-register| -*hl-NvimNumber* Number Non-prefix digits - in integer +*hl-NvimNumber* Number Non-prefix digits + in integer |expr-number| *hl-NvimNumberPrefix* Type `0` for |octal-number| `0x` for |hex-number| @@ -10672,25 +10664,25 @@ Group Default link Colored expression ~ *hl-NvimEnvironmentName* NvimIdentifier Env variable name *hl-NvimString* String Generic string -*hl-NvimStringBody* NvimString Generic string +*hl-NvimStringBody* NvimString Generic string literal body *hl-NvimStringQuote* NvimString Generic string quote -*hl-NvimStringSpecial* SpecialChar Generic string +*hl-NvimStringSpecial* SpecialChar Generic string non-literal body *hl-NvimSingleQuote* NvimStringQuote `'` in |expr-'| -*hl-NvimSingleQuotedBody* NvimStringBody Literal part of +*hl-NvimSingleQuotedBody* NvimStringBody Literal part of |expr-'| string body -*hl-NvimSingleQuotedQuote* NvimStringSpecial `''` inside |expr-'| +*hl-NvimSingleQuotedQuote* NvimStringSpecial `''` inside |expr-'| string body *hl-NvimDoubleQuote* NvimStringQuote `"` in |expr-quote| -*hl-NvimDoubleQuotedBody* NvimStringBody Literal part of +*hl-NvimDoubleQuotedBody* NvimStringBody Literal part of |expr-quote| body -*hl-NvimDoubleQuotedEscape* NvimStringSpecial Valid |expr-quote| +*hl-NvimDoubleQuotedEscape* NvimStringSpecial Valid |expr-quote| escape sequence -*hl-NvimDoubleQuotedUnknownEscape* NvimInvalidValue Unrecognized - |expr-quote| escape +*hl-NvimDoubleQuotedUnknownEscape* NvimInvalidValue Unrecognized + |expr-quote| escape sequence vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/runtime/doc/job_control.txt b/runtime/doc/job_control.txt index e57015db22..ed5f16902a 100644 --- a/runtime/doc/job_control.txt +++ b/runtime/doc/job_control.txt @@ -58,7 +58,7 @@ Description of what happens: - The first shell is idle, waiting to read commands from its stdin. - The second shell is started with -c which executes the command (a for-loop printing 0 through 9) and then exits. - - `JobHandler()` callback is passed to |jobstart()| to handle various job + - `OnEvent()` callback is passed to |jobstart()| to handle various job events. It displays stdout/stderr data received from the shells. For |on_stdout| and |on_stderr| see |channel-callback|. diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 4fe2e07909..4180ca21f2 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -6424,6 +6424,7 @@ A jump table for the options with a short description can be found at |Q_op|. Currently, these messages are given: >= 1 When the shada file is read or written. >= 2 When a file is ":source"'ed. + >= 3 UI info, terminal capabilities >= 5 Every searched tags file and include file. >= 8 Files for which a group of autocommands is executed. >= 9 Every executed autocommand. diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt index 9b33926d04..30c0641ef7 100644 --- a/runtime/doc/starting.txt +++ b/runtime/doc/starting.txt @@ -249,14 +249,14 @@ argument. for reading or writing a ShaDa file. Can be used to find out what is happening upon startup and exit. Example: > - vim -V8 foobar + nvim -V8 -V[N]{filename} - Like -V and set 'verbosefile' to {filename}. The result is - that messages are not displayed but written to the file - {filename}. {filename} must not start with a digit. + Like -V and set 'verbosefile' to {filename}. Messages are not + displayed; instead they are written to the file {filename}. + {filename} must not start with a digit. Example: > - vim -V20vimlog foobar + nvim -V20vimlog < *-D* -D Debugging. Go to debugging mode when executing the first diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt index 828920ef1a..1a4a66ed89 100644 --- a/runtime/doc/vim_diff.txt +++ b/runtime/doc/vim_diff.txt @@ -165,15 +165,17 @@ Highlight groups: |hl-TermCursor| |hl-TermCursorNC| |hl-Whitespace| highlights 'listchars' whitespace - -UI: - *E5408* *E5409* *g:Nvim_color_cmdline* - Command-line coloring is supported. Only |input()| and |inputdialog()| may - be colored by user. For testing purposes regular command-line (|:|) is - colored by callback defined in `g:Nvim_color_cmdline` (this callback is for - testing only, and will be removed in a future version). Additionally - expression command-line is colored using built-in expressions parser (it is - not yet used for actually parsing expressions though), see |expr-coloring|. + |expr-highlight| highlight groups (prefixed with "Nvim") + +Command-line highlighting: + The expression prompt (|@=|, |c_CTRL-R_=|, |i_CTRL-R_=|) is highlighted + using a built-in VimL expression parser. |expr-highlight| + *E5408* *E5409* + |input()|, |inputdialog()| support custom highlighting. |input()-highlight| + *g:Nvim_color_cmdline* + (Experimental) Command-line (|:|) is colored by callback defined in + `g:Nvim_color_cmdline` (this callback is for testing only, and will be + removed in the future). ============================================================================== 4. Changed features *nvim-features-changed* @@ -328,22 +330,26 @@ Ed-compatible mode: ":set noedcompatible" is ignored ":set edcompatible" is an error - *t_xx* *:set-termcap* *termcap-options* *t_AB* *t_Sb* *t_vb* *t_SI* + *t_xx* *termcap-options* *t_AB* *t_Sb* *t_vb* *t_SI* Nvim does not have special `t_XX` options nor <t_XX> keycodes to configure terminal capabilities. Instead Nvim treats the terminal as any other UI. For example, 'guicursor' sets the terminal cursor style if possible. - *'term'* *E529* *E530* *E531* + *:set-termcap* +Start Nvim with 'verbose' level 3 to see the terminal capabilities. > + nvim -V3 +< + *'term'* *E529* *E530* *E531* 'term' reflects the terminal type derived from |$TERM| and other environment checks. For debugging only; not reliable during startup. > :echo &term "builtin_x" means one of the |builtin-terms| was chosen, because the expected terminfo file was not found on the system. - *termcap* + *termcap* Nvim never uses the termcap database, only |terminfo| and |builtin-terms|. - *xterm-8bit* *xterm-8-bit* + *xterm-8bit* *xterm-8-bit* Xterm can be run in a mode where it uses true 8-bit CSI. Supporting this requires autodetection of whether the terminal is in UTF-8 mode or non-UTF-8 mode, as the 8-bit CSI character has to be written differently in each case. diff --git a/src/nvim/README.md b/src/nvim/README.md index 0caf71e2c5..da87a0208e 100644 --- a/src/nvim/README.md +++ b/src/nvim/README.md @@ -32,6 +32,39 @@ The source files use extensions to hint about their purpose. - `*.h.generated.h` - exported functions’ declarations. - `*.c.generated.h` - static functions’ declarations. +TUI debugging +------------- + +### TUI troubleshoot + +Nvim logs its internal terminfo state at 'verbose' level 3. This makes it +possible to see exactly what terminfo values Nvim is using on any system. + + nvim -V3log + +### TUI trace + +The ancient `script` command is still the "state of the art" for tracing +terminal behavior. The libvterm `vterm-dump` utility formats the result for +human-readability. + +Record a Nvim terminal session and format it with `vterm-dump`: + + script foo + ./build/bin/nvim -u NONE + # Exit the script session with CTRL-d + + # Use `vterm-dump` utility to format the result. + ./.deps/usr/bin/vterm-dump foo > bar + +Then you can compare `bar` with another session, to debug TUI behavior. + +### Terminal reference + +- `man terminfo` +- http://bazaar.launchpad.net/~libvterm/libvterm/trunk/view/head:/doc/seqs.txt +- http://invisible-island.net/xterm/ctlseqs/ctlseqs.html + Nvim lifecycle -------------- @@ -39,7 +72,7 @@ Following describes how Nvim processes input. Consider a typical Vim-like editing session: -01. Vim dispays the welcome screen +01. Vim displays the welcome screen 02. User types: `:` 03. Vim enters command-line mode 04. User types: `edit README.txt<CR>` diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index a0816dbc8e..416e7d22d2 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -923,7 +923,7 @@ typedef kvec_withinit_t(ExprASTConvStackItem, 16) ExprASTConvStack; /// starting column and ending column (latter exclusive: /// one should highlight region [start_col, end_col)). /// -/// @return AST: top-level dectionary holds keys +/// @return AST: top-level dictionary holds keys /// /// "error": Dictionary with error, present only if parser saw some /// error. Contains the following keys: @@ -938,8 +938,7 @@ typedef kvec_withinit_t(ExprASTConvStackItem, 16) ExprASTConvStack; /// @note: “Sucessfully parsed” here means “participated in AST /// creation”, not “till the first error”. /// -/// "ast": actual AST, either nil or a dictionary with the following -/// keys: +/// "ast": AST, either nil or a dictionary with these keys: /// /// "type": node type, one of the value names from ExprASTNodeType /// stringified without "kExprNode" prefix. diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 577aa67c60..56aedb1b4e 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -8457,11 +8457,13 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map) int idx = 0; if (argvars[0].v_type == VAR_LIST) { + tv_copy(&argvars[0], rettv); if ((l = argvars[0].vval.v_list) == NULL || (!map && tv_check_lock(l->lv_lock, arg_errmsg, TV_TRANSLATE))) { return; } } else if (argvars[0].v_type == VAR_DICT) { + tv_copy(&argvars[0], rettv); if ((d = argvars[0].vval.v_dict) == NULL || (!map && tv_check_lock(d->dv_lock, arg_errmsg, TV_TRANSLATE))) { return; @@ -8542,8 +8544,6 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map) did_emsg |= save_did_emsg; } - - tv_copy(&argvars[0], rettv); } static int filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp) diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 19fd4b70c5..1adc8325f8 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -3508,8 +3508,10 @@ nextwild ( return FAIL; } - MSG_PUTS("..."); /* show that we are busy */ - ui_flush(); + if (!ui_is_external(kUIWildmenu)) { + MSG_PUTS("..."); // show that we are busy + ui_flush(); + } i = (int)(xp->xp_pattern - ccline.cmdbuff); xp->xp_pattern_len = ccline.cmdpos - i; diff --git a/src/nvim/message.c b/src/nvim/message.c index b90c475ede..5c8f0655bf 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -1237,31 +1237,30 @@ void msg_make(char_u *arg) } } -/* - * Output the string 'str' upto a NUL character. - * Return the number of characters it takes on the screen. - * - * If K_SPECIAL is encountered, then it is taken in conjunction with the - * following character and shown as <F1>, <S-Up> etc. Any other character - * which is not printable shown in <> form. - * If 'from' is TRUE (lhs of a mapping), a space is shown as <Space>. - * If a character is displayed in one of these special ways, is also - * highlighted (its highlight name is '8' in the p_hl variable). - * Otherwise characters are not highlighted. - * This function is used to show mappings, where we want to see how to type - * the character/string -- webb - */ -int -msg_outtrans_special ( - char_u *strstart, - int from /* TRUE for lhs of a mapping */ +/// Output the string 'str' upto a NUL character. +/// Return the number of characters it takes on the screen. +/// +/// If K_SPECIAL is encountered, then it is taken in conjunction with the +/// following character and shown as <F1>, <S-Up> etc. Any other character +/// which is not printable shown in <> form. +/// If 'from' is TRUE (lhs of a mapping), a space is shown as <Space>. +/// If a character is displayed in one of these special ways, is also +/// highlighted (its highlight name is '8' in the p_hl variable). +/// Otherwise characters are not highlighted. +/// This function is used to show mappings, where we want to see how to type +/// the character/string -- webb +int msg_outtrans_special( + const char_u *strstart, + int from ///< true for LHS of a mapping ) { - char_u *str = strstart; + if (strstart == NULL) { + return 0; // Do nothing. + } + const char_u *str = strstart; int retval = 0; - int attr; + int attr = hl_attr(HLF_8); - attr = hl_attr(HLF_8); while (*str != NUL) { const char *string; // Leading and trailing spaces need to be displayed in <> form. @@ -1307,7 +1306,7 @@ char *str2special_save(const char *const str, const bool replace_spaces, return (char *)ga.ga_data; } -/// Convert character, replacing key one key code with printable representation +/// Convert character, replacing key with printable representation. /// /// @param[in,out] sp String to convert. Is advanced to the next key code. /// @param[in] replace_spaces Convert spaces into <Space>, normally used for @@ -1392,7 +1391,7 @@ void str2specialbuf(const char *sp, char *buf, size_t len) while (*sp) { const char *s = str2special(&sp, false, false); const size_t s_len = strlen(s); - if (s_len <= len) { + if (len <= s_len) { break; } memcpy(buf, s, s_len); diff --git a/src/nvim/option.c b/src/nvim/option.c index 913d27d508..37c4233142 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -4906,15 +4906,14 @@ showoptions ( vimoption_T **items = xmalloc(sizeof(vimoption_T *) * PARAM_COUNT); - /* Highlight title */ - if (all == 2) - MSG_PUTS_TITLE(_("\n--- Terminal codes ---")); - else if (opt_flags & OPT_GLOBAL) + // Highlight title + if (opt_flags & OPT_GLOBAL) { MSG_PUTS_TITLE(_("\n--- Global option values ---")); - else if (opt_flags & OPT_LOCAL) + } else if (opt_flags & OPT_LOCAL) { MSG_PUTS_TITLE(_("\n--- Local option values ---")); - else + } else { MSG_PUTS_TITLE(_("\n--- Options ---")); + } /* * do the loop two times: diff --git a/src/nvim/tui/terminfo.c b/src/nvim/tui/terminfo.c index fdc33f0a77..492c1c5e9c 100644 --- a/src/nvim/tui/terminfo.c +++ b/src/nvim/tui/terminfo.c @@ -9,7 +9,10 @@ #include <unibilium.h> #include "nvim/log.h" +#include "nvim/globals.h" #include "nvim/memory.h" +#include "nvim/message.h" +#include "nvim/option.h" #include "nvim/tui/terminfo.h" #ifdef INCLUDE_GENERATED_DECLARATIONS @@ -166,3 +169,87 @@ unibi_term *terminfo_from_builtin(const char *term, char **termname) unibi_set_bool(ut, unibi_back_color_erase, false); return ut; } + +/// Dumps termcap info to the messages area. +/// Serves a similar purpose as Vim `:set termcap` (removed in Nvim). +/// +/// @note adapted from unibilium unibi-dump.c +void terminfo_info_msg(const unibi_term *const ut) +{ + if (exiting) { + return; + } + msg_puts_title("\n\n--- Terminal info --- {{{\n"); + + char *term; + get_tty_option("term", &term); + msg_printf_attr(0, "&term: %s\n", term); + msg_printf_attr(0, "Description: %s\n", unibi_get_name(ut)); + const char **a = unibi_get_aliases(ut); + if (*a) { + msg_puts("Aliases: "); + do { + msg_printf_attr(0, "%s%s\n", *a, a[1] ? " | " : ""); + a++; + } while (*a); + } + + msg_puts("Boolean capabilities:\n"); + for (enum unibi_boolean i = unibi_boolean_begin_ + 1; + i < unibi_boolean_end_; i++) { + msg_printf_attr(0, " %-25s %-10s = %s\n", unibi_name_bool(i), + unibi_short_name_bool(i), + unibi_get_bool(ut, i) ? "true" : "false"); + } + + msg_puts("Numeric capabilities:\n"); + for (enum unibi_numeric i = unibi_numeric_begin_ + 1; + i < unibi_numeric_end_; i++) { + int n = unibi_get_num(ut, i); // -1 means "empty" + msg_printf_attr(0, " %-25s %-10s = %hd\n", unibi_name_num(i), + unibi_short_name_num(i), n); + } + + msg_puts("String capabilities:\n"); + for (enum unibi_string i = unibi_string_begin_ + 1; + i < unibi_string_end_; i++) { + const char *s = unibi_get_str(ut, i); + if (s) { + msg_printf_attr(0, " %-25s %-10s = ", unibi_name_str(i), + unibi_short_name_str(i)); + // Most of these strings will contain escape sequences. + msg_outtrans_special((char_u *)s, false); + msg_putchar('\n'); + } + } + + if (unibi_count_ext_bool(ut)) { + msg_puts("Extended boolean capabilities:\n"); + for (size_t i = 0; i < unibi_count_ext_bool(ut); i++) { + msg_printf_attr(0, " %-25s = %s\n", + unibi_get_ext_bool_name(ut, i), + unibi_get_ext_bool(ut, i) ? "true" : "false"); + } + } + + if (unibi_count_ext_num(ut)) { + msg_puts("Extended numeric capabilities:\n"); + for (size_t i = 0; i < unibi_count_ext_num(ut); i++) { + msg_printf_attr(0, " %-25s = %hd\n", + unibi_get_ext_num_name(ut, i), + unibi_get_ext_num(ut, i)); + } + } + + if (unibi_count_ext_str(ut)) { + msg_puts("Extended string capabilities:\n"); + for (size_t i = 0; i < unibi_count_ext_str(ut); i++) { + msg_printf_attr(0, " %-25s = ", unibi_get_ext_str_name(ut, i)); + msg_outtrans_special((char_u *)unibi_get_ext_str(ut, i), false); + msg_putchar('\n'); + } + } + + msg_puts("}}}\n"); + xfree(term); +} diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 2436295ad4..6e2a5cbe67 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -96,6 +96,7 @@ typedef struct { bool immediate_wrap_after_last_column; bool mouse_enabled; bool busy, is_invisible; + bool cork, overflow; cursorentry_T cursor_shapes[SHAPE_IDX_COUNT]; HlAttrs print_attrs; bool default_attr; @@ -200,6 +201,8 @@ static void terminfo_start(UI *ui) data->default_attr = false; data->is_invisible = true; data->busy = false; + data->cork = false; + data->overflow = false; data->showing_mode = SHAPE_IDX_N; data->unibi_ext.enable_mouse = -1; data->unibi_ext.disable_mouse = -1; @@ -294,7 +297,7 @@ static void terminfo_stop(UI *ui) unibi_out_ext(ui, data->unibi_ext.disable_bracketed_paste); // Disable focus reporting unibi_out_ext(ui, data->unibi_ext.disable_focus_reporting); - flush_buf(ui, true); + flush_buf(ui); uv_tty_reset_mode(); uv_close((uv_handle_t *)&data->output_handle, NULL); uv_run(&data->write_loop, UV_RUN_DEFAULT); @@ -354,10 +357,12 @@ static void tui_main(UIBridgeData *bridge, UI *ui) tui_terminal_start(ui); data->stop = false; - // allow the main thread to continue, we are ready to start handling UI - // callbacks + // Allow main thread to continue, we are ready to handle UI callbacks. CONTINUE(bridge); + loop_schedule_deferred(&main_loop, + event_create(show_termcap_event, 1, data->ut)); + while (!data->stop) { loop_poll_events(&tui_loop, -1); // tui_loop.events is never processed } @@ -1058,7 +1063,25 @@ static void tui_flush(UI *ui) cursor_goto(ui, saved_row, saved_col); - flush_buf(ui, true); + flush_buf(ui); +} + +/// Dumps termcap info to the messages area, if 'verbose' >= 3. +static void show_termcap_event(void **argv) +{ + if (p_verbose < 3) { + return; + } + const unibi_term *const ut = argv[0]; + if (!ut) { + abort(); + } + verbose_enter(); + // XXX: (future) if unibi_term is modified (e.g. after a terminal + // query-response) this is a race condition. + terminfo_info_msg(ut); + verbose_leave(); + verbose_stop(); // flush now } #ifdef UNIX @@ -1219,8 +1242,18 @@ static void unibi_goto(UI *ui, int row, int col) } \ if (str) { \ unibi_var_t vars[26 + 26]; \ + size_t orig_pos = data->bufpos; \ + \ memset(&vars, 0, sizeof(vars)); \ + data->cork = true; \ +retry: \ unibi_format(vars, vars + 26, str, data->params, out, ui, NULL, NULL); \ + if (data->overflow) { \ + data->bufpos = orig_pos; \ + flush_buf(ui); \ + goto retry; \ + } \ + data->cork = false; \ } \ } while (0) static void unibi_out(UI *ui, int unibi_index) @@ -1239,8 +1272,17 @@ static void out(void *ctx, const char *str, size_t len) TUIData *data = ui->data; size_t available = sizeof(data->buf) - data->bufpos; + if (data->cork && data->overflow) { + return; + } + if (len > available) { - flush_buf(ui, false); + if (data->cork) { + data->overflow = true; + return; + } else { + flush_buf(ui); + } } memcpy(data->buf + data->bufpos, str, len); @@ -1460,19 +1502,18 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, } } - // Some terminals cannot be trusted to report DECSCUSR support. So we keep - // blacklist for when we should not trust the reported features. - if (!((vte_version != 0 && vte_version < 3900) || konsole)) { - // Dickey ncurses terminfo has included the Ss and Se capabilities, - // pioneered by tmux, since 2011-07-14. So adding them to terminal types, - // that do actually have such control sequences but lack the correct - // definitions in terminfo, is a fixup, not an augmentation. + // Blacklist of terminals that cannot be trusted to report DECSCUSR support. + if (!(st || (vte_version != 0 && vte_version < 3900) || konsole)) { data->unibi_ext.reset_cursor_style = unibi_find_ext_str(ut, "Se"); data->unibi_ext.set_cursor_style = unibi_find_ext_str(ut, "Ss"); } + + // Dickey ncurses terminfo includes Ss/Se capabilities since 2011-07-14. So + // adding them to terminal types, that have such control sequences but lack + // the correct terminfo entries, is a fixup, not an augmentation. if (-1 == data->unibi_ext.set_cursor_style) { - // The DECSCUSR sequence to change the cursor shape is widely supported by - // several terminal types. https://github.com/gnachman/iTerm2/pull/92 + // DECSCUSR (cursor shape) sequence is widely supported by several terminal + // types. https://github.com/gnachman/iTerm2/pull/92 // xterm extension: vertical bar if (!konsole && ((xterm && !vte_version) // anything claiming xterm compat // per MinTTY 0.4.3-1 release notes from 2009 @@ -1482,6 +1523,7 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, || tmux // per tmux manual page // https://lists.gnu.org/archive/html/screen-devel/2013-03/msg00000.html || screen + || st // #7641 || rxvt // per command.C // per analysis of VT100Terminal.m || iterm || iterm_pretending_xterm @@ -1577,11 +1619,13 @@ static void augment_terminfo(TUIData *data, const char *term, || konsole // per commentary in VT102Emulation.cpp || teraterm // per TeraTerm "Supported Control Functions" doco || rxvt) { // per command.C - data->unibi_ext.resize_screen = (int)unibi_add_ext_str(ut, NULL, + data->unibi_ext.resize_screen = (int)unibi_add_ext_str(ut, + "ext.resize_screen", "\x1b[8;%p1%d;%p2%dt"); } if (putty || xterm || rxvt) { - data->unibi_ext.reset_scroll_region = (int)unibi_add_ext_str(ut, NULL, + data->unibi_ext.reset_scroll_region = (int)unibi_add_ext_str(ut, + "ext.reset_scroll_region", "\x1b[r"); } @@ -1639,25 +1683,33 @@ static void augment_terminfo(TUIData *data, const char *term, /// Terminals usually ignore unrecognized private modes, and there is no /// known ambiguity with these. So we just set them unconditionally. - data->unibi_ext.enable_lr_margin = (int)unibi_add_ext_str(ut, NULL, + data->unibi_ext.enable_lr_margin = (int)unibi_add_ext_str(ut, + "ext.enable_lr_margin", "\x1b[?69h"); - data->unibi_ext.disable_lr_margin = (int)unibi_add_ext_str(ut, NULL, + data->unibi_ext.disable_lr_margin = (int)unibi_add_ext_str(ut, + "ext.disable_lr_margin", "\x1b[?69l"); - data->unibi_ext.enable_bracketed_paste = (int)unibi_add_ext_str(ut, NULL, + data->unibi_ext.enable_bracketed_paste = (int)unibi_add_ext_str(ut, + "ext.enable_bpaste", "\x1b[?2004h"); - data->unibi_ext.disable_bracketed_paste = (int)unibi_add_ext_str(ut, NULL, + data->unibi_ext.disable_bracketed_paste = (int)unibi_add_ext_str(ut, + "ext.disable_bpaste", "\x1b[?2004l"); - data->unibi_ext.enable_focus_reporting = (int)unibi_add_ext_str(ut, NULL, + data->unibi_ext.enable_focus_reporting = (int)unibi_add_ext_str(ut, + "ext.enable_focus", rxvt ? "\x1b]777;focus;on\x7" : "\x1b[?1004h"); - data->unibi_ext.disable_focus_reporting = (int)unibi_add_ext_str(ut, NULL, + data->unibi_ext.disable_focus_reporting = (int)unibi_add_ext_str(ut, + "ext.disable_focus", rxvt ? "\x1b]777;focus;off\x7" : "\x1b[?1004l"); - data->unibi_ext.enable_mouse = (int)unibi_add_ext_str(ut, NULL, + data->unibi_ext.enable_mouse = (int)unibi_add_ext_str(ut, + "ext.enable_mouse", "\x1b[?1002h\x1b[?1006h"); - data->unibi_ext.disable_mouse = (int)unibi_add_ext_str(ut, NULL, + data->unibi_ext.disable_mouse = (int)unibi_add_ext_str(ut, + "ext.disable_mouse", "\x1b[?1002l\x1b[?1006l"); } -static void flush_buf(UI *ui, bool toggle_cursor) +static void flush_buf(UI *ui) { uv_write_t req; uv_buf_t bufs[3]; @@ -1668,7 +1720,7 @@ static void flush_buf(UI *ui, bool toggle_cursor) return; } - if (toggle_cursor && !data->is_invisible) { + if (!data->is_invisible) { // cursor is visible. Write a "cursor invisible" command before writing the // buffer. bufp->base = data->invis; @@ -1683,7 +1735,7 @@ static void flush_buf(UI *ui, bool toggle_cursor) bufp++; } - if (toggle_cursor && !data->busy && data->is_invisible) { + if (!data->busy && data->is_invisible) { // not busy and the cursor is invisible. Write a "cursor normal" command // after writing the buffer. bufp->base = data->norm; @@ -1696,6 +1748,7 @@ static void flush_buf(UI *ui, bool toggle_cursor) bufs, (unsigned)(bufp - bufs), NULL); uv_run(&data->write_loop, UV_RUN_DEFAULT); data->bufpos = 0; + data->overflow = false; } #if TERMKEY_VERSION_MAJOR > 0 || TERMKEY_VERSION_MINOR > 18 diff --git a/src/nvim/ui_bridge.c b/src/nvim/ui_bridge.c index 5585886612..7573fa1653 100644 --- a/src/nvim/ui_bridge.c +++ b/src/nvim/ui_bridge.c @@ -82,6 +82,7 @@ UI *ui_bridge_attach(UI *ui, ui_main_fn ui_main, event_scheduler scheduler) abort(); } + // Suspend the main thread until CONTINUE is called by the UI thread. while (!rv->ready) { uv_cond_wait(&rv->cond, &rv->mutex); } @@ -149,7 +150,7 @@ static void ui_bridge_suspend(UI *b) uv_mutex_lock(&data->mutex); UI_BRIDGE_CALL(b, suspend, 1, b); data->ready = false; - // suspend the main thread until CONTINUE is called by the UI thread + // Suspend the main thread until CONTINUE is called by the UI thread. while (!data->ready) { uv_cond_wait(&data->cond, &data->mutex); } diff --git a/test/functional/eval/null_spec.lua b/test/functional/eval/null_spec.lua index 6fd30caec9..b67158eb22 100644 --- a/test/functional/eval/null_spec.lua +++ b/test/functional/eval/null_spec.lua @@ -42,14 +42,6 @@ describe('NULL', function() describe('list', function() -- Incorrect behaviour - -- FIXME map() should not return 0 without error - null_expr_test('does not crash map()', 'map(L, "v:val")', 0, 0) - -- FIXME map() should not return 0 without error - null_expr_test('does not crash filter()', 'filter(L, "1")', 0, 0) - -- FIXME map() should at least return L - null_expr_test('makes map() return v:_null_list', 'map(L, "v:val") is# L', 0, 0) - -- FIXME filter() should at least return L - null_expr_test('makes filter() return v:_null_list', 'map(L, "1") is# L', 0, 0) -- FIXME add() should not return 1 at all null_expr_test('does not crash add()', 'add(L, 0)', 0, 1) null_expr_test('does not crash extend()', 'extend(L, [1])', 'E742: Cannot change value of extend() argument', 0) @@ -111,6 +103,8 @@ describe('NULL', function() null_expr_test('does not crash line()', 'line(L)', 0, 0) null_expr_test('does not crash count()', 'count(L, 1)', 0, 0) null_expr_test('does not crash cursor()', 'cursor(L)', 'E474: Invalid argument', -1) + null_expr_test('does not crash map()', 'map(L, "v:val")', 0, {}) + null_expr_test('does not crash filter()', 'filter(L, "1")', 0, {}) null_expr_test('is empty', 'empty(L)', 0, 1) null_expr_test('does not crash get()', 'get(L, 1, 10)', 0, 10) null_expr_test('has zero length', 'len(L)', 0, 0) @@ -126,6 +120,8 @@ describe('NULL', function() null_expr_test('is equal to itself', 'L == L', 0, 1) null_expr_test('is not not equal to itself', 'L != L', 0, 0) null_expr_test('counts correctly', 'count([L], L)', 0, 1) + null_expr_test('makes map() return v:_null_list', 'map(L, "v:val") is# L', 0, 1) + null_expr_test('makes filter() return v:_null_list', 'filter(L, "1") is# L', 0, 1) end) describe('dict', function() it('does not crash when indexing NULL dict', function() @@ -134,5 +130,9 @@ describe('NULL', function() end) null_expr_test('makes extend error out', 'extend(D, {})', 'E742: Cannot change value of extend() argument', 0) null_expr_test('makes extend do nothing', 'extend({1: 2}, D)', 0, {['1']=2}) + null_expr_test('does not crash map()', 'map(D, "v:val")', 0, {}) + null_expr_test('does not crash filter()', 'filter(D, "1")', 0, {}) + null_expr_test('makes map() return v:_null_dict', 'map(D, "v:val") is# D', 0, 1) + null_expr_test('makes filter() return v:_null_dict', 'filter(D, "1") is# D', 0, 1) end) end) diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index da334d4ac6..f939567693 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -261,6 +261,7 @@ local function retry(max, max_ms, fn) if status then return result end + luv.update_time() -- Update cached value of luv.now() (libuv: uv_now()). if (max and tries >= max) or (luv.now() - start_time > timeout) then if type(result) == "string" then result = "\nretry() attempts: "..tostring(tries).."\n"..result @@ -333,8 +334,8 @@ local function feed_command(...) end -- Dedent the given text and write it to the file name. -local function write_file(name, text, dont_dedent) - local file = io.open(name, 'w') +local function write_file(name, text, no_dedent, append) + local file = io.open(name, (append and 'a' or 'w')) if type(text) == 'table' then -- Byte blob local bytes = text @@ -342,7 +343,7 @@ local function write_file(name, text, dont_dedent) for _, char in ipairs(bytes) do text = ('%s%c'):format(text, char) end - elseif not dont_dedent then + elseif not no_dedent then text = dedent(text) end file:write(text) diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index d5f6a21d1d..bf3c6bdb3a 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -4,6 +4,7 @@ local global_helpers = require('test.helpers') local uname = global_helpers.uname local helpers = require('test.functional.helpers')(after_each) local thelpers = require('test.functional.terminal.helpers') +local eq = helpers.eq local feed_data = thelpers.feed_data local feed_command = helpers.feed_command local clear = helpers.clear @@ -11,6 +12,8 @@ local nvim_dir = helpers.nvim_dir local retry = helpers.retry local nvim_prog = helpers.nvim_prog local nvim_set = helpers.nvim_set +local ok = helpers.ok +local read_file = helpers.read_file if helpers.pending_win32(pending) then return end @@ -21,9 +24,6 @@ describe('tui', function() clear() screen = thelpers.screen_setup(0, '["'..nvim_prog ..'", "-u", "NONE", "-i", "NONE", "--cmd", "set noswapfile noshowcmd noruler undodir=. directory=. viewdir=. backupdir=."]') - -- right now pasting can be really slow in the TUI, especially in ASAN. - -- this will be fixed later but for now we require a high timeout. - screen.timeout = 60000 screen:expect([[ {1: } | {4:~ }| @@ -125,6 +125,9 @@ describe('tui', function() end) it('automatically sends <Paste> for bracketed paste sequences', function() + -- Pasting can be really slow in the TUI, specially in ASAN. + -- This will be fixed later but for now we require a high timeout. + screen.timeout = 60000 feed_data('i\027[200~') screen:expect([[ {1: } | @@ -158,6 +161,8 @@ describe('tui', function() end) it('can handle arbitrarily long bursts of input', function() + -- Need extra time for this test, specially in ASAN. + screen.timeout = 60000 feed_command('set ruler') local t = {} for i = 1, 3000 do @@ -639,6 +644,7 @@ end) describe("tui 'term' option", function() local screen local is_bsd = not not string.find(string.lower(uname()), 'bsd') + local is_macos = not not string.find(string.lower(uname()), 'darwin') local function assert_term(term_envvar, term_expected) clear() @@ -664,11 +670,62 @@ describe("tui 'term' option", function() end) it('gets system-provided term if $TERM is valid', function() - if is_bsd then -- BSD lacks terminfo, we always use builtin there. + if is_bsd then -- BSD lacks terminfo, builtin is always used. assert_term("xterm", "builtin_xterm") + elseif is_macos then + local status, _ = pcall(assert_term, "xterm", "xterm") + if not status then + pending("macOS: unibilium could not find terminfo", function() end) + end else assert_term("xterm", "xterm") end end) end) + +-- These tests require `thelpers` because --headless/--embed +-- does not initialize the TUI. +describe("tui", function() + local screen + local logfile = 'Xtest_tui_verbose_log' + after_each(function() + os.remove(logfile) + end) + + -- Runs (child) `nvim` in a TTY (:terminal), to start the builtin TUI. + local function nvim_tui(extra_args) + clear() + -- This is ugly because :term/termopen() forces TERM=xterm-256color. + -- TODO: Revisit this after jobstart/termopen accept `env` dict. + local cmd = string.format( + [=[['sh', '-c', 'LANG=C %s -u NONE -i NONE %s --cmd "%s"']]=], + nvim_prog, + extra_args or "", + nvim_set) + screen = thelpers.screen_setup(0, cmd) + end + + it('-V3log logs terminfo values', function() + nvim_tui('-V3'..logfile) + + -- Wait for TUI to start. + feed_data('Gitext') + screen:expect([[ + text{1: } | + {4:~ }| + {4:~ }| + {4:~ }| + {4:~ }| + {3:-- INSERT --} | + {3:-- TERMINAL --} | + ]]) + + retry(nil, 3000, function() -- Wait for log file to be flushed. + local log = read_file('Xtest_tui_verbose_log') or '' + eq('--- Terminal info --- {{{\n', string.match(log, '--- Terminal.-\n')) + ok(#log > 50) + end) + end) + +end) diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 136ab09d4f..d15afc81bb 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -10,12 +10,19 @@ describe('external cmdline', function() local last_level = 0 local cmdline = {} local block = nil + local wild_items = nil + local wild_selected = nil before_each(function() clear() cmdline, block = {}, nil screen = Screen.new(25, 5) screen:attach({rgb=true, ext_cmdline=true}) + screen:set_default_attr_ids({ + [1] = {bold = true, foreground = Screen.colors.Blue1}, + [2] = {reverse = true}, + [3] = {bold = true, reverse = true}, + }) screen:set_on_event_handler(function(name, data) if name == "cmdline_show" then local content, pos, firstc, prompt, indent, level = unpack(data) @@ -38,6 +45,12 @@ describe('external cmdline', function() block[#block+1] = data[1] elseif name == "cmdline_block_hide" then block = nil + elseif name == "wildmenu_show" then + wild_items = data[1] + elseif name == "wildmenu_select" then + wild_selected = data[1] + elseif name == "wildmenu_hide" then + wild_items, wild_selected = nil, nil end end) end) @@ -66,9 +79,9 @@ describe('external cmdline', function() feed(':') screen:expect([[ ^ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| | ]], nil, nil, function() eq(1, last_level) @@ -84,9 +97,9 @@ describe('external cmdline', function() feed('sign') screen:expect([[ ^ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| | ]], nil, nil, function() eq({{ @@ -101,9 +114,9 @@ describe('external cmdline', function() feed('<Left>') screen:expect([[ ^ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| | ]], nil, nil, function() eq({{ @@ -118,9 +131,9 @@ describe('external cmdline', function() feed('<bs>') screen:expect([[ ^ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| | ]], nil, nil, function() eq({{ @@ -135,9 +148,9 @@ describe('external cmdline', function() feed('<Esc>') screen:expect([[ ^ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| | ]], nil, nil, function() eq({}, cmdline) @@ -148,9 +161,9 @@ describe('external cmdline', function() feed(':call input("input", "default")<cr>') screen:expect([[ ^ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| | ]], nil, nil, function() eq({{ @@ -164,9 +177,9 @@ describe('external cmdline', function() feed('<cr>') screen:expect([[ ^ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| | ]], nil, nil, function() eq({}, cmdline) @@ -178,9 +191,9 @@ describe('external cmdline', function() feed(':xx<c-r>') screen:expect([[ ^ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| | ]], nil, nil, function() eq({{ @@ -196,9 +209,9 @@ describe('external cmdline', function() feed('=') screen:expect([[ ^ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| | ]], nil, nil, function() eq({{ @@ -238,9 +251,9 @@ describe('external cmdline', function() }} screen:expect([[ ^ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| | ]], nil, nil, function() eq(expectation, cmdline) @@ -253,9 +266,9 @@ describe('external cmdline', function() -- focus is at external cmdline anyway. screen:expect([[ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| ^ | ]], nil, nil, function() eq(expectation, cmdline) @@ -265,9 +278,9 @@ describe('external cmdline', function() feed('<cr>') screen:expect([[ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| ^ | ]], nil, nil, function() eq({{ @@ -282,9 +295,9 @@ describe('external cmdline', function() feed('<esc>') screen:expect([[ ^ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| | ]], nil, nil, function() eq({}, cmdline) @@ -295,9 +308,9 @@ describe('external cmdline', function() feed(':function Foo()<cr>') screen:expect([[ ^ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| | ]], nil, nil, function() eq({{ @@ -313,9 +326,9 @@ describe('external cmdline', function() feed('line1<cr>') screen:expect([[ ^ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| | ]], nil, nil, function() eq({ { { {}, 'function Foo()'} }, @@ -326,9 +339,9 @@ describe('external cmdline', function() command("redraw!") screen:expect([[ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| ^ | ]], nil, nil, function() eq({ { { {}, 'function Foo()'} }, @@ -339,9 +352,9 @@ describe('external cmdline', function() feed('endfunction<cr>') screen:expect([[ ^ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| | ]], nil, nil, function() eq(nil, block) @@ -352,9 +365,9 @@ describe('external cmdline', function() feed(':make') screen:expect([[ ^ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| | ]], nil, nil, function() eq({{ @@ -369,9 +382,9 @@ describe('external cmdline', function() feed('<c-f>') screen:expect([[ | - [No Name] | - :make^ | - [Command Line] | + {2:[No Name] }| + {1::}make^ | + {3:[Command Line] }| | ]], nil, nil, function() eq({}, cmdline) @@ -381,9 +394,9 @@ describe('external cmdline', function() feed(':yank') screen:expect([[ | - [No Name] | - :make^ | - [Command Line] | + {2:[No Name] }| + {1::}make^ | + {3:[Command Line] }| | ]], nil, nil, function() eq({nil, { @@ -399,9 +412,9 @@ describe('external cmdline', function() command("redraw!") screen:expect([[ | - [No Name] | - :make | - [Command Line] | + {2:[No Name] }| + {1::}make | + {3:[Command Line] }| ^ | ]], nil, nil, function() eq({nil, { @@ -416,9 +429,9 @@ describe('external cmdline', function() feed("<c-c>") screen:expect([[ | - [No Name] | - :make^ | - [Command Line] | + {2:[No Name] }| + {1::}make^ | + {3:[Command Line] }| | ]], nil, nil, function() eq({}, cmdline) @@ -427,9 +440,9 @@ describe('external cmdline', function() feed("<c-c>") screen:expect([[ | - [No Name] | - :make^ | - [Command Line] | + {2:[No Name] }| + {1::}make^ | + {3:[Command Line] }| | ]], nil, nil, function() eq({{ @@ -445,9 +458,9 @@ describe('external cmdline', function() command("redraw!") screen:expect([[ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| ^ | ]], nil, nil, function() eq({{ @@ -464,9 +477,9 @@ describe('external cmdline', function() feed(":call inputsecret('secret:')<cr>abc123") screen:expect([[ ^ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| | ]], nil, nil, function() eq({{ @@ -480,50 +493,160 @@ describe('external cmdline', function() end) it('works with highlighted cmdline', function() - source([[ - highlight RBP1 guibg=Red - highlight RBP2 guibg=Yellow - highlight RBP3 guibg=Green - highlight RBP4 guibg=Blue - let g:NUM_LVLS = 4 - function RainBowParens(cmdline) - let ret = [] - let i = 0 - let lvl = 0 - while i < len(a:cmdline) - if a:cmdline[i] is# '(' - call add(ret, [i, i + 1, 'RBP' . ((lvl % g:NUM_LVLS) + 1)]) - let lvl += 1 - elseif a:cmdline[i] is# ')' - let lvl -= 1 - call add(ret, [i, i + 1, 'RBP' . ((lvl % g:NUM_LVLS) + 1)]) - endif - let i += 1 - endwhile - return ret - endfunction - map <f5> :let x = input({'prompt':'>','highlight':'RainBowParens'})<cr> - "map <f5> :let x = input({'prompt':'>'})<cr> - ]]) - screen:set_default_attr_ids({ - RBP1={background = Screen.colors.Red}, - RBP2={background = Screen.colors.Yellow}, - RBP3={background = Screen.colors.Green}, - RBP4={background = Screen.colors.Blue}, - EOB={bold = true, foreground = Screen.colors.Blue1}, - ERR={foreground = Screen.colors.Grey100, background = Screen.colors.Red}, - SK={foreground = Screen.colors.Blue}, - PE={bold = true, foreground = Screen.colors.SeaGreen4} - }) - feed('<f5>(a(b)a)') - screen:expect([[ - ^ | - {EOB:~ }| - {EOB:~ }| - {EOB:~ }| - | - ]], nil, nil, function() - expect_cmdline(1, '{RBP1:(}a{RBP2:(}b{RBP2:)}a{RBP1:)}') - end) + source([[ + highlight RBP1 guibg=Red + highlight RBP2 guibg=Yellow + highlight RBP3 guibg=Green + highlight RBP4 guibg=Blue + let g:NUM_LVLS = 4 + function RainBowParens(cmdline) + let ret = [] + let i = 0 + let lvl = 0 + while i < len(a:cmdline) + if a:cmdline[i] is# '(' + call add(ret, [i, i + 1, 'RBP' . ((lvl % g:NUM_LVLS) + 1)]) + let lvl += 1 + elseif a:cmdline[i] is# ')' + let lvl -= 1 + call add(ret, [i, i + 1, 'RBP' . ((lvl % g:NUM_LVLS) + 1)]) + endif + let i += 1 + endwhile + return ret + endfunction + map <f5> :let x = input({'prompt':'>','highlight':'RainBowParens'})<cr> + "map <f5> :let x = input({'prompt':'>'})<cr> + ]]) + screen:set_default_attr_ids({ + RBP1={background = Screen.colors.Red}, + RBP2={background = Screen.colors.Yellow}, + RBP3={background = Screen.colors.Green}, + RBP4={background = Screen.colors.Blue}, + EOB={bold = true, foreground = Screen.colors.Blue1}, + ERR={foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + SK={foreground = Screen.colors.Blue}, + PE={bold = true, foreground = Screen.colors.SeaGreen4} + }) + feed('<f5>(a(b)a)') + screen:expect([[ + ^ | + {EOB:~ }| + {EOB:~ }| + {EOB:~ }| + | + ]], nil, nil, function() + expect_cmdline(1, '{RBP1:(}a{RBP2:(}b{RBP2:)}a{RBP1:)}') + end) + end) + + it('works together with ext_wildmenu', function() + local expected = { + 'define', + 'jump', + 'list', + 'place', + 'undefine', + 'unplace', + } + + command('set wildmode=full') + command('set wildmenu') + screen:set_option('ext_wildmenu', true) + feed(':sign <tab>') + + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]], nil, nil, function() + eq({{ + content = { { {}, "sign define"} }, + firstc = ":", + indent = 0, + pos = 11, + prompt = "" + }}, cmdline) + eq(expected, wild_items) + eq(0, wild_selected) + end) + + feed('<tab>') + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]], nil, nil, function() + eq({{ + content = { { {}, "sign jump"} }, + firstc = ":", + indent = 0, + pos = 9, + prompt = "" + }}, cmdline) + eq(expected, wild_items) + eq(1, wild_selected) + end) + + feed('<left><left>') + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]], nil, nil, function() + eq({{ + content = { { {}, "sign "} }, + firstc = ":", + indent = 0, + pos = 5, + prompt = "" + }}, cmdline) + eq(expected, wild_items) + eq(-1, wild_selected) + end) + + feed('<right>') + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]], nil, nil, function() + eq({{ + content = { { {}, "sign define"} }, + firstc = ":", + indent = 0, + pos = 11, + prompt = "" + }}, cmdline) + eq(expected, wild_items) + eq(0, wild_selected) + end) + + feed('a') + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]], nil, nil, function() + eq({{ + content = { { {}, "sign definea"} }, + firstc = ":", + indent = 0, + pos = 12, + prompt = "" + }}, cmdline) + eq(nil, wild_items) + eq(nil, wild_selected) + end) end) end) diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index a6b7fb2997..075d8c40d7 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -176,6 +176,10 @@ function Screen:try_resize(columns, rows) self:sleep(0.1) end +function Screen:set_option(option, value) + uimeths.set_option(option, value) +end + -- Asserts that `expected` eventually matches the screen state. -- -- expected: Expected screen state (string). Each line represents a screen diff --git a/third-party/cmake/BuildLuarocks.cmake b/third-party/cmake/BuildLuarocks.cmake index ef8a8450f1..c7b7f8d837 100644 --- a/third-party/cmake/BuildLuarocks.cmake +++ b/third-party/cmake/BuildLuarocks.cmake @@ -96,8 +96,7 @@ if(USE_BUNDLED_LUAJIT) endif() endif() -# Each target depends on the previous module, this serializes all calls to -# luarocks since it is unhappy to be called in parallel. +# DEPENDS on the previous module, because Luarocks breaks if parallel. add_custom_command(OUTPUT ${HOSTDEPS_LIB_DIR}/luarocks/rocks/mpack COMMAND ${LUAROCKS_BINARY} ARGS build mpack ${LUAROCKS_BUILDARGS} @@ -106,7 +105,7 @@ add_custom_target(mpack DEPENDS ${HOSTDEPS_LIB_DIR}/luarocks/rocks/mpack) list(APPEND THIRD_PARTY_DEPS mpack) - +# DEPENDS on the previous module, because Luarocks breaks if parallel. add_custom_command(OUTPUT ${HOSTDEPS_LIB_DIR}/luarocks/rocks/lpeg COMMAND ${LUAROCKS_BINARY} ARGS build lpeg ${LUAROCKS_BUILDARGS} @@ -116,16 +115,18 @@ add_custom_target(lpeg list(APPEND THIRD_PARTY_DEPS lpeg) +# DEPENDS on the previous module, because Luarocks breaks if parallel. add_custom_command(OUTPUT ${HOSTDEPS_LIB_DIR}/luarocks/rocks/inspect COMMAND ${LUAROCKS_BINARY} ARGS build inspect ${LUAROCKS_BUILDARGS} - DEPENDS mpack) + DEPENDS lpeg) add_custom_target(inspect DEPENDS ${HOSTDEPS_LIB_DIR}/luarocks/rocks/inspect) list(APPEND THIRD_PARTY_DEPS inspect) if(USE_BUNDLED_BUSTED) + # DEPENDS on the previous module, because Luarocks breaks if parallel. add_custom_command(OUTPUT ${HOSTDEPS_LIB_DIR}/luarocks/rocks/penlight/1.3.2-2 COMMAND ${LUAROCKS_BINARY} ARGS build penlight 1.3.2-2 ${LUAROCKS_BUILDARGS} @@ -138,6 +139,7 @@ if(USE_BUNDLED_BUSTED) else() set(BUSTED_EXE "${HOSTDEPS_BIN_DIR}/busted") endif() + # DEPENDS on the previous module, because Luarocks breaks if parallel. add_custom_command(OUTPUT ${BUSTED_EXE} COMMAND ${LUAROCKS_BINARY} ARGS build https://raw.githubusercontent.com/Olivine-Labs/busted/v2.0.rc12-1/busted-2.0.rc12-1.rockspec ${LUAROCKS_BUILDARGS} @@ -145,6 +147,7 @@ if(USE_BUNDLED_BUSTED) add_custom_target(busted DEPENDS ${BUSTED_EXE}) + # DEPENDS on the previous module, because Luarocks breaks if parallel. add_custom_command(OUTPUT ${HOSTDEPS_BIN_DIR}/luacheck COMMAND ${LUAROCKS_BINARY} ARGS build https://raw.githubusercontent.com/mpeterv/luacheck/master/luacheck-scm-1.rockspec ${LUAROCKS_BUILDARGS} @@ -160,6 +163,7 @@ if(USE_BUNDLED_BUSTED) if(USE_BUNDLED_LIBUV) list(APPEND LUV_ARGS LIBUV_DIR=${HOSTDEPS_INSTALL_DIR}) endif() + # DEPENDS on the previous module, because Luarocks breaks if parallel. add_custom_command(OUTPUT ${HOSTDEPS_LIB_DIR}/luarocks/rocks/luv COMMAND ${LUAROCKS_BINARY} ARGS make ${LUAROCKS_BUILDARGS} ${LUV_ARGS} @@ -168,6 +172,7 @@ if(USE_BUNDLED_BUSTED) add_custom_target(luv DEPENDS ${HOSTDEPS_LIB_DIR}/luarocks/rocks/luv) + # DEPENDS on the previous module, because Luarocks breaks if parallel. add_custom_command(OUTPUT ${HOSTDEPS_LIB_DIR}/luarocks/rocks/nvim-client COMMAND ${LUAROCKS_BINARY} ARGS build https://raw.githubusercontent.com/neovim/lua-client/0.0.1-26/nvim-client-0.0.1-26.rockspec ${LUAROCKS_BUILDARGS} |