diff options
60 files changed, 887 insertions, 416 deletions
@@ -1198,18 +1198,28 @@ def CheckForMultilineCommentsAndStrings(filename, clean_lines, linenum, error): threading_list = ( - ('asctime(', 'asctime_r('), - ('ctime(', 'ctime_r('), - ('getgrgid(', 'getgrgid_r('), - ('getgrnam(', 'getgrnam_r('), - ('getlogin(', 'getlogin_r('), - ('getpwnam(', 'getpwnam_r('), - ('getpwuid(', 'getpwuid_r('), - ('gmtime(', 'gmtime_r('), - ('localtime(', 'localtime_r('), - ('rand(', 'rand_r('), - ('strtok(', 'strtok_r('), - ('ttyname(', 'ttyname_r('), + ('asctime(', 'os_asctime_r('), + ('ctime(', 'os_ctime_r('), + ('getgrgid(', 'os_getgrgid_r('), + ('getgrnam(', 'os_getgrnam_r('), + ('getlogin(', 'os_getlogin_r('), + ('getpwnam(', 'os_getpwnam_r('), + ('getpwuid(', 'os_getpwuid_r('), + ('gmtime(', 'os_gmtime_r('), + ('localtime(', 'os_localtime_r('), + ('strtok(', 'os_strtok_r('), + ('ttyname(', 'os_ttyname_r('), + ('asctime_r(', 'os_asctime_r('), + ('ctime_r(', 'os_ctime_r('), + ('getgrgid_r(', 'os_getgrgid_r('), + ('getgrnam_r(', 'os_getgrnam_r('), + ('getlogin_r(', 'os_getlogin_r('), + ('getpwnam_r(', 'os_getpwnam_r('), + ('getpwuid_r(', 'os_getpwuid_r('), + ('gmtime_r(', 'os_gmtime_r('), + ('localtime_r(', 'os_localtime_r('), + ('strtok_r(', 'os_strtok_r('), + ('ttyname_r(', 'os_ttyname_r('), ) @@ -1235,9 +1245,10 @@ def CheckPosixThreading(filename, clean_lines, linenum, error): if ix >= 0 and (ix == 0 or (not line[ix - 1].isalnum() and line[ix - 1] not in ('_', '.', '>'))): error(filename, linenum, 'runtime/threadsafe_fn', 2, - 'Consider using ' + multithread_safe_function + + 'Use ' + multithread_safe_function + '...) instead of ' + single_thread_function + - '...) for improved thread safety.') + '...). If it is missing, consider implementing it;' + + ' see os_localtime_r for an example.') # Matches invalid increment: *count++, which moves pointer instead of diff --git a/config/CMakeLists.txt b/config/CMakeLists.txt index aab4b5c23d..a46f686d7c 100644 --- a/config/CMakeLists.txt +++ b/config/CMakeLists.txt @@ -5,6 +5,7 @@ include(CheckIncludeFiles) check_type_size("int" SIZEOF_INT) check_type_size("long" SIZEOF_LONG) +check_type_size("intmax_t" SIZEOF_INTMAX_T) check_type_size("off_t" SIZEOF_OFF_T) check_type_size("void *" SIZEOF_VOID_PTR) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 6ffa37ac39..65b1f2aa3c 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -5100,12 +5100,12 @@ rpcnotify({channel}, {event}[, {args}...]) {Nvim} *rpcnotify()* rpcrequest({channel}, {method}[, {args}...]) {Nvim} *rpcrequest()* Sends a request to {channel} to invoke {method} via |msgpack-rpc| and blocks until a response is received. - Example: > + Example: > :let result = rpcrequest(rpc_chan, "func", 1, 2, 3) rpcstart({prog}[, {argv}]) {Nvim} *rpcstart()* - Spawns {prog} as a job(optionally passing the {argv} list), - and opens a |msgpack-rpc| channel with the spawned process + Spawns {prog} as a job (optionally passing the list {argv}), + and opens a |msgpack-rpc| channel with the spawned process's stdin/stdout. It returns: - The channel id on success, which is used by |rpcrequest()|, |rpcnotify()| and |rpcstop()| @@ -5114,10 +5114,9 @@ rpcstart({prog}[, {argv}]) {Nvim} *rpcstart()* :let rpc_chan = rpcstart('prog', ['arg1', 'arg2']) rpcstop({channel}) {Nvim} *rpcstop()* - Closes a |msgpack-rpc| channel, possibly created via - |rpcstart()| (Though it will also close channels created by - connections to |$NVIM_LISTEN_ADDRESS|). It accepts the rpc - channel id as only argument. + Closes a |msgpack-rpc| {channel}, possibly created via + |rpcstart()|. Also closes channels created by connections to + |$NVIM_LISTEN_ADDRESS|. screenattr(row, col) *screenattr()* Like screenchar(), but return the attribute. This is a rather @@ -6748,7 +6747,6 @@ mouse Compiled with support mouse. mouse_dec Compiled with support for Dec terminal mouse. mouse_gpm Compiled with support for gpm (Linux console mouse) mouse_netterm Compiled with support for netterm mouse. -mouse_pterm Compiled with support for qnx pterm mouse. mouse_sysmouse Compiled with support for sysmouse (*BSD console mouse) mouse_sgr Compiled with support for sgr mouse. mouse_urxvt Compiled with support for urxvt mouse. @@ -6768,7 +6766,6 @@ printer Compiled with |:hardcopy| support. profile Compiled with |:profile| support. python Compiled with Python 2.x interface. |has-python| python3 Compiled with Python 3.x interface. |has-python| -qnx QNX version of Vim. quickfix Compiled with |quickfix| support. reltime Compiled with |reltime()| support. rightleft Compiled with 'rightleft' support. diff --git a/runtime/doc/job_control.txt b/runtime/doc/job_control.txt index f381d5ad66..000409597f 100644 --- a/runtime/doc/job_control.txt +++ b/runtime/doc/job_control.txt @@ -13,7 +13,7 @@ Nvim's facilities for job control *job-control* 1. Introduction *job-control-intro* Job control is a simple way to perform multitasking in vimscript. Wikipedia -contains a more generic/detailed description: +contains a more generic/detailed description: "Job control in computing refers to the control of multiple tasks or Jobs on a computer system, ensuring that they each have access to adequate resources to @@ -27,8 +27,8 @@ control multiple processes without blocking the current Nvim instance. Nvim's job control was designed to be simple and familiar to vimscript programmers, instead of being very powerful but complex. Unlike Vim's -facilities for calling with external commands, job control does not depend -on installed shells, calling OS functions for process management directly. +facilities for calling with external commands, job control does not depend on +available shells, instead relying on OS functionality for process management. Internally, Nvim job control is powered by libuv, which has a nice cross-platform API for managing processes. See https://github.com/libuv/libuv @@ -43,8 +43,8 @@ event. The best way to understand is with a complete example: > set nocp let job1 = jobstart('shell1', 'bash') - let job2 = jobstart('shell2', 'bash', ['-c', 'for ((i = 0; i < 10; i++)); do echo -n hello $i!; sleep 2; done']) - + let job2 = jobstart('shell2', 'bash', ['-c', 'for ((i = 0; i < 10; i++)); do echo hello $i!; sleep 1; done']) + function JobHandler() if v:job_data[1] == 'stdout' let str = 'shell '. v:job_data[0].' stdout: '.join(v:job_data[2]) @@ -53,27 +53,27 @@ event. The best way to understand is with a complete example: else let str = 'shell '.v:job_data[0].' exited' endif - + call append(line('$'), str) endfunction - + au JobActivity shell* call JobHandler() < -To test the above, copy it to the ~/jobcontrol.vim file and start with a clean +To test the above, copy it to the file ~/jobcontrol.vim and start with a clean nvim instance: - > - nvim -u NONE -S ~/jobcontrol.vim +> + nvim -u NONE -S ~/jobcontrol.vim < Here's what is happening: -- Two bash instances are spawned by |jobstart()| and their stdin/stdout/stderr - are connected to nvim. -- The first shell is idle, waiting to read commands from it's stdin -- The second shell is passed the -c option to execute a command and exit. In - our case, the command is a for loop that will print numbers and exit after - a while. -- The JobHandler function is called by the JobActivity autocommand(notice how - the shell* pattern matches the `shell1` and `shell2` names passed to +- Two bash instances are spawned by |jobstart()| with their stdin/stdout/stderr + connected to nvim. +- The first shell is idle, waiting to read commands from its stdin. +- The second shell is started with the -c argument, causing it to execute a + command then exit. In this case, the command is a for loop that will print 0 + through 9 then exit. +- The |JobHandler()| function is called by the `JobActivity` autocommand (notice + how the shell* pattern matches the names `shell1` and `shell2` passed to |jobstart()|), and it takes care of displaying stdout/stderr received from the shells. - The v:job_data is an array set by the JobActivity event. It has the @@ -86,16 +86,16 @@ Here's what is happening: To send data to the job's stdin, one can use the |jobsend()| function, like this: > - :call jobsend(job1, 'ls\n') - :call jobsend(job1, 'invalid-command\n') - :call jobsend(job1, 'exit\n') + :call jobsend(job1, "ls\n") + :call jobsend(job1, "invalid-command\n") + :call jobsend(job1, "exit\n") < A job may be killed at any time with the |jobstop()| function: > :call jobstop(job1) < -When |jobstop()| is called, it will send `SIGTERM` to the job. If a job -doesn't exit after a while, `SIGKILL` will be sent. - +When |jobstop()| is called, `SIGTERM` will be sent to the job. If a job does +not exit after 2 seconds, `SIGKILL` will be sent. + ============================================================================== vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/runtime/doc/msgpack_rpc.txt b/runtime/doc/msgpack_rpc.txt index 0fb419e5d5..af4ef3e132 100644 --- a/runtime/doc/msgpack_rpc.txt +++ b/runtime/doc/msgpack_rpc.txt @@ -4,10 +4,10 @@ NVIM REFERENCE MANUAL by Thiago de Arruda -The Msgpack-RPC Interface to Nvim *msgpack-rpc* +The Msgpack-RPC Interface to Nvim *msgpack-rpc* 1. Introduction |msgpack-rpc-intro| -2. API |msgpack-rpc-api| +2. API |msgpack-rpc-api| 3. Connecting |msgpack-rpc-connecting| 4. Clients |msgpack-rpc-clients| 5. Types |msgpack-rpc-types| @@ -40,9 +40,9 @@ Nvim's msgpack-rpc interface can be seen as a more powerful version of Vim's The Nvim C API is automatically exposed to the msgpack-rpc interface by the build system, which parses headers at src/nvim/api from the project root. A -dispatch function is generated, which matches msgpack-rpc method names -with non-static API functions, converting/validating arguments and return -values back to msgpack. +dispatch function is generated, which matches msgpack-rpc method names with +non-static API functions, converting/validating arguments and return values +back to msgpack. Client libraries will normally provide wrappers that hide msgpack-rpc details from programmers, which can be automatically generated by reading bundled API @@ -60,7 +60,7 @@ There are two ways to obtain API metadata: separate compilation step. Here's a simple way to get human-readable description of the API (requires -python and the pyyaml/msgpack-python pip packages): +python and the `pyyaml`/`msgpack-python` pip packages): > nvim --api-info | python -c 'import msgpack, sys, yaml; print yaml.dump(msgpack.unpackb(sys.stdin.read()))' > api.yaml @@ -69,21 +69,19 @@ python and the pyyaml/msgpack-python pip packages): There are four ways to open msgpack-rpc streams to nvim: -1. Through nvim's stdin/stdout when started with the `--embed` option. This is +1. Through Nvim's stdin/stdout when started with the `--embed` option. This is how other programs can embed nvim. -2. Through stdin/stdout of a program spawned by the |rpcstart()| function. +2. Through the stdin/stdout of a program spawned by the |rpcstart()| function. 3. Through the socket automatically created with each instance. To find out the socket location (which is random by default) from a running nvim - instance, one can inspect the *$NVIM_LISTEN_ADDRESS* environment variable - like this: + instance, one can inspect the |$NVIM_LISTEN_ADDRESS| environment variable: > :echo $NVIM_LISTEN_ADDRESS < -4. Through a TCP/IP socket. To make nvim listen on a TCP/IP socket, you need - to set the $NVIM_LISTEN_ADDRESS environment variable before starting, like - this: +4. Through a TCP/IP socket. To make nvim listen on a TCP/IP socket, set the + |$NVIM_LISTEN_ADDRESS| environment variable in a shell before starting: > NVIM_LISTEN_ADDRESS=127.0.0.1:6666 nvim < @@ -120,34 +118,34 @@ functions can be called interactively: ============================================================================== 4. Implementing new clients *msgpack-rpc-clients* -Nvim is still alpha and there's no in-depth documentation explaining how to -properly implement a client library. The python client (neovim pip package) -will be always up-to-date with the latest API changes, so its source code is -the best documentation currently available. There are some guidelines however: +Nvim is still in alpha, so there's no in-depth documentation explaining how to +properly implement a client library yet. The python client (the pip package +"neovim") will always be up-to-date with the latest API changes, so its source +code is the best documentation currently available. There are some guidelines +however: -- Separate the transport layer from the rest of the library (see - |msgpack-rpc-connecting| for details of how a client can connect to nvim). -- Use a msgpack library that implements the spec version 5, Nvim uses the - BIN/EXT types. +- Separate the transport layer from the rest of the library. See + |msgpack-rpc-connecting| for details on how clients can connect to nvim. +- Use a MessagePack library that implements at least version 5 of the + MessagePack spec, which supports the `bin` and `ext` types used by nvim. - Read API metadata in order to create client-side wrappers for all msgpack-rpc methods. - Use a single-threaded event loop library/pattern. -- Use a fiber/coroutine library for the language you are implementing a client - for. These greatly simplify concurrency and allow the library to expose a - blocking API on top of a non-blocking event loop without the complexity - that comes with preemptive multitasking. +- Use a fiber/coroutine library for the language being used for implementing a + client. These greatly simplify concurrency and allow the library to expose a + blocking API on top of a non-blocking event loop without the complexity that + comes with preemptive multitasking. - Don't assume anything about the order that responses to msgpack-rpc requests will arrive. - Clients should expect to receive msgpack-rpc requests, which need to be handled immediately because Nvim is blocked while waiting for the client response. - Clients should expect to receive msgpack-rpc notifications, but these don't - need to be handled immediately because they won't block Nvim (though you - probably want to handle them immediately anyway). - + need to be handled immediately because they won't block Nvim (although they + should probably be handled immediately anyway). Most of the complexity could be handled by a msgpack-rpc library that supports -server->client requests and notifications, but it's not clear if this is part +server to client requests and notifications, but it's not clear if this is part of the msgpack-rpc spec. At least the ruby msgpack-rpc library does not seem to support it: https://github.com/msgpack-rpc/msgpack-rpc-ruby/blob/master/lib/msgpack/rpc/transport/tcp.rb#L150-L158 @@ -217,7 +215,7 @@ that makes this task easier: - Methods that operate instances of Nvim's types are prefixed with the type name in lower case, e.g. `buffer_get_line` represents the `get_line` method of a Buffer instance. -- Global methods are prefixed with `vim`, e.g.`vim_list_buffers`. +- Global methods are prefixed with `vim`, e.g. `vim_list_buffers`. So, for an object-oriented language, a client library would have the classes that represent Nvim's types, and the methods of each class could be defined @@ -227,13 +225,13 @@ class with methods mapped to functions prefixed with `vim_` ============================================================================== 7. Vimscript functions *msgpack-rpc-vim-functions* -Four functions related to msgpack-rpc are available to vimscript: +Four functions related to msgpack-rpc are available in vimscript: 1. |rpcstart()|: Similarly to |jobstart()|, this will spawn a co-process with its standard handles connected to Nvim. The difference is that it's not - possible to process raw data to/from the process stdin/stdout/stderr (since - the job's stdin/stdout combo are used as a msgpack channel that is - processed directly by Nvim C code). + possible to process raw data to/from the process's stdin/stdout/stderr. + This is because the job's stdin and stdout are used as a single msgpack + channel that is processed directly by Nvim. 2. |rpcstop()|: Same as |jobstop()|, but operates on handles returned by |rpcstart()|. diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 4a2646f1c4..8152c3d3c4 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -4935,9 +4935,8 @@ A jump table for the options with a short description can be found at |Q_op|. global {not in Vi} Enable the use of the mouse. Only works for certain terminals - (xterm, MS-DOS, Win32 |win32-mouse|, QNX pterm, *BSD console with - sysmouse and Linux console with gpm). For using the mouse in the - GUI, see |gui-mouse|. + (xterm, Win32 |win32-mouse|, *BSD console with sysmouse and Linux + console with gpm). For using the mouse in the GUI, see |gui-mouse|. The mouse can be enabled for different modes: n Normal mode v Visual mode @@ -7402,8 +7401,6 @@ A jump table for the options with a short description can be found at |Q_op|. rather complex sequence, starting with "<Esc>[". This is also available for an Xterm, if it was configured with "--enable-dec-locator". - *pterm-mouse* - pterm QNX pterm mouse handling. *urxvt-mouse* urxvt Mouse handling for the urxvt (rxvt-unicode) terminal. The mouse works only if the terminal supports this diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 58310a22a4..3a378ea360 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -602,7 +602,6 @@ void goto_buffer(exarg_T *eap, int start, int dir, int count) { (void)do_buffer(*eap->cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO, start, dir, count, eap->forceit); -#ifdef HAS_SWAP_EXISTS_ACTION buf_T *old_curbuf = curbuf; swap_exists_action = SEA_DIALOG; @@ -624,10 +623,8 @@ void goto_buffer(exarg_T *eap, int start, int dir, int count) } else { handle_swap_exists(old_curbuf); } -#endif } -#if defined(HAS_SWAP_EXISTS_ACTION) || defined(PROTO) /* * Handle the situation of swap_exists_action being set. * It is allowed for "old_curbuf" to be NULL or invalid. @@ -678,7 +675,6 @@ void handle_swap_exists(buf_T *old_curbuf) } swap_exists_action = SEA_NONE; } -#endif /* * do_bufdel() - delete or unload buffer(s) @@ -2351,7 +2347,7 @@ int buflist_add(char_u *fname, int flags) return 0; } -#if defined(BACKSLASH_IN_FILENAME) || defined(PROTO) +#if defined(BACKSLASH_IN_FILENAME) /* * Adjust slashes in file names. Called after 'shellslash' was set. */ @@ -2752,7 +2748,7 @@ void resettitle(void) mch_settitle(lasttitle, lasticon); } -# if defined(EXITFREE) || defined(PROTO) +# if defined(EXITFREE) void free_titles(void) { free(lasttitle); @@ -3934,17 +3930,12 @@ void ex_buffer_all(exarg_T *eap) continue; /* Open the buffer in this window. */ -#if defined(HAS_SWAP_EXISTS_ACTION) swap_exists_action = SEA_DIALOG; -#endif set_curbuf(buf, DOBUF_GOTO); if (!buf_valid(buf)) { /* autocommands deleted the buffer!!! */ -#if defined(HAS_SWAP_EXISTS_ACTION) swap_exists_action = SEA_NONE; -# endif break; } -#if defined(HAS_SWAP_EXISTS_ACTION) if (swap_exists_action == SEA_QUIT) { cleanup_T cs; @@ -3964,7 +3955,6 @@ void ex_buffer_all(exarg_T *eap) leave_cleanup(&cs); } else handle_swap_exists(NULL); -#endif } os_breakcheck(); diff --git a/src/nvim/charset.c b/src/nvim/charset.c index 8781e389ed..b86c66c3fe 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -1695,7 +1695,9 @@ intmax_t getdigits(char_u **pp) int getdigits_int(char_u **pp) { intmax_t number = getdigits(pp); +#if SIZEOF_INTMAX_T > SIZEOF_INT assert(number >= INT_MIN && number <= INT_MAX); +#endif return (int)number; } @@ -1705,7 +1707,9 @@ int getdigits_int(char_u **pp) long getdigits_long(char_u **pp) { intmax_t number = getdigits(pp); +#if SIZEOF_INTMAX_T > SIZEOF_LONG assert(number >= LONG_MIN && number <= LONG_MAX); +#endif return (long)number; } @@ -1849,7 +1853,7 @@ int hex2nr(int c) return c - '0'; } -#if defined(FEAT_TERMRESPONSE) || defined(FEAT_GUI_GTK) || defined(PROTO) +#if defined(FEAT_TERMRESPONSE) || defined(FEAT_GUI_GTK) /// Convert two hex characters to a byte. /// Return -1 if one of the characters is not hex. @@ -1866,8 +1870,7 @@ int hexhex2nr(char_u *p) return (hex2nr(p[0]) << 4) + hex2nr(p[1]); } -#endif // if defined(FEAT_TERMRESPONSE) || defined(FEAT_GUI_GTK) - // || defined(PROTO) +#endif // if defined(FEAT_TERMRESPONSE) || defined(FEAT_GUI_GTK) /// Return true if "str" starts with a backslash that should be removed. /// For WIN32 this is only done when the character after the diff --git a/src/nvim/edit.c b/src/nvim/edit.c index e1a1fb18fa..4c00547daa 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -5800,7 +5800,7 @@ void set_last_insert(int c) last_insert_skip = 0; } -#if defined(EXITFREE) || defined(PROTO) +#if defined(EXITFREE) void free_last_insert(void) { free(last_insert); diff --git a/src/nvim/eval.c b/src/nvim/eval.c index d60ce2de73..1833461fa9 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -76,6 +76,7 @@ #include "nvim/tag.h" #include "nvim/tempfile.h" #include "nvim/term.h" +#include "nvim/ui.h" #include "nvim/mouse.h" #include "nvim/undo.h" #include "nvim/version.h" @@ -499,7 +500,7 @@ void eval_init(void) job_event_pool = kmp_init(JobEventPool); } -#if defined(EXITFREE) || defined(PROTO) +#if defined(EXITFREE) void eval_clear(void) { struct vimvar *p; @@ -4847,7 +4848,6 @@ list_equal ( return item1 == NULL && item2 == NULL; } -#if defined(PROTO) /* * Return the dictitem that an entry in a hashtable points to. */ @@ -4855,12 +4855,6 @@ dictitem_T *dict_lookup(hashitem_T *hi) { return HI2DI(hi); } -#endif - -dictitem_T * dict_lookup(hashitem_T *hi) -{ - return HI2DI(hi); -} /* * Return TRUE when two dictionaries have exactly the same key/values. @@ -10023,6 +10017,8 @@ static void f_has(typval_T *argvars, typval_T *rettv) #endif } else if (STRICMP(name, "syntax_items") == 0) { n = syntax_present(curwin); + } else if (STRICMP(name, "gui_running") == 0) { + n = ui_rgb_attached(); } } @@ -14440,7 +14436,7 @@ static void f_synIDattr(typval_T *argvars, typval_T *rettv) if (modec != 't' && modec != 'c' && modec != 'g') modec = 0; /* replace invalid with current */ } else { - if (t_colors > 1) + if (abstract_ui || t_colors > 1) modec = 'c'; else modec = 't'; @@ -18047,7 +18043,7 @@ static ufunc_T *find_func(char_u *name) return NULL; } -#if defined(EXITFREE) || defined(PROTO) +#if defined(EXITFREE) void free_all_functions(void) { hashitem_T *hi; diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 03b45f9d49..763a2d6212 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -825,7 +825,7 @@ void ex_copy(linenr_T line1, linenr_T line2, linenr_T n) static char_u *prevcmd = NULL; /* the previous command */ -#if defined(EXITFREE) || defined(PROTO) +#if defined(EXITFREE) void free_prev_shellcmd(void) { free(prevcmd); @@ -2978,9 +2978,7 @@ do_ecmd ( lnum = curwin->w_cursor.lnum; topline = curwin->w_topline; if (!oldbuf) { /* need to read the file */ -#if defined(HAS_SWAP_EXISTS_ACTION) swap_exists_action = SEA_DIALOG; -#endif curbuf->b_flags |= BF_CHECK_RO; /* set/reset 'ro' flag */ /* @@ -2989,11 +2987,9 @@ do_ecmd ( if (should_abort(open_buffer(FALSE, eap, readfile_flags))) retval = FAIL; -#if defined(HAS_SWAP_EXISTS_ACTION) if (swap_exists_action == SEA_QUIT) retval = FAIL; handle_swap_exists(old_curbuf); -#endif } else { /* Read the modelines, but only to set window-local options. Any * buffer-local options have already been set and may have been @@ -4609,7 +4605,7 @@ void write_viminfo_sub_string(FILE *fp) } } -#if defined(EXITFREE) || defined(PROTO) +#if defined(EXITFREE) void free_old_sub(void) { free(old_sub); @@ -6184,7 +6180,7 @@ char_u * sign_typenr2name(int typenr) return (char_u *)_("[Deleted]"); } -#if defined(EXITFREE) || defined(PROTO) +#if defined(EXITFREE) /* * Undefine/free all signs. */ diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index c796cf6ac7..7de47cb296 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -2546,7 +2546,7 @@ void ex_scriptnames(exarg_T *eap) } } -# if defined(BACKSLASH_IN_FILENAME) || defined(PROTO) +# if defined(BACKSLASH_IN_FILENAME) /* * Fix slashes in the list of script names for 'shellslash'. */ @@ -2579,7 +2579,7 @@ char_u *get_scriptname(scid_T id) return SCRIPT_ITEM(id).sn_name; } -# if defined(EXITFREE) || defined(PROTO) +# if defined(EXITFREE) void free_scriptnames() { # define FREE_SCRIPTNAME(item) free((item)->sn_name) @@ -3204,7 +3204,7 @@ static char_u **find_locales(void) return (char_u **)locales_ga.ga_data; } -# if defined(EXITFREE) || defined(PROTO) +# if defined(EXITFREE) void free_locales(void) { int i; diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 3661a65b11..b4dfe99aed 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -5530,7 +5530,7 @@ void alist_new(void) alist_init(curwin->w_alist); } -#if !defined(UNIX) || defined(PROTO) +#if !defined(UNIX) /* * Expand the file names in the global argument list. * If "fnum_list" is not NULL, use "fnum_list[fnum_len]" as a list of buffer @@ -5623,7 +5623,7 @@ alist_add ( ++al->al_ga.ga_len; } -#if defined(BACKSLASH_IN_FILENAME) || defined(PROTO) +#if defined(BACKSLASH_IN_FILENAME) /* * Adjust slashes in file names. Called after 'shellslash' was set. */ @@ -6256,7 +6256,7 @@ static void ex_read(exarg_T *eap) static char_u *prev_dir = NULL; -#if defined(EXITFREE) || defined(PROTO) +#if defined(EXITFREE) void free_cd_dir(void) { free(prev_dir); diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 3ce8263457..b942f69f61 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -1972,7 +1972,7 @@ static void realloc_cmdbuff(int len) static char_u *arshape_buf = NULL; -# if defined(EXITFREE) || defined(PROTO) +# if defined(EXITFREE) void free_cmdline_buf(void) { free(arshape_buf); diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 58e67fa58c..370584b095 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -636,14 +636,12 @@ readfile ( #endif } -#if defined(HAS_SWAP_EXISTS_ACTION) /* If "Quit" selected at ATTENTION dialog, don't load the file */ if (swap_exists_action == SEA_QUIT) { if (!read_buffer && !read_stdin) close(fd); return FAIL; } -#endif ++no_wait_return; /* don't wait for return yet */ @@ -5149,7 +5147,7 @@ void write_lnum_adjust(linenr_T offset) curbuf->b_no_eol_lnum += offset; } -#if defined(BACKSLASH_IN_FILENAME) || defined(PROTO) +#if defined(BACKSLASH_IN_FILENAME) /* * Convert all backslashes in fname to forward slashes in-place. */ @@ -5547,7 +5545,7 @@ void do_augroup(char_u *arg, int del_group) } } -#if defined(EXITFREE) || defined(PROTO) +#if defined(EXITFREE) void free_all_autocmds(void) { for (current_augroup = -1; current_augroup < augroups.ga_len; @@ -7454,7 +7452,7 @@ file_pat_to_reg_pat ( return reg_pat; } -#if defined(EINTR) || defined(PROTO) +#if defined(EINTR) /* * Version of read() that retries when interrupted by EINTR (possibly * by a SIGWINCH). diff --git a/src/nvim/garray.c b/src/nvim/garray.c index c4f8f66bfe..c3a3426e87 100644 --- a/src/nvim/garray.c +++ b/src/nvim/garray.c @@ -199,7 +199,7 @@ void ga_append(garray_T *gap, char c) GA_APPEND(char, gap, c); } -#if defined(UNIX) || defined(WIN3264) || defined(PROTO) +#if defined(UNIX) || defined(WIN3264) /// Append the text in "gap" below the cursor line and clear "gap". /// diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index e12601e4c9..d97c983133 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -1307,7 +1307,7 @@ static void closescript(void) --curscript; } -#if defined(EXITFREE) || defined(PROTO) +#if defined(EXITFREE) void close_all_scripts(void) { while (scriptin[0] != NULL) diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 11a7e9ecac..73bcdea226 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -859,7 +859,6 @@ EXTERN int cmd_silent INIT(= FALSE); /* don't echo the command line */ #define SEA_QUIT 2 /* quit editing the file */ #define SEA_RECOVER 3 /* recover the file */ -#define HAS_SWAP_EXISTS_ACTION EXTERN int swap_exists_action INIT(= SEA_NONE); /* For dialog when swap file already * exists. */ diff --git a/src/nvim/hardcopy.c b/src/nvim/hardcopy.c index 993ec143bb..92abcbada4 100644 --- a/src/nvim/hardcopy.c +++ b/src/nvim/hardcopy.c @@ -14,6 +14,7 @@ #include <errno.h> #include <string.h> #include <inttypes.h> +#include <stdint.h> #include "nvim/vim.h" #include "nvim/ascii.h" @@ -726,8 +727,7 @@ void ex_hardcopy(exarg_T *eap) if (got_int || settings.user_abort) goto print_fail; - assert(prtpos.bytes_printed == 0 - || prtpos.bytes_printed * 100 > prtpos.bytes_printed); + assert(prtpos.bytes_printed <= SIZE_MAX / 100); sprintf((char *)IObuff, _("Printing page %d (%zu%%)"), page_count + 1 + side, prtpos.bytes_printed * 100 / bytes_to_print); diff --git a/src/nvim/keymap.h b/src/nvim/keymap.h index 94ea095ace..c82a95c00c 100644 --- a/src/nvim/keymap.h +++ b/src/nvim/keymap.h @@ -97,9 +97,6 @@ /* Used a termcap entry that produces a normal character. */ #define KS_KEY 242 -/* Used for the qnx pterm mouse. */ -#define KS_PTERM_MOUSE 241 - /* Used for click in a tab pages label. */ #define KS_TABLINE 240 @@ -412,7 +409,6 @@ enum key_extra { #define K_NETTERM_MOUSE TERMCAP2KEY(KS_NETTERM_MOUSE, KE_FILLER) #define K_DEC_MOUSE TERMCAP2KEY(KS_DEC_MOUSE, KE_FILLER) -#define K_PTERM_MOUSE TERMCAP2KEY(KS_PTERM_MOUSE, KE_FILLER) #define K_URXVT_MOUSE TERMCAP2KEY(KS_URXVT_MOUSE, KE_FILLER) #define K_SGR_MOUSE TERMCAP2KEY(KS_SGR_MOUSE, KE_FILLER) diff --git a/src/nvim/main.c b/src/nvim/main.c index 1f6c8ddc81..05b9778102 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -149,10 +149,6 @@ void early_init(void) (void)mb_init(); // init mb_bytelen_tab[] to ones eval_init(); // init global variables -#ifdef __QNXNTO__ - qnx_init(); // PhAttach() for clipboard, (and gui) -#endif - // Init the table of Normal mode commands. init_normal_cmds(); @@ -265,10 +261,7 @@ int main(int argc, char **argv) if (params.want_full_screen && !silent_mode) { if (embedded_mode) { - // In embedded mode don't do terminal-related initializations, assume an - // initial screen size of 80x20 - full_screen = true; - screen_resize(80, 20, false); + // embedded mode implies abstract_ui termcapinit((uint8_t *)"abstract_ui"); } else { // set terminal name and get terminal capabilities (will set full_screen) @@ -282,7 +275,9 @@ int main(int argc, char **argv) event_init(); if (abstract_ui) { + full_screen = true; t_colors = 256; + T_CCO = (uint8_t *)"256"; } else { // Print a warning if stdout is not a terminal TODO(tarruda): Remove this // check once the new terminal UI is implemented @@ -1564,19 +1559,15 @@ static void handle_quickfix(mparm_T *paramp) static void handle_tag(char_u *tagname) { if (tagname != NULL) { -#if defined(HAS_SWAP_EXISTS_ACTION) swap_exists_did_quit = FALSE; -#endif vim_snprintf((char *)IObuff, IOSIZE, "ta %s", tagname); do_cmdline_cmd(IObuff); TIME_MSG("jumping to tag"); -#if defined(HAS_SWAP_EXISTS_ACTION) /* If the user doesn't want to edit the file then we quit here. */ if (swap_exists_did_quit) getout(1); -#endif } } @@ -1611,10 +1602,8 @@ static void read_stdin(void) { int i; -#if defined(HAS_SWAP_EXISTS_ACTION) /* When getting the ATTENTION prompt here, use a dialog */ swap_exists_action = SEA_DIALOG; -#endif no_wait_return = TRUE; i = msg_didany; set_buflisted(TRUE); @@ -1622,9 +1611,7 @@ static void read_stdin(void) no_wait_return = FALSE; msg_didany = i; TIME_MSG("reading stdin"); -#if defined(HAS_SWAP_EXISTS_ACTION) check_swap_exists_action(); -#endif /* * Close stdin and dup it from stderr. Required for GPM to work * properly, and for running external commands. @@ -1706,16 +1693,13 @@ static void create_windows(mparm_T *parmp) /* Set 'foldlevel' to 'foldlevelstart' if it's not negative. */ if (p_fdls >= 0) curwin->w_p_fdl = p_fdls; -#if defined(HAS_SWAP_EXISTS_ACTION) /* When getting the ATTENTION prompt here, use a dialog */ swap_exists_action = SEA_DIALOG; -#endif set_buflisted(TRUE); /* create memfile, read file */ (void)open_buffer(FALSE, NULL, 0); -#if defined(HAS_SWAP_EXISTS_ACTION) if (swap_exists_action == SEA_QUIT) { if (got_int || only_one_window()) { /* abort selected or quit and only one window */ @@ -1730,7 +1714,6 @@ static void create_windows(mparm_T *parmp) swap_exists_action = SEA_NONE; } else handle_swap_exists(NULL); -#endif dorewind = TRUE; /* start again */ } os_breakcheck(); @@ -1801,13 +1784,10 @@ static void edit_buffers(mparm_T *parmp) curwin->w_arg_idx = arg_idx; /* Edit file from arg list, if there is one. When "Quit" selected * at the ATTENTION prompt close the window. */ -# ifdef HAS_SWAP_EXISTS_ACTION swap_exists_did_quit = FALSE; -# endif (void)do_ecmd(0, arg_idx < GARGCOUNT ? alist_name(&GARGLIST[arg_idx]) : NULL, NULL, NULL, ECMD_LASTL, ECMD_HIDE, curwin); -# ifdef HAS_SWAP_EXISTS_ACTION if (swap_exists_did_quit) { /* abort or quit selected */ if (got_int || only_one_window()) { @@ -1818,7 +1798,6 @@ static void edit_buffers(mparm_T *parmp) win_close(curwin, TRUE); advance = FALSE; } -# endif if (arg_idx == GARGCOUNT - 1) arg_had_last = TRUE; ++arg_idx; @@ -2219,7 +2198,6 @@ static void usage(void) mch_exit(0); } -#if defined(HAS_SWAP_EXISTS_ACTION) /* * Check the result of the ATTENTION dialog: * When "Quit" selected, exit Vim. @@ -2232,5 +2210,4 @@ static void check_swap_exists_action(void) handle_swap_exists(NULL); } -#endif diff --git a/src/nvim/mark.c b/src/nvim/mark.c index cf11be665a..cfc702f189 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -1180,7 +1180,7 @@ void set_last_cursor(win_T *win) win->w_buffer->b_last_cursor = win->w_cursor; } -#if defined(EXITFREE) || defined(PROTO) +#if defined(EXITFREE) void free_all_marks(void) { int i; diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index 3274c8d8ec..bc8f768724 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -106,8 +106,6 @@ #include "nvim/os/os.h" #include "nvim/arabic.h" -#define WINBYTE BYTE - typedef struct { int rangeStart; int rangeEnd; @@ -365,10 +363,6 @@ enc_alias_table[] = {NULL, 0} }; -#ifndef CP_UTF8 -# define CP_UTF8 65001 /* magic number from winnls.h */ -#endif - /* * Find encoding "name" in the list of canonical encoding names. * Returns -1 if not found. @@ -3452,7 +3446,7 @@ char_u * enc_locale(void) return enc_canonize((char_u *)buf); } -# if defined(USE_ICONV) || defined(PROTO) +# if defined(USE_ICONV) /* @@ -3591,7 +3585,7 @@ static char_u * iconv_string(vimconv_T *vcp, char_u *str, int slen, int *unconvl return result; } -# if defined(DYNAMIC_ICONV) || defined(PROTO) +# if defined(DYNAMIC_ICONV) /* * Dynamically load the "iconv.dll" on Win32. */ diff --git a/src/nvim/memline.c b/src/nvim/memline.c index f6246c8b57..1fa6d6acc6 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -3000,7 +3000,7 @@ static void ml_lineadd(buf_T *buf, int count) } } -#if defined(HAVE_READLINK) || defined(PROTO) +#if defined(HAVE_READLINK) /* * Resolve a symlink in the last component of a file name. * Note that f_resolve() does it for every part of the path, we don't do that @@ -3367,9 +3367,7 @@ findswapname ( * for the current file, and the buffer was not recovered. */ if (differ == FALSE && !(curbuf->b_flags & BF_RECOVERED) && vim_strchr(p_shm, SHM_ATTENTION) == NULL) { -#if defined(HAS_SWAP_EXISTS_ACTION) int choice = 0; -#endif #ifdef UNIX process_still_running = FALSE; @@ -3427,7 +3425,6 @@ findswapname ( redraw_all_later(NOT_VALID); } -#if defined(HAS_SWAP_EXISTS_ACTION) if (choice > 0) { switch (choice) { case 1: @@ -3454,7 +3451,6 @@ findswapname ( if (!os_file_exists(fname)) break; } else -#endif { MSG_PUTS("\n"); if (msg_silent == 0) diff --git a/src/nvim/memory.c b/src/nvim/memory.c index f38dfd56ac..a2274a25fe 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -440,7 +440,7 @@ void do_outofmem_msg(size_t size) } } -#if defined(EXITFREE) || defined(PROTO) +#if defined(EXITFREE) #include "nvim/file_search.h" #include "nvim/buffer.h" diff --git a/src/nvim/menu.c b/src/nvim/menu.c index ea15fd68e3..9c1ca71477 100644 --- a/src/nvim/menu.c +++ b/src/nvim/menu.c @@ -1359,7 +1359,7 @@ void ex_emenu(exarg_T *eap) #if defined(FEAT_GUI_MSWIN) \ || defined(FEAT_GUI_GTK) \ - || defined(FEAT_BEVAL_TIP) || defined(PROTO) + || defined(FEAT_BEVAL_TIP) /* * Given a menu descriptor, e.g. "File.New", find it in the menu hierarchy. */ diff --git a/src/nvim/message.c b/src/nvim/message.c index 46e0a1a0df..9cd3814826 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -10,8 +10,6 @@ * message.c: functions for displaying messages on the command line */ -#define MESSAGE_FILE /* don't include prototype for smsg() */ - #include <assert.h> #include <errno.h> #include <inttypes.h> diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c index c0d2e254ac..f756201efb 100644 --- a/src/nvim/misc1.c +++ b/src/nvim/misc1.c @@ -2662,7 +2662,7 @@ void init_homedir(void) } } -#if defined(EXITFREE) || defined(PROTO) +#if defined(EXITFREE) void free_homedir(void) { free(homedir); diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index 4c35cce09a..c8f8252e6d 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -45,6 +45,7 @@ typedef struct { typedef struct { uint64_t id; + size_t pending_requests; PMap(cstr_t) *subscribed_events; bool is_job, closed; msgpack_unpacker *unpacker; @@ -83,7 +84,6 @@ static uint64_t next_id = 1; static PMap(uint64_t) *channels = NULL; static PMap(cstr_t) *event_strings = NULL; static msgpack_sbuffer out_buffer; -static size_t pending_requests = 0; #ifdef INCLUDE_GENERATED_DECLARATIONS # include "msgpack_rpc/channel.c.generated.h" @@ -103,14 +103,7 @@ void channel_init(void) } if (abstract_ui) { - // Add handler for "attach_ui" remote_ui_init(); - String method = cstr_as_string("attach_ui"); - MsgpackRpcRequestHandler handler = {.fn = remote_ui_attach, .defer = true}; - msgpack_rpc_add_method_handler(method, handler); - method = cstr_as_string("detach_ui"); - handler.fn = remote_ui_detach; - msgpack_rpc_add_method_handler(method, handler); } } @@ -200,20 +193,21 @@ bool channel_send_event(uint64_t id, char *name, Array args) return false; } - if (pending_requests) { - DelayedNotification p = { - .channel = channel, - .method = cstr_to_string(name), - .args = args - }; - // Pending request, queue the notification for sending later - *kl_pushp(DelayedNotification, delayed_notifications) = p; - } else { - if (channel) { - send_event(channel, name, args); + if (channel) { + if (channel->pending_requests) { + DelayedNotification p = { + .channel = channel, + .method = cstr_to_string(name), + .args = args + }; + // Pending request, queue the notification for sending later + *kl_pushp(DelayedNotification, delayed_notifications) = p; } else { - broadcast_event(name, args); + send_event(channel, name, args); } + } else { + // TODO(tarruda): Implement event broadcasting in vimscript + broadcast_event(name, args); } return true; @@ -246,10 +240,10 @@ Object channel_send_call(uint64_t id, // Push the frame ChannelCallFrame frame = {request_id, false, false, NIL}; kv_push(ChannelCallFrame *, channel->call_stack, &frame); - pending_requests++; + channel->pending_requests++; event_poll_until(-1, frame.returned); (void)kv_pop(channel->call_stack); - pending_requests--; + channel->pending_requests--; if (frame.errored) { api_set_error(err, Exception, "%s", frame.result.data.string.data); @@ -261,7 +255,7 @@ Object channel_send_call(uint64_t id, free_channel(channel); } - if (!pending_requests) { + if (!channel->pending_requests) { send_delayed_notifications(); } @@ -644,6 +638,7 @@ static void close_channel(Channel *channel) uv_handle_t *handle = (uv_handle_t *)channel->data.streams.uv; if (handle) { uv_close(handle, close_cb); + free_channel(channel); } else { event_push((Event) { .handler = on_stdio_close }, false); } @@ -687,6 +682,7 @@ static Channel *register_channel(void) rv->closed = false; rv->unpacker = msgpack_unpacker_new(MSGPACK_UNPACKER_INIT_BUFFER_SIZE); rv->id = next_id++; + rv->pending_requests = 0; rv->subscribed_events = pmap_new(cstr_t)(); rv->next_request_id = 1; kv_init(rv->call_stack); diff --git a/src/nvim/msgpack_rpc/remote_ui.c b/src/nvim/msgpack_rpc/remote_ui.c index f980a77b4c..361e93a6da 100644 --- a/src/nvim/msgpack_rpc/remote_ui.c +++ b/src/nvim/msgpack_rpc/remote_ui.c @@ -26,18 +26,44 @@ static PMap(uint64_t) *connected_uis = NULL; void remote_ui_init(void) { connected_uis = pmap_new(uint64_t)(); + // Add handler for "attach_ui" + String method = cstr_as_string("ui_attach"); + MsgpackRpcRequestHandler handler = {.fn = remote_ui_attach, .defer = false}; + msgpack_rpc_add_method_handler(method, handler); + method = cstr_as_string("ui_detach"); + handler.fn = remote_ui_detach; + msgpack_rpc_add_method_handler(method, handler); + method = cstr_as_string("ui_try_resize"); + handler.fn = remote_ui_try_resize; + msgpack_rpc_add_method_handler(method, handler); } -Object remote_ui_attach(uint64_t channel_id, uint64_t request_id, Array args, - Error *error) +void remote_ui_disconnect(uint64_t channel_id) +{ + UI *ui = pmap_get(uint64_t)(connected_uis, channel_id); + if (!ui) { + return; + } + UIData *data = ui->data; + // destroy pending screen updates + api_free_array(data->buffer); + pmap_del(uint64_t)(connected_uis, channel_id); + free(ui->data); + ui_detach(ui); + free(ui); +} + +static Object remote_ui_attach(uint64_t channel_id, uint64_t request_id, + Array args, Error *error) { if (pmap_has(uint64_t)(connected_uis, channel_id)) { api_set_error(error, Exception, _("UI already attached for channel")); return NIL; } - if (args.size != 2 || args.items[0].type != kObjectTypeInteger + if (args.size != 3 || args.items[0].type != kObjectTypeInteger || args.items[1].type != kObjectTypeInteger + || args.items[2].type != kObjectTypeBoolean || args.items[0].data.integer <= 0 || args.items[1].data.integer <= 0) { api_set_error(error, Validation, _("Arguments must be a pair of positive integers " @@ -50,6 +76,7 @@ Object remote_ui_attach(uint64_t channel_id, uint64_t request_id, Array args, UI *ui = xcalloc(1, sizeof(UI)); ui->width = (int)args.items[0].data.integer; ui->height = (int)args.items[1].data.integer; + ui->rgb = args.items[2].data.boolean; ui->data = data; ui->resize = remote_ui_resize; ui->clear = remote_ui_clear; @@ -67,16 +94,19 @@ Object remote_ui_attach(uint64_t channel_id, uint64_t request_id, Array args, ui->put = remote_ui_put; ui->bell = remote_ui_bell; ui->visual_bell = remote_ui_visual_bell; + ui->update_fg = remote_ui_update_fg; + ui->update_bg = remote_ui_update_bg; ui->flush = remote_ui_flush; ui->suspend = remote_ui_suspend; + ui->set_title = remote_ui_set_title; + ui->set_icon = remote_ui_set_icon; pmap_put(uint64_t)(connected_uis, channel_id, ui); ui_attach(ui); - return NIL; } -Object remote_ui_detach(uint64_t channel_id, uint64_t request_id, Array args, - Error *error) +static Object remote_ui_detach(uint64_t channel_id, uint64_t request_id, + Array args, Error *error) { if (!pmap_has(uint64_t)(connected_uis, channel_id)) { api_set_error(error, Exception, _("UI is not attached for channel")); @@ -86,21 +116,30 @@ Object remote_ui_detach(uint64_t channel_id, uint64_t request_id, Array args, return NIL; } -void remote_ui_disconnect(uint64_t channel_id) +static Object remote_ui_try_resize(uint64_t channel_id, uint64_t request_id, + Array args, Error *error) { - UI *ui = pmap_get(uint64_t)(connected_uis, channel_id); - if (!ui) { - return; + if (!pmap_has(uint64_t)(connected_uis, channel_id)) { + api_set_error(error, Exception, _("UI is not attached for channel")); } - UIData *data = ui->data; - // destroy pending screen updates - api_free_array(data->buffer); - pmap_del(uint64_t)(connected_uis, channel_id); - free(ui->data); - ui_detach(ui); - free(ui); + + if (args.size != 2 || args.items[0].type != kObjectTypeInteger + || args.items[1].type != kObjectTypeInteger + || args.items[0].data.integer <= 0 || args.items[1].data.integer <= 0) { + api_set_error(error, Validation, + _("Arguments must be a pair of positive integers " + "representing the remote screen width/height")); + return NIL; + } + + UI *ui = pmap_get(uint64_t)(connected_uis, channel_id); + ui->width = (int)args.items[0].data.integer; + ui->height = (int)args.items[1].data.integer; + ui_refresh(); + return NIL; } + static void push_call(UI *ui, char *name, Array args) { Array call = ARRAY_DICT_INIT; @@ -214,10 +253,6 @@ static void remote_ui_highlight_set(UI *ui, HlAttrs attrs) PUT(hl, "bold", BOOLEAN_OBJ(true)); } - if (attrs.standout) { - PUT(hl, "standout", BOOLEAN_OBJ(true)); - } - if (attrs.underline) { PUT(hl, "underline", BOOLEAN_OBJ(true)); } @@ -266,6 +301,20 @@ static void remote_ui_visual_bell(UI *ui) push_call(ui, "visual_bell", args); } +static void remote_ui_update_fg(UI *ui, int fg) +{ + Array args = ARRAY_DICT_INIT; + ADD(args, INTEGER_OBJ(fg)); + push_call(ui, "update_fg", args); +} + +static void remote_ui_update_bg(UI *ui, int bg) +{ + Array args = ARRAY_DICT_INIT; + ADD(args, INTEGER_OBJ(bg)); + push_call(ui, "update_bg", args); +} + static void remote_ui_flush(UI *ui) { UIData *data = ui->data; @@ -275,6 +324,20 @@ static void remote_ui_flush(UI *ui) static void remote_ui_suspend(UI *ui) { - UIData *data = ui->data; - remote_ui_disconnect(data->channel_id); + Array args = ARRAY_DICT_INIT; + push_call(ui, "suspend", args); +} + +static void remote_ui_set_title(UI *ui, char *title) +{ + Array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstr_to_string(title))); + push_call(ui, "set_title", args); +} + +static void remote_ui_set_icon(UI *ui, char *icon) +{ + Array args = ARRAY_DICT_INIT; + ADD(args, STRING_OBJ(cstr_to_string(icon))); + push_call(ui, "set_icon", args); } diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 87a2c2ca05..8fb3ba7f08 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -2293,7 +2293,7 @@ void init_yank(void) y_regs[i].y_array = NULL; } -#if defined(EXITFREE) || defined(PROTO) +#if defined(EXITFREE) void clear_registers(void) { int i; diff --git a/src/nvim/option.c b/src/nvim/option.c index 6c774937cd..88108b14a2 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -2237,7 +2237,7 @@ void set_number_default(char *name, long val) options[opt_idx].def_val[VI_DEFAULT] = (char_u *)val; } -#if defined(EXITFREE) || defined(PROTO) +#if defined(EXITFREE) /* * Free all options. */ diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 8b36df3276..99e8e645b6 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -576,13 +576,12 @@ EXTERN char_u *p_ttym; /* 'ttymouse' */ EXTERN unsigned ttym_flags; # ifdef IN_OPTION_C static char *(p_ttym_values[]) = -{"xterm", "xterm2", "dec", "netterm", "pterm", "urxvt", "sgr", NULL}; +{"xterm", "xterm2", "dec", "netterm", "urxvt", "sgr", NULL}; # endif # define TTYM_XTERM 0x01 # define TTYM_XTERM2 0x02 # define TTYM_DEC 0x04 # define TTYM_NETTERM 0x08 -# define TTYM_PTERM 0x10 # define TTYM_URXVT 0x20 # define TTYM_SGR 0x40 #endif diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index c0d588f4ef..2ae4558f3d 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -187,14 +187,20 @@ size_t input_enqueue(String keys) unsigned int new_size = trans_special((uint8_t **)&ptr, buf, false); if (!new_size) { + if (*ptr == '<') { + // Invalid key sequence, skip until the next '>' or until *end + do { + ptr++; + } while (ptr < end && *ptr != '>'); + ptr++; + continue; + } // copy the character unmodified *buf = (uint8_t)*ptr++; new_size = 1; } new_size = handle_mouse_event(&ptr, buf, new_size); - // TODO(tarruda): Don't produce past unclosed '<' characters, except if - // there's a lot of characters after the '<' rbuffer_write(input_buffer, (char *)buf, new_size); } @@ -217,7 +223,8 @@ static unsigned int handle_mouse_event(char **ptr, uint8_t *buf, mouse_code = buf[5]; } - if (mouse_code < KE_LEFTMOUSE || mouse_code > KE_RIGHTRELEASE) { + if (!((mouse_code >= KE_LEFTMOUSE && mouse_code <= KE_RIGHTRELEASE) + || (mouse_code >= KE_MOUSEDOWN && mouse_code <= KE_MOUSERIGHT))) { return bufsize; } @@ -226,7 +233,7 @@ static unsigned int handle_mouse_event(char **ptr, uint8_t *buf, // find mouse coordinates, and it would be too expensive to refactor this // now. int col, row, advance; - if (sscanf(*ptr, "<%d,%d>%n", &col, &row, &advance)) { + if (sscanf(*ptr, "<%d,%d>%n", &col, &row, &advance) != EOF && advance) { if (col >= 0 && row >= 0) { mouse_row = row; mouse_col = col; diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index d0f8442768..d481d6af56 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -24,7 +24,6 @@ #include "nvim/option_defs.h" #include "nvim/charset.h" #include "nvim/strings.h" -#include "nvim/ui.h" #define DYNAMIC_BUFFER_INIT {NULL, 0, 0} @@ -414,6 +413,7 @@ static size_t write_output(char *output, size_t remaining, bool to_buffer, char *start = output; size_t off = 0; + int lastrow = (int)Rows - 1; while (off < remaining) { if (output[off] == NL) { // Insert the line @@ -421,10 +421,8 @@ static size_t write_output(char *output, size_t remaining, bool to_buffer, if (to_buffer) { ml_append(curwin->w_cursor.lnum++, (char_u *)output, 0, false); } else { - // pending data from the output buffer has been flushed to the screen, - // safe to call ui_write directly - ui_write((char_u *)output, (int)off); - ui_write((char_u *)"\r\n", 2); + screen_del_lines(0, 0, 1, (int)Rows, true, NULL); + screen_puts_len((char_u *)output, (int)off, lastrow, 0, 0); } size_t skip = off + 1; output += skip; @@ -448,8 +446,8 @@ static size_t write_output(char *output, size_t remaining, bool to_buffer, // remember that the NL was missing curbuf->b_no_eol_lnum = curwin->w_cursor.lnum; } else { - ui_write((char_u *)output, (int)remaining); - ui_write((char_u *)"\r\n", 2); + screen_del_lines(0, 0, 1, (int)Rows, true, NULL); + screen_puts_len((char_u *)output, (int)remaining, lastrow, 0, 0); } output += remaining; } else if (to_buffer) { diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c index 810ddea82b..b69be88fc7 100644 --- a/src/nvim/os/time.c +++ b/src/nvim/os/time.c @@ -80,11 +80,11 @@ struct tm *os_localtime_r(const time_t *restrict clock, { #ifdef UNIX // POSIX provides localtime_r() as a thread-safe version of localtime(). - return localtime_r(clock, result); + return localtime_r(clock, result); // NOLINT(runtime/threadsafe_fn) #else // Windows version of localtime() is thread-safe. // See http://msdn.microsoft.com/en-us/library/bf12f0hc%28VS.80%29.aspx - struct tm *local_time = localtime(clock); // NOLINT + struct tm *local_time = localtime(clock); // NOLINT(runtime/threadsafe_fn) if (!local_time) { return NULL; } diff --git a/src/nvim/os_unix.c b/src/nvim/os_unix.c index 7ec4059bce..f7b47f9569 100644 --- a/src/nvim/os_unix.c +++ b/src/nvim/os_unix.c @@ -43,6 +43,7 @@ #include "nvim/syntax.h" #include "nvim/tempfile.h" #include "nvim/term.h" +#include "nvim/ui.h" #include "nvim/types.h" #include "nvim/os/os.h" #include "nvim/os/time.h" @@ -181,22 +182,26 @@ void mch_settitle(char_u *title, char_u *icon) * Note: if "t_ts" is set, title is set with escape sequence rather * than x11 calls, because the x11 calls don't always work */ - if ((type || *T_TS != NUL) && title != NULL) { + if ((type || *T_TS != NUL || abstract_ui) && title != NULL) { if (oldtitle == NULL ) /* first call but not in GUI, save title */ (void)get_x11_title(FALSE); - if (*T_TS != NUL) /* it's OK if t_fs is empty */ + if (abstract_ui) { + ui_set_title((char *)title); + } else if (*T_TS != NUL) /* it's OK if t_fs is empty */ term_settitle(title); did_set_title = TRUE; } - if ((type || *T_CIS != NUL) && icon != NULL) { + if ((type || *T_CIS != NUL || abstract_ui) && icon != NULL) { if (oldicon == NULL ) /* first call, save icon */ get_x11_icon(FALSE); - if (*T_CIS != NUL) { + if (abstract_ui) { + ui_set_icon((char *)icon); + } else if (*T_CIS != NUL) { out_str(T_CIS); /* set icon start */ out_str_nf(icon); out_str(T_CIE); /* set icon end */ @@ -270,7 +275,7 @@ int use_xterm_mouse(void) return 0; } -#if defined(USE_FNAME_CASE) || defined(PROTO) +#if defined(USE_FNAME_CASE) /* * Set the case of the file name, if it already exists. This will cause the * file name to remain exactly the same. @@ -326,7 +331,7 @@ int len /* buffer size, only used when name gets longer */ } #endif -#if defined(HAVE_ACL) || defined(PROTO) +#if defined(HAVE_ACL) # ifdef HAVE_SYS_ACL_H # include <sys/acl.h> # endif @@ -335,7 +340,7 @@ int len /* buffer size, only used when name gets longer */ # endif -#if defined(HAVE_SELINUX) || defined(PROTO) +#if defined(HAVE_SELINUX) /* * Copy security info from "from_file" to "to_file". */ @@ -437,7 +442,7 @@ int mch_nodetype(char_u *name) return NODE_WRITABLE; } -#if defined(EXITFREE) || defined(PROTO) +#if defined(EXITFREE) void mch_free_mem(void) { free(oldtitle); diff --git a/src/nvim/path.c b/src/nvim/path.c index 8af4015611..219dac12de 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -403,9 +403,9 @@ char_u *save_absolute_path(const char_u *name) } -#if !defined(NO_EXPANDPATH) || defined(PROTO) +#if !defined(NO_EXPANDPATH) -#if defined(UNIX) || defined(USE_UNIXFILENAME) || defined(PROTO) +#if defined(UNIX) || defined(USE_UNIXFILENAME) /* * Unix style wildcard expansion code. * It's here because it's used both for Unix and Mac. @@ -1622,7 +1622,7 @@ int same_directory(char_u *f1, char_u *f2) && pathcmp((char *)ffname, (char *)f2, (int)(t1 - ffname)) == 0; } -#if !defined(NO_EXPANDPATH) || defined(PROTO) +#if !defined(NO_EXPANDPATH) /* * Compare path "p[]" to "q[]". * If "maxlen" >= 0 compare "p[maxlen]" to "q[maxlen]" diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index 62c01e3798..fafd99c046 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -3228,7 +3228,7 @@ static garray_T backpos = GA_EMPTY_INIT_VALUE; #define REGSTACK_INITIAL 2048 #define BACKPOS_INITIAL 64 -#if defined(EXITFREE) || defined(PROTO) +#if defined(EXITFREE) void free_regexp_stuff(void) { ga_clear(®stack); diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 855c09619e..8f4f894128 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -4548,7 +4548,7 @@ static void screen_line(int row, int coloff, int endcol, int clear_width, int rl int c; c = fillchar_vsep(&hl); - if (ScreenLines[off_to] != c + if (ScreenLines[off_to] != (schar_T)c || (enc_utf8 && (int)ScreenLinesUC[off_to] != (c >= 0x80 ? c : 0)) || ScreenAttrs[off_to] != hl) { @@ -5971,7 +5971,7 @@ void screen_stop_highlight(void) */ void reset_cterm_colors(void) { - if (t_colors > 1) { + if (!abstract_ui && t_colors > 1) { /* set Normal cterm colors */ if (cterm_normal_fg_color > 0 || cterm_normal_bg_color > 0) { out_str(T_OP); @@ -6150,8 +6150,7 @@ void screen_fill(int start_row, int end_row, int start_col, int end_col, int c1, return; /* it's a "normal" terminal when not in a GUI or cterm */ - norm_term = ( - t_colors <= 1); + norm_term = (!abstract_ui && t_colors <= 1); for (row = start_row; row < end_row; ++row) { if (has_mbyte ) { @@ -6675,8 +6674,8 @@ static void linecopy(int to, int from, win_T *wp) */ int can_clear(char_u *p) { - return *p != NUL && (t_colors <= 1 - || cterm_normal_bg_color == 0 || *T_UT != NUL); + return abstract_ui || (*p != NUL && (t_colors <= 1 + || cterm_normal_bg_color == 0 || *T_UT != NUL)); } /* @@ -8186,8 +8185,13 @@ void screen_resize(int width, int height, int mustset) Columns = width; } check_shellsize(); + height = Rows; + width = Columns; if (abstract_ui) { + // Clear the output buffer to ensure UIs don't receive redraw command meant + // for invalid screen sizes. + out_buf_clear(); ui_resize(width, height); } else { mch_set_shellsize(); diff --git a/src/nvim/search.c b/src/nvim/search.c index 25b8277933..e2781f17d5 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -294,7 +294,7 @@ void restore_search_patterns(void) } } -#if defined(EXITFREE) || defined(PROTO) +#if defined(EXITFREE) void free_search_patterns(void) { free(spats[0].pat); diff --git a/src/nvim/strings.c b/src/nvim/strings.c index 25e4a6c93b..20fa35ed1c 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -329,7 +329,7 @@ void vim_strcat(char_u *restrict to, const char_u *restrict from, STRCPY(to + tolen, from); } -#if (!defined(HAVE_STRCASECMP) && !defined(HAVE_STRICMP)) || defined(PROTO) +#if (!defined(HAVE_STRCASECMP) && !defined(HAVE_STRICMP)) /* * Compare two strings, ignoring case, using current locale. * Doesn't work for multi-byte characters. @@ -353,7 +353,7 @@ int vim_stricmp(const char *s1, const char *s2) } #endif -#if (!defined(HAVE_STRNCASECMP) && !defined(HAVE_STRNICMP)) || defined(PROTO) +#if (!defined(HAVE_STRNCASECMP) && !defined(HAVE_STRNICMP)) /* * Compare two strings, for length "len", ignoring case, using current locale. * Doesn't work for multi-byte characters. diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 4e2be0cd44..3980a4d8e6 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -45,6 +45,7 @@ #include "nvim/strings.h" #include "nvim/syntax_defs.h" #include "nvim/term.h" +#include "nvim/ui.h" #include "nvim/os/os.h" #include "nvim/os/time.h" @@ -223,8 +224,6 @@ struct name_list { #define ATTR_OFF (HL_ALL + 1) -#define SYN_NAMELEN 50 /* maximum length of a syntax name */ - static char *(spo_name_tab[SPO_COUNT]) = {"ms=", "me=", "hs=", "he=", "rs=", "re=", "lc="}; @@ -6036,6 +6035,7 @@ int load_colors(char_u *name) apply_autocmds(EVENT_COLORSCHEME, name, curbuf->b_fname, FALSE, curbuf); recursive = FALSE; + ui_refresh(); return retval; } @@ -6070,8 +6070,6 @@ do_highlight ( int error = FALSE; int color; int is_normal_group = FALSE; /* "Normal" group */ -# define is_menu_group 0 -# define is_tooltip_group 0 /* * If no argument, list current highlighting. @@ -6407,12 +6405,6 @@ do_highlight ( 4+8, 4+8, 2+8, 2+8, 6+8, 6+8, 1+8, 1+8, 5+8, 5+8, 3+8, 3+8, 7+8, -1}; -#if defined(__QNXNTO__) - static int *color_numbers_8_qansi = color_numbers_8; - /* On qnx, the 8 & 16 color arrays are the same */ - if (STRNCMP(T_NAME, "qansi", 5) == 0) - color_numbers_8_qansi = color_numbers_16; -#endif /* reduce calls to STRICMP a bit, it can be slow */ off = TOUPPER_ASC(*arg); @@ -6433,11 +6425,7 @@ do_highlight ( if (color >= 0) { if (t_colors == 8) { /* t_Co is 8: use the 8 colors table */ -#if defined(__QNXNTO__) - color = color_numbers_8_qansi[i]; -#else color = color_numbers_8[i]; -#endif if (key[5] == 'F') { /* set/reset bold attribute to get light foreground * colors (on some terminals, e.g. "linux") */ @@ -6448,8 +6436,7 @@ do_highlight ( HL_TABLE()[idx].sg_cterm &= ~HL_BOLD; } color &= 7; /* truncate to 8 colors */ - } else if (t_colors == 16 || t_colors == 88 - || t_colors == 256) { + } else if (t_colors == 16 || t_colors == 88 || t_colors == 256) { /* * Guess: if the termcap entry ends in 'm', it is * probably an xterm-like terminal. Use the changed @@ -6459,7 +6446,7 @@ do_highlight ( p = T_CAF; else p = T_CSF; - if (*p != NUL && *(p + STRLEN(p) - 1) == 'm') + if (abstract_ui || (*p != NUL && *(p + STRLEN(p) - 1) == 'm')) switch (t_colors) { case 16: color = color_numbers_8[i]; @@ -6642,6 +6629,10 @@ do_highlight ( if (is_normal_group) { HL_TABLE()[idx].sg_term_attr = 0; HL_TABLE()[idx].sg_cterm_attr = 0; + if (abstract_ui) { + // If the normal group has changed, it is simpler to refresh every UI + ui_refresh(); + } } else set_hl_attr(idx); HL_TABLE()[idx].sg_scriptID = current_SID; @@ -6654,7 +6645,7 @@ do_highlight ( need_highlight_changed = TRUE; } -#if defined(EXITFREE) || defined(PROTO) +#if defined(EXITFREE) void free_highlight(void) { for (int i = 0; i < highlight_ga.ga_len; ++i) { @@ -6870,7 +6861,7 @@ int hl_combine_attr(int char_attr, int prim_attr) if (char_attr <= HL_ALL && prim_attr <= HL_ALL) return char_attr | prim_attr; - if (t_colors > 1) { + if (abstract_ui || t_colors > 1) { if (char_attr > HL_ALL) char_aep = syn_cterm_attr2entry(char_attr); if (char_aep != NULL) @@ -6934,7 +6925,7 @@ int syn_attr2attr(int attr) { attrentry_T *aep; - if (t_colors > 1) + if (abstract_ui || t_colors > 1) aep = syn_cterm_attr2entry(attr); else aep = syn_term_attr2entry(attr); @@ -7204,9 +7195,10 @@ set_hl_attr ( * For the color term mode: If there are other than "normal" * highlighting attributes, need to allocate an attr number. */ - if (sgp->sg_cterm_fg == 0 && sgp->sg_cterm_bg == 0) + if (sgp->sg_cterm_fg == 0 && sgp->sg_cterm_bg == 0 + && sgp->sg_rgb_fg == -1 && sgp->sg_rgb_bg == -1) { sgp->sg_cterm_attr = sgp->sg_cterm; - else { + } else { at_en.ae_attr = abstract_ui ? sgp->sg_gui : sgp->sg_cterm; at_en.ae_u.cterm.fg_color = sgp->sg_cterm_fg; at_en.ae_u.cterm.bg_color = sgp->sg_cterm_bg; @@ -7361,7 +7353,7 @@ int syn_id2attr(int hl_id) hl_id = syn_get_final_id(hl_id); sgp = &HL_TABLE()[hl_id - 1]; /* index is ID minus one */ - if (t_colors > 1) + if (abstract_ui || t_colors > 1) attr = sgp->sg_cterm_attr; else attr = sgp->sg_term_attr; diff --git a/src/nvim/tag.c b/src/nvim/tag.c index fb39e069f0..bab594a27d 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -1981,7 +1981,7 @@ static void found_tagfile_cb(char_u *fname, void *cookie) GA_APPEND(char_u *, &tag_fnames, vim_strsave(fname)); } -#if defined(EXITFREE) || defined(PROTO) +#if defined(EXITFREE) void free_tag_stuff(void) { ga_clear_strings(&tag_fnames); diff --git a/src/nvim/term.c b/src/nvim/term.c index b7c30300b0..78fd3c6a67 100644 --- a/src/nvim/term.c +++ b/src/nvim/term.c @@ -170,6 +170,7 @@ static struct builtin_term builtin_termcaps[] = {(int)KS_DL, "\033|d"}, {(int)KS_CDL, "\033|%p1%dD"}, {(int)KS_CS, "\033|%p1%d;%p2%dR"}, + {(int)KS_CSV, "\033|%p1%d;%p2%dV"}, {(int)KS_CL, "\033|C"}, // attributes switched on with 'h', off with * 'H' {(int)KS_ME, "\033|31H"}, // HL_ALL @@ -1473,7 +1474,6 @@ int set_termname(char_u *term) # define HMT_NORMAL 1 # define HMT_NETTERM 2 # define HMT_DEC 4 -# define HMT_PTERM 8 # define HMT_URXVT 16 # define HMT_SGR 32 @@ -1488,7 +1488,7 @@ set_mouse_termcode ( add_termcode(name, s, FALSE); } -# if (defined(UNIX) && defined(FEAT_MOUSE_TTY)) || defined(PROTO) +# if (defined(UNIX) && defined(FEAT_MOUSE_TTY)) void del_mouse_termcode ( char_u n /* KS_MOUSE, KS_NETTERM_MOUSE or KS_DEC_MOUSE */ @@ -1705,7 +1705,7 @@ static char_u term_7to8bit(char_u *p) } -#if !defined(HAVE_TGETENT) || defined(PROTO) +#if !defined(HAVE_TGETENT) char_u *tltoa(unsigned long i) { @@ -1817,17 +1817,20 @@ void term_write(char_u *s, size_t len) static char_u out_buf[OUT_SIZE + 1]; static int out_pos = 0; /* number of chars in out_buf */ +// Clear the output buffer +void out_buf_clear(void) +{ + out_pos = 0; +} + /* * out_flush(): flush the output buffer */ void out_flush(void) { - if (out_pos != 0) { - /* set out_pos to 0 before ui_write, to avoid recursiveness */ - int len = out_pos; - out_pos = 0; - ui_write(out_buf, len); - } + int len = out_pos; + out_pos = 0; + ui_write(out_buf, len); } /* @@ -1946,7 +1949,7 @@ void term_delete_lines(int line_count) OUT_STR(tgoto((char *)T_CDL, 0, line_count)); } -#if defined(HAVE_TGETENT) || defined(PROTO) +#if defined(HAVE_TGETENT) void term_set_winpos(int x, int y) { /* Can't handle a negative value here */ @@ -2011,7 +2014,7 @@ static void term_color(char_u *s, int n) OUT_STR(tgoto((char *)s, 0, n)); } -#if defined(UNIX) || defined(MACOS_X) || defined(PROTO) +#if defined(UNIX) || defined(MACOS_X) /* * Generic function to set window title, using t_ts and t_fs. */ @@ -2203,7 +2206,11 @@ void win_new_shellsize(void) */ void shell_resized(void) { - screen_resize(0, 0, FALSE); + if (abstract_ui) { + ui_refresh(); + } else { + screen_resize(0, 0, FALSE); + } } /* diff --git a/src/nvim/testdir/test48.in b/src/nvim/testdir/test48.in index 25ea2fa154..998e1bba00 100644 --- a/src/nvim/testdir/test48.in +++ b/src/nvim/testdir/test48.in @@ -44,6 +44,10 @@ $4lDi<-- 'D' should be intact /^"r" $5lrxa<-- should be 'x' :" +:" Test "r" on a tab +:" Note that for this test, 'ts' must be 8 (the default). +^5lrxA<-- should be ' x ' +:" :" Test to make sure 'x' can delete control characters :set display=uhex ^xxxxxxi[This line should contain only the text between the brackets.] @@ -72,6 +76,7 @@ this is a test this is a test this is a test "r" +"r" ab
sd abcv6efi.him0kl diff --git a/src/nvim/testdir/test48.ok b/src/nvim/testdir/test48.ok index 334cb5a29c..14cd9b12ec 100644 --- a/src/nvim/testdir/test48.ok +++ b/src/nvim/testdir/test48.ok @@ -12,6 +12,7 @@ this is a test this is a test this is a test "r" x<-- should be 'x' +"r" x <-- should be ' x ' [This line should contain only the text between the brackets.] v i m <-- should show the name of a noted text editor 6 . 0 <-- and its version number diff --git a/src/nvim/ui.c b/src/nvim/ui.c index 25d6a81960..a8ca58d633 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -60,11 +60,8 @@ static struct { int top, bot, left, right; } sr; static int current_highlight_mask = 0; -static HlAttrs current_attrs = { - false, false, false, false, false, false, -1, -1 -}; static bool cursor_enabled = true; -static int height = INT_MAX, width = INT_MAX; +static int height, width; // This set of macros allow us to use UI_CALL to invoke any function on // registered UI instances. The functions can have 0-5 arguments(configurable @@ -98,6 +95,10 @@ void ui_write(uint8_t *s, int len) return; } + if (!len) { + return; + } + char_u *tofree = NULL; if (output_conv.vc_type != CONV_NONE) { @@ -113,6 +114,16 @@ void ui_write(uint8_t *s, int len) free(tofree); } +bool ui_rgb_attached(void) +{ + for (size_t i = 0; i < ui_count; i++) { + if (uis[i]->rgb) { + return true; + } + } + return false; +} + /* * If the machine has job control, use it to suspend the program, * otherwise fake it by starting a new shell. @@ -122,11 +133,24 @@ void ui_suspend(void) { if (abstract_ui) { UI_CALL(suspend); + UI_CALL(flush); } else { mch_suspend(); } } +void ui_set_title(char *title) +{ + UI_CALL(set_title, title); + UI_CALL(flush); +} + +void ui_set_icon(char *icon) +{ + UI_CALL(set_icon, icon); + UI_CALL(flush); +} + /* * Try to get the current Vim shell size. Put the result in Rows and Columns. * Use the new sizes as defaults for 'columns' and 'lines'. @@ -165,8 +189,31 @@ void ui_cursor_shape(void) } } -void ui_resize(int width, int height) +void ui_refresh(void) { + if (!ui_count) { + return; + } + + int width = INT_MAX, height = INT_MAX; + + for (size_t i = 0; i < ui_count; i++) { + UI *ui = uis[i]; + width = ui->width < width ? ui->width : width; + height = ui->height < height ? ui->height : height; + } + + screen_resize(width, height, true); +} + +void ui_resize(int new_width, int new_height) +{ + width = new_width; + height = new_height; + + UI_CALL(update_fg, (ui->rgb ? normal_fg : cterm_normal_fg_color - 1)); + UI_CALL(update_bg, (ui->rgb ? normal_bg : cterm_normal_bg_color - 1)); + sr.top = 0; sr.bot = height - 1; sr.left = 0; @@ -240,7 +287,7 @@ void ui_attach(UI *ui) } uis[ui_count++] = ui; - resized(ui); + ui_refresh(); } void ui_detach(UI *ui) @@ -267,17 +314,8 @@ void ui_detach(UI *ui) ui_count--; - if (ui->width == width || ui->height == height) { - // It is possible that the UI being detached had the smallest screen, - // so check for the new minimum dimensions - width = height = INT_MAX; - for (size_t i = 0; i < ui_count; i++) { - check_dimensions(uis[i]); - } - } - if (ui_count) { - screen_resize(width, height, true); + ui_refresh(); } } @@ -295,8 +333,7 @@ static void highlight_start(int mask) return; } - set_highlight_args(current_highlight_mask, ¤t_attrs); - UI_CALL(highlight_set, current_attrs); + set_highlight_args(current_highlight_mask); } static void highlight_stop(int mask) @@ -309,12 +346,12 @@ static void highlight_stop(int mask) current_highlight_mask &= ~mask; } - set_highlight_args(current_highlight_mask, ¤t_attrs); - UI_CALL(highlight_set, current_attrs); + set_highlight_args(current_highlight_mask); } -static void set_highlight_args(int mask, HlAttrs *attrs) +static void set_highlight_args(int mask) { + HlAttrs rgb_attrs = { false, false, false, false, false, -1, -1 }; attrentry_T *aep = NULL; if (mask > HL_ALL) { @@ -322,18 +359,40 @@ static void set_highlight_args(int mask, HlAttrs *attrs) mask = aep ? aep->ae_attr : 0; } - attrs->bold = mask & HL_BOLD; - attrs->standout = mask & HL_STANDOUT; - attrs->underline = mask & HL_UNDERLINE; - attrs->undercurl = mask & HL_UNDERCURL; - attrs->italic = mask & HL_ITALIC; - attrs->reverse = mask & HL_INVERSE; - attrs->foreground = aep && aep->fg_color >= 0 ? aep->fg_color : normal_fg; - attrs->background = aep && aep->bg_color >= 0 ? aep->bg_color : normal_bg; + rgb_attrs.bold = mask & HL_BOLD; + rgb_attrs.underline = mask & HL_UNDERLINE; + rgb_attrs.undercurl = mask & HL_UNDERCURL; + rgb_attrs.italic = mask & HL_ITALIC; + rgb_attrs.reverse = mask & (HL_INVERSE | HL_STANDOUT); + HlAttrs cterm_attrs = rgb_attrs; + + if (aep) { + if (aep->fg_color != normal_fg) { + rgb_attrs.foreground = aep->fg_color; + } + + if (aep->bg_color != normal_bg) { + rgb_attrs.background = aep->bg_color; + } + + if (cterm_normal_fg_color != aep->ae_u.cterm.fg_color) { + cterm_attrs.foreground = aep->ae_u.cterm.fg_color - 1; + } + + if (cterm_normal_bg_color != aep->ae_u.cterm.bg_color) { + cterm_attrs.background = aep->ae_u.cterm.bg_color - 1; + } + } + + UI_CALL(highlight_set, (ui->rgb ? rgb_attrs : cterm_attrs)); } static void parse_abstract_ui_codes(uint8_t *ptr, int len) { + if (!ui_count) { + return; + } + int arg1 = 0, arg2 = 0; uint8_t *end = ptr + len, *p, c; bool update_cursor = false; @@ -444,6 +503,9 @@ static void parse_abstract_ui_codes(uint8_t *ptr, int len) UI_CALL(put, NULL, 0); col++; } + if (col >= width) { + ui_linefeed(); + } p += clen; } ptr = p; @@ -457,25 +519,6 @@ static void parse_abstract_ui_codes(uint8_t *ptr, int len) UI_CALL(flush); } -static void resized(UI *ui) -{ - check_dimensions(ui); - screen_resize(width, height, true); -} - -static void check_dimensions(UI *ui) -{ - // The internal screen dimensions are always the minimum required to fit on - // all connected screens - if (ui->width < width) { - width = ui->width; - } - - if (ui->height < height) { - height = ui->height; - } -} - static void ui_linefeed(void) { int new_col = 0; diff --git a/src/nvim/ui.h b/src/nvim/ui.h index d0933055cc..099f2643d5 100644 --- a/src/nvim/ui.h +++ b/src/nvim/ui.h @@ -6,13 +6,14 @@ #include <stdint.h> typedef struct { - bool bold, standout, underline, undercurl, italic, reverse; + bool bold, underline, undercurl, italic, reverse; int foreground, background; } HlAttrs; typedef struct ui_t UI; struct ui_t { + bool rgb; int width, height; void *data; void (*resize)(UI *ui, int rows, int columns); @@ -32,7 +33,11 @@ struct ui_t { void (*bell)(UI *ui); void (*visual_bell)(UI *ui); void (*flush)(UI *ui); + void (*update_fg)(UI *ui, int fg); + void (*update_bg)(UI *ui, int bg); void (*suspend)(UI *ui); + void (*set_title)(UI *ui, char *title); + void (*set_icon)(UI *ui, char *icon); }; #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/undo.c b/src/nvim/undo.c index 59920cfbe1..4d84c69158 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -128,7 +128,7 @@ static int undo_undoes = FALSE; static int lastmark = 0; -#if defined(U_DEBUG) || defined(PROTO) +#if defined(U_DEBUG) /* * Check the undo structures for being valid. Print a warning when something * looks wrong. diff --git a/src/nvim/version.c b/src/nvim/version.c index 9b87cbe99a..3e214bfd30 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -178,6 +178,13 @@ static char *(features[]) = { }; static int included_patches[] = { + 567, + //566, + //565, + //564, + 563, + //562, + //561, //560 NA 559, //558 NA @@ -272,6 +279,7 @@ static int included_patches[] = { //469 NA 468, 467, + 466, //465 NA //464 NA 463, diff --git a/src/nvim/window.c b/src/nvim/window.c index 0e336e8cbe..cf0977e280 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -371,7 +371,10 @@ newwindow: postponed_split = Prenum; else postponed_split = -1; - g_do_tagpreview = 0; + + if (nchar != '}') { + g_do_tagpreview = 0; + } // Execute the command right here, required when // "wincmd ]" was used in a function. @@ -2057,7 +2060,7 @@ win_free_mem ( return wp; } -#if defined(EXITFREE) || defined(PROTO) +#if defined(EXITFREE) void win_free_all(void) { int dummy; diff --git a/test/functional/legacy/066_visual_block_tab_spec.lua b/test/functional/legacy/066_visual_block_tab_spec.lua index cd283e6746..82bb988c67 100644 --- a/test/functional/legacy/066_visual_block_tab_spec.lua +++ b/test/functional/legacy/066_visual_block_tab_spec.lua @@ -23,18 +23,18 @@ describe('visual block shift and tab characters', function() abcdefghijklmnopqrstuvwxyz]]) feed('gg') - feed([[fe<C-v>4jR<esc>ugvr1:'<,'>yank A<cr>]]) + feed([[fe<C-v>4jR<esc>ugvr1:'<lt>,'>yank A<cr>]]) execute('/^abcdefgh') - feed('<C-v>4jI <esc>j<<11|D') + feed('<C-v>4jI <esc>j<lt><lt>11|D') feed('j7|a <esc>') feed('j7|a <esc>') - feed('j7|a <esc>4k13|<C-v>4j<') + feed('j7|a <esc>4k13|<C-v>4j<lt>') execute('$-5,$yank A') execute([[$-4,$s/\s\+//g]]) - feed('<C-v>4kI <esc>j<<') + feed('<C-v>4kI <esc>j<lt><lt>') feed('j7|a <esc>') feed('j7|a <esc>') - feed('j7|a <esc>4k13|<C-v>4j3<') + feed('j7|a <esc>4k13|<C-v>4j3<lt>') execute('$-4,$yank A') -- Put @a and clean empty lines diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index 3c55c09f95..701297cc15 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -1,7 +1,30 @@ local helpers = require('test.functional.helpers') local Screen = require('test.functional.ui.screen') local clear, feed, nvim = helpers.clear, helpers.feed, helpers.nvim -local execute = helpers.execute +local execute, request, eq = helpers.execute, helpers.request, helpers.eq + + +describe('color scheme compatibility', function() + before_each(function() + clear() + end) + + it('t_Co is set to 256 by default', function() + eq('256', request('vim_eval', '&t_Co')) + request('vim_set_option', 't_Co', '88') + eq('88', request('vim_eval', '&t_Co')) + end) + + it('emulates gui_running when a rgb UI is attached', function() + eq(0, request('vim_eval', 'has("gui_running")')) + local screen = Screen.new() + screen:attach() + eq(1, request('vim_eval', 'has("gui_running")')) + screen:detach() + eq(0, request('vim_eval', 'has("gui_running")')) + end) +end) + describe('Default highlight groups', function() -- Test the default attributes for highlight groups shown by the :highlight @@ -24,7 +47,6 @@ describe('Default highlight groups', function() after_each(function() screen:detach() end) - it('window status bar', function() screen:set_default_attr_ids({ [1] = {reverse = true, bold = true}, -- StatusLine @@ -142,7 +164,6 @@ describe('Default highlight groups', function() end) it('end of file markers', function() - nvim('command', 'hi Normal guibg=black') screen:expect([[ ^ | {1:~ }| diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua index 507b5aacae..653d8ad92c 100644 --- a/test/functional/ui/mouse_spec.lua +++ b/test/functional/ui/mouse_spec.lua @@ -1,6 +1,7 @@ local helpers = require('test.functional.helpers') local Screen = require('test.functional.ui.screen') local clear, feed, nvim = helpers.clear, helpers.feed, helpers.nvim +local insert, execute = helpers.insert, helpers.execute describe('Mouse input', function() local screen, hlgroup_colors @@ -154,4 +155,87 @@ describe('Mouse input', function() ]]) feed('<cr>') end) + + it('mouse whell will target the hovered window', function() + feed('ggdG') + insert([[ + Inserting + text + with + many + lines + to + test + mouse scrolling + ]]) + screen:try_resize(53, 14) + execute('sp', 'vsp') + screen:expect([[ + lines |lines | + to |to | + test |test | + mouse scrolling |mouse scrolling | + ^ | | + ~ |~ | + [No Name] [+] [No Name] [+] | + to | + test | + mouse scrolling | + | + ~ | + [No Name] [+] | + :vsp | + ]]) + feed('<MouseUp><0,0>') + screen:expect([[ + mouse scrolling |lines | + ^ |to | + ~ |test | + ~ |mouse scrolling | + ~ | | + ~ |~ | + [No Name] [+] [No Name] [+] | + to | + test | + mouse scrolling | + | + ~ | + [No Name] [+] | + | + ]]) + feed('<MouseDown><27,0>') + screen:expect([[ + mouse scrolling |text | + ^ |with | + ~ |many | + ~ |lines | + ~ |to | + ~ |test | + [No Name] [+] [No Name] [+] | + to | + test | + mouse scrolling | + | + ~ | + [No Name] [+] | + | + ]]) + feed('<MouseDown><27,7><MouseDown>') + screen:expect([[ + mouse scrolling |text | + ^ |with | + ~ |many | + ~ |lines | + ~ |to | + ~ |test | + [No Name] [+] [No Name] [+] | + Inserting | + text | + with | + many | + lines | + [No Name] [+] | + | + ]]) + end) end) diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 8e7d1ed798..105e43843c 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -83,6 +83,21 @@ local eq, dedent = helpers.eq, helpers.dedent local Screen = {} Screen.__index = Screen +local debug_screen + + +function Screen.debug(command) + if not command then + command = 'pynvim -n -g -c ' + end + command = command .. request('vim_eval', '$NVIM_LISTEN_ADDRESS') + if debug_screen then + debug_screen:close() + end + debug_screen = io.popen(command, 'r') + debug_screen:read() +end + function Screen.new(width, height) if not width then width = 53 @@ -90,24 +105,22 @@ function Screen.new(width, height) if not height then height = 14 end - return setmetatable({ + local self = setmetatable({ + title = '', + icon = '', + bell = false, + visual_bell = false, + suspended = false, _default_attr_ids = nil, - _width = width, - _height = height, - _rows = new_cell_grid(width, height), _mode = 'normal', _mouse_enabled = true, - _bell = false, - _visual_bell = false, - _suspended = true, _attrs = {}, _cursor = { enabled = true, row = 1, col = 1 - }, - _scroll_region = { - top = 1, bot = height, left = 1, right = width } }, Screen) + self:_handle_resize(width, height) + return self end function Screen:set_default_attr_ids(attr_ids) @@ -115,13 +128,15 @@ function Screen:set_default_attr_ids(attr_ids) end function Screen:attach() - request('attach_ui', self._width, self._height) - self._suspended = false + request('ui_attach', self._width, self._height, true) end function Screen:detach() - request('detach_ui') - self._suspended = true + request('ui_detach') +end + +function Screen:try_resize(columns, rows) + request('ui_try_resize', columns, rows) end function Screen:expect(expected, attr_ids) @@ -134,7 +149,7 @@ function Screen:expect(expected, attr_ids) table.insert(expected_rows, row) end local ids = attr_ids or self._default_attr_ids - self:_wait(function() + self:wait(function() for i = 1, self._height do local expected_row = expected_rows[i] local actual_row = self:_row_repr(self._rows[i], ids) @@ -146,7 +161,7 @@ function Screen:expect(expected, attr_ids) end) end -function Screen:_wait(check, timeout) +function Screen:wait(check, timeout) local err, checked = false local function notification_cb(method, args) assert(method == 'redraw') @@ -181,16 +196,30 @@ function Screen:_redraw(updates) end function Screen:_handle_resize(width, height) - self._rows = new_cell_grid(width, height) + local rows = {} + for i = 1, height do + local cols = {} + for j = 1, width do + table.insert(cols, {text = ' ', attrs = {}}) + end + table.insert(rows, cols) + end + self._rows = rows + self._width = width + self._height = height + self._scroll_region = { + top = 1, bot = height, left = 1, right = width + } end function Screen:_handle_clear() - self:_clear_block(1, self._height, 1, self._width) + self:_clear_block(self._scroll_region.top, self._scroll_region.bot, + self._scroll_region.left, self._scroll_region.right) end function Screen:_handle_eol_clear() local row, col = self._cursor.row, self._cursor.col - self:_clear_block(row, 1, col, self._width - col) + self:_clear_block(row, 1, col, self._scroll_region.right - col) end function Screen:_handle_cursor_goto(row, col) @@ -250,11 +279,14 @@ function Screen:_handle_scroll(count) for i = start, stop, step do local target = self._rows[i] local source = self._rows[i + count] - self:_copy_row_section(target, source, left, right) + for j = left, right do + target[j].text = source[j].text + target[j].attrs = source[j].attrs + end end -- clear invalid rows - for i = stop + 1, stop + count, step do + for i = stop + step, stop + count, step do self:_clear_row_section(i, left, right) end end @@ -271,15 +303,31 @@ function Screen:_handle_put(str) end function Screen:_handle_bell() - self._bell = true + self.bell = true end function Screen:_handle_visual_bell() - self._visual_bell = true + self.visual_bell = true +end + +function Screen:_handle_update_fg(fg) + self._fg = fg +end + +function Screen:_handle_update_bg(bg) + self._bg = bg end function Screen:_handle_suspend() - self._suspended = true + self.suspended = true +end + +function Screen:_handle_set_title(title) + self.title = title +end + +function Screen:_handle_set_icon(icon) + self.icon = icon end function Screen:_clear_block(top, lines, left, columns) @@ -296,13 +344,6 @@ function Screen:_clear_row_section(rownum, startcol, stopcol) end end -function Screen:_copy_row_section(target, source, startcol, stopcol) - for i = startcol, stopcol do - target[i].text = source[i].text - target[i].attrs = source[i].attrs - end -end - function Screen:_row_repr(row, attr_ids) local rv = {} local current_attr_id @@ -353,18 +394,6 @@ function backward_find_meaningful(tbl, from) return from end -function new_cell_grid(width, height) - local rows = {} - for i = 1, height do - local cols = {} - for j = 1, width do - table.insert(cols, {text = ' ', attrs = {}}) - end - table.insert(rows, cols) - end - return rows -end - function get_attr_id(attr_ids, attrs) if not attr_ids then return diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua index a1110b3231..4ee6c43528 100644 --- a/test/functional/ui/screen_basic_spec.lua +++ b/test/functional/ui/screen_basic_spec.lua @@ -16,6 +16,69 @@ describe('Screen', function() screen:detach() end) + describe(':suspend', function() + it('is forwarded to the UI', function() + local function check() + if not screen.suspended then + return 'Screen was not suspended' + end + end + execute('suspend') + screen:wait(check) + screen.suspended = false + feed('<c-z>') + screen:wait(check) + end) + end) + + describe('bell/visual bell', function() + it('is forwarded to the UI', function() + feed('<left>') + screen:wait(function() + if not screen.bell or screen.visual_bell then + return 'Bell was not sent' + end + end) + screen.bell = false + execute('set visualbell') + feed('<left>') + screen:wait(function() + if not screen.visual_bell or screen.bell then + return 'Visual bell was not sent' + end + end) + end) + end) + + describe(':set title', function() + it('is forwarded to the UI', function() + local expected = 'test-title' + execute('set titlestring='..expected) + execute('set title') + screen:wait(function() + local actual = screen.title + if actual ~= expected then + return 'Expected title to be "'..expected..'" but was "'..actual..'"' + end + end) + end) + end) + + describe(':set icon', function() + it('is forwarded to the UI', function() + local expected = 'test-icon' + execute('set iconstring='..expected) + execute('set icon') + screen:wait(function() + local actual = screen.icon + if actual ~= expected then + return 'Expected title to be "'..expected..'" but was "'..actual..'"' + end + end) + end) + end) + + describe('window', function() describe('split', function() it('horizontal', function() @@ -95,6 +158,8 @@ describe('Screen', function() | ]]) end) + + end) end) @@ -221,4 +286,193 @@ describe('Screen', function() feed('<cr>') -- skip the "Press ENTER..." state or tests will hang end) end) + + describe('scrolling and clearing', function() + before_each(function() + insert([[ + Inserting + text + with + many + lines + to + test + scrolling + and + clearing + in + split + windows + ]]) + execute('sp', 'vsp', 'vsp') + screen:expect([[ + and |and |and | + clearing |clearing |clearing | + in |in |in | + split |split |split | + windows |windows |windows | + ^ | | | + [No Name] [+] [No Name] [+] [No Name] [+] | + clearing | + in | + split | + windows | + | + [No Name] [+] | + | + ]]) + end) + + it('only affects the current scroll region', function() + feed('6k') + screen:expect([[ + ^crolling |and |and | + and |clearing |clearing | + clearing |in |in | + in |split |split | + split |windows |windows | + windows | | | + [No Name] [+] [No Name] [+] [No Name] [+] | + clearing | + in | + split | + windows | + | + [No Name] [+] | + | + ]]) + feed('<c-w>l') + screen:expect([[ + scrolling |and |and | + and |clearing |clearing | + clearing |in |in | + in |split |split | + split |windows |windows | + windows |^ | | + [No Name] [+] [No Name] [+] <Name] [+] | + clearing | + in | + split | + windows | + | + [No Name] [+] | + | + ]]) + feed('gg') + screen:expect([[ + scrolling |^nserting |and | + and |text |clearing | + clearing |with |in | + in |many |split | + split |lines |windows | + windows |to | | + [No Name] [+] [No Name] [+] <Name] [+] | + clearing | + in | + split | + windows | + | + [No Name] [+] | + | + ]]) + feed('7j') + screen:expect([[ + scrolling |with |and | + and |many |clearing | + clearing |lines |in | + in |to |split | + split |test |windows | + windows |^crolling | | + [No Name] [+] [No Name] [+] <Name] [+] | + clearing | + in | + split | + windows | + | + [No Name] [+] | + | + ]]) + feed('2j') + screen:expect([[ + scrolling |lines |and | + and |to |clearing | + clearing |test |in | + in |scrolling |split | + split |and |windows | + windows |^learing | | + [No Name] [+] [No Name] [+] <Name] [+] | + clearing | + in | + split | + windows | + | + [No Name] [+] | + | + ]]) + feed('5k') + screen:expect([[ + scrolling |^ines |and | + and |to |clearing | + clearing |test |in | + in |scrolling |split | + split |and |windows | + windows |clearing | | + [No Name] [+] [No Name] [+] <Name] [+] | + clearing | + in | + split | + windows | + | + [No Name] [+] | + | + ]]) + feed('k') + screen:expect([[ + scrolling |^any |and | + and |lines |clearing | + clearing |to |in | + in |test |split | + split |scrolling |windows | + windows |and | | + [No Name] [+] [No Name] [+] <Name] [+] | + clearing | + in | + split | + windows | + | + [No Name] [+] | + | + ]]) + end) + end) + + describe('resize', function() + before_each(function() + screen:try_resize(25, 5) + feed('iresize') + end) + + it('rebuilds the whole screen', function() + screen:expect([[ + resize^ | + ~ | + ~ | + ~ | + -- INSERT -- | + ]]) + end) + + it('has minimum width/height values', function() + screen:try_resize(1, 1) + screen:expect([[ + -- INS^RT --| + | + ]]) + feed('<esc>:ls') + screen:expect([[ + resize | + :ls^ | + ]]) + end) + end) end) diff --git a/test/unit/formatc.lua b/test/unit/formatc.lua index 792894f349..f9397eaec6 100644 --- a/test/unit/formatc.lua +++ b/test/unit/formatc.lua @@ -149,8 +149,7 @@ local C_keywords = set { -- }; -- -- would become: --- struct mystruct --- { int a; int b; }; +-- struct mystruct { int a; int b; }; -- -- The first one will have a lot of false positives (the line '{' for -- example), the second one is more unique. @@ -179,7 +178,8 @@ local function formatc(str) -- static and/or inline usually indicate an inline header function, -- which has no trailing ';', so we have to add a newline after the -- '}' ourselves. - if token[1] == 'static' or token[1] == 'inline' then + local tok = token[1] + if tok == 'static' or tok == 'inline' or tok == '__inline' then end_at_brace = true end elseif typ == 'preprocessor' then diff --git a/test/unit/os/fs_spec.lua b/test/unit/os/fs_spec.lua index 2d54dc6003..90f5a0b7de 100644 --- a/test/unit/os/fs_spec.lua +++ b/test/unit/os/fs_spec.lua @@ -33,11 +33,11 @@ local absolute_executable = nil local executable_name = nil local function assert_file_exists(filepath) - eq(false, nil == (lfs.attributes(filepath, 'r'))) + neq(nil, lfs.attributes(filepath)) end local function assert_file_does_not_exist(filepath) - eq(true, nil == (lfs.attributes(filepath, 'r'))) + eq(nil, lfs.attributes(filepath)) end describe('fs function', function() diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt index debad7bf85..7c5906931d 100644 --- a/third-party/CMakeLists.txt +++ b/third-party/CMakeLists.txt @@ -73,9 +73,9 @@ set(LIBTERMKEY_URL https://github.com/neovim/libtermkey/archive/7b3bdafdf589d084 set(LIBTERMKEY_SHA1 28bfe54dfd9269910a132b51dee7725a2121578d) set(LIBTERMKEY_MD5 f0bac9c2467cc80c821be937ea5c13bc) -set(LIBTICKIT_URL https://github.com/neovim/libtickit/archive/0430ba2f43fdf1c31bca66def52a2537c581ade5.tar.gz) -set(LIBTICKIT_SHA1 732b145a4dab06e6f1b40a352424f808730726bf) -set(LIBTICKIT_MD5 3fcb635e572851472fc5009709d980fe) +set(LIBTICKIT_URL https://github.com/neovim/libtickit/archive/33f4afb3891df05955429acbf5b406dfe87ec22b.tar.gz) +set(LIBTICKIT_SHA1 3aab459b9fb3cd83e85ac2e08f05e5f162c8c9d2) +set(LIBTICKIT_MD5 19ee9271c16716620d0906db74158ec6) if(USE_BUNDLED_LIBUNIBILIUM) ExternalProject_Add(libunibilium |