The terminfo entry for linux only advertises 8 colours, but nvim tries
to make it display 16 colours anyway, resulting in erroneous SGR control
sequences for colours 8 and above. The Linux kernel terminal emulator
itself has actually understood the 256-colour control sequences since
version 4.8 and the 16-colour control sequences since version 4.9. Thus
we apply the same terminfo fixup as we apply for *xterm* and *256*, to
emit the 16-colour and 256-colour control sequences even if terminfo's
setaf and setab do not advertise them.
For CI builds unibilium is provided through msys2 packages, and
libtermkey is built from source in third-party from equalsraf/libtermkey.
In Windows we cannot read terminal input from the stdin file descriptor,
instead use libuv's uv_tty API. It should handle key input and encoding.
The UI suspend is not implemented for Windows, because the
SIGSTP/SIGCONT do not exist in windows. Currently this is a NOOP.
Closes#3902Closes#6640
Asynchronous API functions are served immediately, which means pending
input could change the state of Nvim shortly after an async API function
result is returned.
nvim_get_mode() is different:
- If RPCs are known to be blocked, it responds immediately (without
flushing the input/event queue)
- else it is handled just-in-time before waiting for input, after
pending input was processed. This makes the result more reliable
(but not perfect).
Internally this is handled as a special case, but _semantically_ nothing
has changed: API users never know when input flushes, so this internal
special-case doesn't violate that. As far as API users are concerned,
nvim_get_mode() is just another asynchronous API function.
In all cases nvim_get_mode() never blocks for more than the time it
takes to flush the input/event queue (~µs).
Note: This doesn't address #6166; nvim_get_mode() will provoke #6166 if
e.g. `d` is operator-pending.
Closes#6159
For now only supports valid hex colors (does not check for the validity
the hex color) when termguicolors is set, otherwise it won't attempt to
change the cursor color.
If we get a mouse_on/mouse_off event, but the mouse is already in the
corresponding state, there's no need to send the event up to the
terminal.
Closes#4394
bridge.width and bridge.height reach ui.c:ui_refresh() when it iterates
through all UIs, so they do not need to be set directly by
tui.c:update_size().
Race found by helgrind:
==18532== Helgrind, a thread error detector
==18532== Copyright (C) 2007-2015, and GNU GPL'd, by OpenWorks LLP et al.
==18532== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==18532== Command: ./build/bin/nvim -u NONE --cmd set\ rtp+=~/.vim/bundle/vimfiler.vim,~/.vim/bundle/unite.vim --cmd runtime\ plugin/vimfiler.vim --cmd runtime\ plugin/unite.vim
==18532== Parent PID: 6477
==18532==
==18532== ---Thread-Announcement------------------------------------------
==18532==
==18532== Thread #2 was created
==18532== at 0x68FA98E: clone (clone.S:73)
==18532== by 0x5270179: create_thread (createthread.c:102)
==18532== by 0x5271BE2: pthread_create@@GLIBC_2.2.5 (pthread_create.c:679)
==18532== by 0x4C32B07: pthread_create_WRK (hg_intercepts.c:427)
==18532== by 0x4E53A3F: uv_thread_create (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
==18532== by 0x6A7154: ui_bridge_attach (ui_bridge.c:89)
==18532== by 0x6A164C: tui_start (tui.c:116)
==18532== by 0x6A4CFC: ui_builtin_start (ui.c:89)
==18532== by 0x55A825: main (main.c:433)
==18532==
==18532== ---Thread-Announcement------------------------------------------
==18532==
==18532== Thread #1 is the program's root thread
==18532==
==18532== ----------------------------------------------------------------
==18532==
==18532== Possible data race during write of size 4 at 0x770E7B4 by thread #2
==18532== Locks held: none
==18532== at 0x6A3071: update_size (tui.c:759)
==18532== by 0x6A30DB: sigwinch_cb (tui.c:269)
==18532== by 0x4D0A54: signal_event (signal.c:44)
==18532== by 0x4CDDB6: multiqueue_process_events (multiqueue.c:146)
==18532== by 0x4CD135: loop_poll_events (loop.c:56)
==18532== by 0x6A2451: tui_main (tui.c:239)
==18532== by 0x6A857A: ui_thread_run (ui_bridge.c:112)
==18532== by 0x4E539F6: ??? (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
==18532== by 0x4C32D06: mythread_wrapper (hg_intercepts.c:389)
==18532== by 0x5271423: start_thread (pthread_create.c:333)
==18532== by 0x68FA9BE: clone (clone.S:105)
==18532==
==18532== This conflicts with a previous read of size 4 by thread #1
==18532== Locks held: none
==18532== at 0x6A542A: ui_refresh (ui.c:169)
==18532== by 0x6A5870: ui_refresh_event (ui.c:181)
==18532== by 0x4CDDB6: multiqueue_process_events (multiqueue.c:146)
==18532== by 0x4CD135: loop_poll_events (loop.c:56)
==18532== by 0x5DEDB4: os_breakcheck (input.c:150)
==18532== by 0x59263D: line_breakcheck (misc1.c:2667)
==18532== by 0x621AE5: nfa_regmatch (regexp_nfa.c:6171)
==18532== by 0x61DCF7: nfa_regtry (regexp_nfa.c:6240)
==18532== Address 0x770e7b4 is 4 bytes inside a block of size 352 alloc'd
==18532== at 0x4C2EFE5: calloc (vg_replace_malloc.c:711)
==18532== by 0x57C962: xcalloc (memory.c:119)
==18532== by 0x6A6E29: ui_bridge_attach (ui_bridge.c:53)
==18532== by 0x6A164C: tui_start (tui.c:116)
==18532== by 0x6A4CFC: ui_builtin_start (ui.c:89)
==18532== by 0x55A825: main (main.c:433)
==18532== Block was alloc'd by thread #1
==18532==
==18532== ----------------------------------------------------------------
==18532==
==18532== Possible data race during write of size 4 at 0x770E7B8 by thread #2
==18532== Locks held: none
==18532== at 0x6A3085: update_size (tui.c:760)
==18532== by 0x6A30DB: sigwinch_cb (tui.c:269)
==18532== by 0x4D0A54: signal_event (signal.c:44)
==18532== by 0x4CDDB6: multiqueue_process_events (multiqueue.c:146)
==18532== by 0x4CD135: loop_poll_events (loop.c:56)
==18532== by 0x6A2451: tui_main (tui.c:239)
==18532== by 0x6A857A: ui_thread_run (ui_bridge.c:112)
==18532== by 0x4E539F6: ??? (in /usr/lib/x86_64-linux-gnu/libuv.so.1.0.0)
==18532== by 0x4C32D06: mythread_wrapper (hg_intercepts.c:389)
==18532== by 0x5271423: start_thread (pthread_create.c:333)
==18532== by 0x68FA9BE: clone (clone.S:105)
==18532==
==18532== This conflicts with a previous read of size 4 by thread #1
==18532== Locks held: none
==18532== at 0x6A5455: ui_refresh (ui.c:170)
==18532== by 0x6A5870: ui_refresh_event (ui.c:181)
==18532== by 0x4CDDB6: multiqueue_process_events (multiqueue.c:146)
==18532== by 0x4CD135: loop_poll_events (loop.c:56)
==18532== by 0x5DEDB4: os_breakcheck (input.c:150)
==18532== by 0x59263D: line_breakcheck (misc1.c:2667)
==18532== by 0x621AE5: nfa_regmatch (regexp_nfa.c:6171)
==18532== by 0x61DCF7: nfa_regtry (regexp_nfa.c:6240)
==18532== Address 0x770e7b8 is 8 bytes inside a block of size 352 alloc'd
==18532== at 0x4C2EFE5: calloc (vg_replace_malloc.c:711)
==18532== by 0x57C962: xcalloc (memory.c:119)
==18532== by 0x6A6E29: ui_bridge_attach (ui_bridge.c:53)
==18532== by 0x6A164C: tui_start (tui.c:116)
==18532== by 0x6A4CFC: ui_builtin_start (ui.c:89)
==18532== by 0x55A825: main (main.c:433)
==18532== Block was alloc'd by thread #1
As discussed in neovim/neovim#5977, it's typical for the terminfo
database to disable cursor blink as part of setting up the normal
cursor. Since this interferes with the user's control over the cursor,
we'll skip over DECRST 12 if it starts the cursor_normal entry.
Note, this doesn't handle any case where DECRST 12 is not at the start
of the entry since unibilium simply stores the given pointer. We would
need to allocate (and somewhere free) a modified copy of what we get
back from unibi_get_str to handle that.
Also give NVIM_TUI_ENABLE_CURSOR_SHAPE more granularity:
0 = do not change cursor shape
1 = non-blinking ("steady") cursor with mode-sensitive shape
2 = blinking cursor with mode-sensitive shape
Note: blink state is not changed for Konsole, instead user's terminal
preference makes the decision. (Can't do that for xterm-likes, DECSCUSR
forces us to choose blink-state.)
This is a temporary step until the TUI respects 'guicursor'
Ref: https://github.com/neovim/neovim/issues/2583#issuecomment-272988384
"CSI ? 12 l" stops cursor blinking. `unibi_cursor_normal` need only
_show_ the cursor, not make any pronouncement about cursor blinking.
User's terminal setting (or NVIM_TUI_ENABLE_CURSOR_SHAPE) takes
precedence.
Closes#1234
multiqueue:
- Implement multiqueue_size()
- Rename MultiQueueItem.parent to MultiQueueItem.parent_item, to avoid confusion
with MultiQueue.parent.
Eliminate mb_init():
Set "enc_utf" and "has_mbyte" early. Eliminate "enc_unicode" and "enc_latin1like".
init_chartab() and screenalloc() are already invoked elsewhere
in the initialization process.
The EncodingChanged autocmd cannot be triggered.
At initialization, there is no spellfiles to reload
Set STDIN to blocking on "suspend". This was missed in #2598.
See 8a782f1699.
Also on "continue"/SIGCONT explicitly set STDIN back to NON-blocking.
We don't explicitly do that on *startup* (libuv does it internally),
but on "continue" it seems wise to restore libuv's expectations.
Closes#5459
unibi_format() calls out() multiple times for a given format string.
When data->buf fills up during this process, flush_buf() gets called,
which possibly calls unibi_out() again to toggle the cursor visibility.
However, if we were halfway through outputting an escape sequence, doing
this will clobber it, resulting in junk being displayed.
Fix this by not toggling the cursor visibility when draining a full
buffer in out().
References #4867
For users who use a "bar" shape in the shell, it's annoying that Nvim starts
with that same cursor shape, despite starting in normal-mode. So default to the
normal-mode "block" shape instead. (Note: technically it's possible some user
may set 'insertmode', and then the opposite problem occurs. But 'insertmode' is
a silly option that shouldn't exist, and any user that uses it probably isn't
fiddling with their cursor shape anyways.)
Also rename the unibilium extensions:
enter_insert_mode => set_cursor_shape_bar
enter_replace_mode => set_cursor_shape_underline
exit_insert_mode => set_cursor_shape_block
to say explicitly what they do in the context of a terminal; it's irrelevant in
this context what purpose they serve in Nvim.
`lib/queue.h` implements a basic queue. `event/queue.c` implements
a specialized data structure on top of lib/queue.h; it is not a "normal"
queue.
Rename the specialized multi-level queue implemented in event/queue.c to
"multiqueue", to avoid confusion when reading the code.
Before this change one can eventually notice that "macros (uppercase
symbols) are for the normal queue, lowercase operations are for the
multi-level queue", but that is unnecessary friction for new developers
(or existing developers just visiting this part of the codebase).
Because terminfo_stop() already ran, there is not much reason to wait
for the loop to teardown.
Helped-by: Björn Linse <bjorn.linse@gmail.com>
Helped-by: oni-link <knil.ino@gmail.com>
Closes#4778
References #3541
---
Bug report:
> After pressing `ZZ` I can find two threads freezing, occupying 100% CPU:
|-systemd-+
|-nvim,11567 /home/lz/code/1.rs +set title
| `-{nvim},11574
> 11567 has two threads:
(gdb) info threads
Id Target Id Frame
* 1 Thread 0x7f7622907780 (LWP 11567) "nvim" 0x00007f76222e66bd in pthread_join () from /usr/lib/libpthread.so.0
2 Thread 0x7f761f5ff700 (LWP 11574) "nvim" 0x00007ffcec9e9c59 in clock_gettime ()
(gdb) thread apply all bt
Thread 2 (Thread 0x7f761f5ff700 (LWP 11574)):
#0 0x00007ffcec9e9c59 in clock_gettime ()
#1 0x00007f76210b9356 in clock_gettime () from /usr/lib/libc.so.6
#2 0x00007f7622513e3c in ?? () from /usr/lib/libuv.so.1
#3 0x00007f7622505e94 in uv_run () from /usr/lib/libuv.so.1
#4 0x00000000004822ed in loop_close (loop=loop@entry=0x7f761f5fe870) at /tmp/yaourt-tmp-lz/aur-neovim-git/src/neovim-git/src/nvim/event/loop.c:87
#5 0x00000000005a7ec0 in tui_main (bridge=0x7f761f6ac000, ui=0x7f761f69ace0) at /tmp/yaourt-tmp-lz/aur-neovim-git/src/neovim-git/src/nvim/tui/tui.c:234
#6 0x00000000005a9b47 in ui_thread_run (data=<optimized out>) at /tmp/yaourt-tmp-lz/aur-neovim-git/src/neovim-git/src/nvim/ui_bridge.c:87
#7 0x00007f7622510d07 in ?? () from /usr/lib/libuv.so.1
#8 0x00007f76222e5474 in start_thread () from /usr/lib/libpthread.so.0
#9 0x00007f76210ac69d in clone () from /usr/lib/libc.so.6
Thread 1 (Thread 0x7f7622907780 (LWP 11567)):
#0 0x00007f76222e66bd in pthread_join () from /usr/lib/libpthread.so.0
#1 0x00007f7622510dae in uv_thread_join () from /usr/lib/libuv.so.1
#2 0x00000000005aac9e in ui_bridge_stop (b=0x7f761f6ac000) at /tmp/yaourt-tmp-lz/aur-neovim-git/src/neovim-git/src/nvim/ui_bridge.c:104
#3 0x00000000005a90e4 in ui_builtin_stop () at /tmp/yaourt-tmp-lz/aur-neovim-git/src/neovim-git/src/nvim/ui.c:91
#4 0x000000000052be09 in mch_exit (r=r@entry=1) at /tmp/yaourt-tmp-lz/aur-neovim-git/src/neovim-git/src/nvim/os_unix.c:143
#5 0x00000000004db1cc in getout (exitval=exitval@entry=1) at /tmp/yaourt-tmp-lz/aur-neovim-git/src/neovim-git/src/nvim/main.c:623
#6 0x00000000004fa43c in preserve_exit () at /tmp/yaourt-tmp-lz/aur-neovim-git/src/neovim-git/src/nvim/misc1.c:2652
#7 0x000000000052b77a in deadly_signal (signum=1) at /tmp/yaourt-tmp-lz/aur-neovim-git/src/neovim-git/src/nvim/os/signal.c:120
#8 0x000000000052b7cf in on_signal (handle=<optimized out>, signum=<optimized out>, data=<optimized out>) at /tmp/yaourt-tmp-lz/aur-neovim-git/src/neovim-git/src/nvim/os/signal.c:145
#9 0x0000000000484178 in signal_event (argv=<optimized out>) at /tmp/yaourt-tmp-lz/aur-neovim-git/src/neovim-git/src/nvim/event/signal.c:44
#10 0x0000000000483b7f in queue_process_events (queue=0x7f7620417360) at /tmp/yaourt-tmp-lz/aur-neovim-git/src/neovim-git/src/nvim/event/queue.c:142
#11 0x0000000000482208 in loop_poll_events (loop=0x84dec0 <loop>, ms=ms@entry=4000) at /tmp/yaourt-tmp-lz/aur-neovim-git/src/neovim-git/src/nvim/event/loop.c:56
#12 0x000000000052a364 in input_poll (ms=ms@entry=4000) at /tmp/yaourt-tmp-lz/aur-neovim-git/src/neovim-git/src/nvim/os/input.c:325
#13 0x000000000052a3e2 in inbuf_poll (ms=4000) at /tmp/yaourt-tmp-lz/aur-neovim-git/src/neovim-git/src/nvim/os/input.c:347
#14 0x000000000052a839 in os_inchar (buf=buf@entry=0x0, maxlen=maxlen@entry=0, ms=ms@entry=-1, tb_change_cnt=tb_change_cnt@entry=0) at /tmp/yaourt-tmp-lz/aur-neovim-git/src/neovim-git/src/nvim/os/input.c:107
#15 0x0000000000592eeb in state_enter (s=s@entry=0x7ffcec9d3560) at /tmp/yaourt-tmp-lz/aur-neovim-git/src/neovim-git/src/nvim/state.c:46
#16 0x0000000000508533 in normal_enter (cmdwin=cmdwin@entry=false, noexmode=noexmode@entry=false) at /tmp/yaourt-tmp-lz/aur-neovim-git/src/neovim-git/src/nvim/normal.c:464
#17 0x00000000004dc17e in main (argc=<optimized out>, argv=<optimized out>) at /tmp/yaourt-tmp-lz/aur-neovim-git/src/neovim-git/src/nvim/main.c:538