mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 09:44:31 +00:00 
			
		
		
		
	fix(terminal): don't pass incomplete UTF-8 sequence to libvterm (#27922)
This commit is contained in:
		@@ -29,6 +29,7 @@
 | 
			
		||||
#include "nvim/log.h"
 | 
			
		||||
#include "nvim/lua/executor.h"
 | 
			
		||||
#include "nvim/main.h"
 | 
			
		||||
#include "nvim/mbyte.h"
 | 
			
		||||
#include "nvim/memory.h"
 | 
			
		||||
#include "nvim/message.h"
 | 
			
		||||
#include "nvim/msgpack_rpc/channel.h"
 | 
			
		||||
@@ -646,35 +647,52 @@ static inline list_T *buffer_to_tv_list(const char *const buf, const size_t len)
 | 
			
		||||
void on_channel_data(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof)
 | 
			
		||||
{
 | 
			
		||||
  Channel *chan = data;
 | 
			
		||||
  on_channel_output(stream, chan, buf, count, eof, &chan->on_data);
 | 
			
		||||
  on_channel_output(stream, chan, buf, eof, &chan->on_data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void on_job_stderr(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof)
 | 
			
		||||
{
 | 
			
		||||
  Channel *chan = data;
 | 
			
		||||
  on_channel_output(stream, chan, buf, count, eof, &chan->on_stderr);
 | 
			
		||||
  on_channel_output(stream, chan, buf, eof, &chan->on_stderr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void on_channel_output(Stream *stream, Channel *chan, RBuffer *buf, size_t count, bool eof,
 | 
			
		||||
static void on_channel_output(Stream *stream, Channel *chan, RBuffer *buf, bool eof,
 | 
			
		||||
                              CallbackReader *reader)
 | 
			
		||||
{
 | 
			
		||||
  // stub variable, to keep reading consistent with the order of events, only
 | 
			
		||||
  // consider the count parameter.
 | 
			
		||||
  size_t r;
 | 
			
		||||
  char *ptr = rbuffer_read_ptr(buf, &r);
 | 
			
		||||
  size_t count;
 | 
			
		||||
  char *output = rbuffer_read_ptr(buf, &count);
 | 
			
		||||
 | 
			
		||||
  if (chan->term) {
 | 
			
		||||
    if (!eof) {
 | 
			
		||||
      char *p = output;
 | 
			
		||||
      char *end = output + count;
 | 
			
		||||
      while (p < end) {
 | 
			
		||||
        // Don't pass incomplete UTF-8 sequences to libvterm. #16245
 | 
			
		||||
        // Composing chars can be passed separately, so utf_ptr2len_len() is enough.
 | 
			
		||||
        int clen = utf_ptr2len_len(p, (int)(end - p));
 | 
			
		||||
        if (clen > end - p) {
 | 
			
		||||
          count = (size_t)(p - output);
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
        p += clen;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    terminal_receive(chan->term, output, count);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (count) {
 | 
			
		||||
    rbuffer_consumed(buf, count);
 | 
			
		||||
  }
 | 
			
		||||
  // Move remaining data to start of buffer, so the buffer can never wrap around.
 | 
			
		||||
  rbuffer_reset(buf);
 | 
			
		||||
 | 
			
		||||
  if (callback_reader_set(*reader)) {
 | 
			
		||||
    ga_concat_len(&reader->buffer, output, count);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (eof) {
 | 
			
		||||
    reader->eof = true;
 | 
			
		||||
  } else {
 | 
			
		||||
    if (chan->term) {
 | 
			
		||||
      terminal_receive(chan->term, ptr, count);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    rbuffer_consumed(buf, count);
 | 
			
		||||
 | 
			
		||||
    if (callback_reader_set(*reader)) {
 | 
			
		||||
      ga_concat_len(&reader->buffer, ptr, count);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (callback_reader_set(*reader)) {
 | 
			
		||||
 
 | 
			
		||||
@@ -49,6 +49,10 @@ int main(int argc, char **argv)
 | 
			
		||||
    help();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
#ifdef _MSC_VER
 | 
			
		||||
  SetConsoleOutputCP(CP_UTF8);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  if (argc >= 2) {
 | 
			
		||||
    if (strcmp(argv[1], "-t") == 0) {
 | 
			
		||||
      if (argc < 3) {
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@ local pcall_err = helpers.pcall_err
 | 
			
		||||
local eq, neq = helpers.eq, helpers.neq
 | 
			
		||||
local api = helpers.api
 | 
			
		||||
local retry = helpers.retry
 | 
			
		||||
local testprg = helpers.testprg
 | 
			
		||||
local write_file = helpers.write_file
 | 
			
		||||
local command = helpers.command
 | 
			
		||||
local exc_exec = helpers.exc_exec
 | 
			
		||||
@@ -395,6 +396,20 @@ describe(':terminal buffer', function()
 | 
			
		||||
      eq('a' .. composing:rep(5), api.nvim_get_current_line())
 | 
			
		||||
    end)
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it('handles split UTF-8 sequences #16245', function()
 | 
			
		||||
    local screen = Screen.new(50, 7)
 | 
			
		||||
    screen:attach()
 | 
			
		||||
    fn.termopen({ testprg('shell-test'), 'UTF-8' })
 | 
			
		||||
    screen:expect([[
 | 
			
		||||
      ^å                                                 |
 | 
			
		||||
      ref: å̲                                            |
 | 
			
		||||
      1: å̲                                              |
 | 
			
		||||
      2: å̲                                              |
 | 
			
		||||
      3: å̲                                              |
 | 
			
		||||
                                                        |*2
 | 
			
		||||
    ]])
 | 
			
		||||
  end)
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
describe('on_lines does not emit out-of-bounds line indexes when', function()
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user