Patch 8.2.4684
Problem:    Cannot open a channel on a Unix domain socket.
Solution:   Add Unix domain socket support. (closes #10062)
Files:      runtime/doc/channel.txt, src/channel.c, src/testdir/check.vim,
            src/testdir/shared.vim, src/testdir/test_channel.py,
            src/testdir/test_channel.vim, src/testdir/test_channel_unix.py,
            src/testdir/test_cmdline.vim


*** ../vim-8.2.4683/runtime/doc/channel.txt     2022-03-30 10:14:41.485657271 
+0100
--- runtime/doc/channel.txt     2022-04-04 15:39:23.550236560 +0100
***************
*** 119,128 ****
  
  Use |ch_status()| to see if the channel could be opened.
  
! {address} has the form "hostname:port".  E.g., "localhost:8765".
! 
! When using an IPv6 address, enclose it within square brackets.  E.g.,
! "[2001:db8::1]:8765".
  
  {options} is a dictionary with optional entries:      *channel-open-options*
  
--- 119,131 ----
  
  Use |ch_status()| to see if the channel could be opened.
  
!                                       *channel-address*
! {address} can be a domain name or an IP address, followed by a port number, or
! a Unix-domain socket path prefixed by "unix:".  E.g. >
!     www.example.com:80   " domain + port
!     127.0.0.1:1234       " IPv4 + port
!     [2001:db8::1]:8765   " IPv6 + port
!     unix:/tmp/my-socket  " Unix-domain socket path
  
  {options} is a dictionary with optional entries:      *channel-open-options*
  
***************
*** 579,588 ****
--- 582,596 ----
                When opened with ch_open():
                   "hostname"     the hostname of the address
                   "port"         the port of the address
+                  "path"         the path of the Unix-domain socket
                   "sock_status"  "open" or "closed"
                   "sock_mode"    "NL", "RAW", "JSON" or "JS"
                   "sock_io"      "socket"
                   "sock_timeout" timeout in msec
+ 
+               Note that "pair" is only present for Unix-domain sockets, for
+               regular ones "hostname" and "port" are present instead.
+ 
                When opened with job_start():
                   "out_status"   "open", "buffered" or "closed"
                   "out_mode"     "NL", "RAW", "JSON" or "JS"
***************
*** 641,651 ****
                Open a channel to {address}.  See |channel|.
                Returns a Channel.  Use |ch_status()| to check for failure.
  
!               {address} is a String and has the form "hostname:port", e.g.,
!               "localhost:8765".
! 
!               When using an IPv6 address, enclose it within square brackets.
!               E.g., "[2001:db8::1]:8765".
  
                If {options} is given it must be a |Dictionary|.
                See |channel-open-options|.
--- 649,656 ----
                Open a channel to {address}.  See |channel|.
                Returns a Channel.  Use |ch_status()| to check for failure.
  
!               {address} is a String, see |channel-address| for the possible
!               accepted forms.
  
                If {options} is given it must be a |Dictionary|.
                See |channel-open-options|.
*** ../vim-8.2.4683/src/channel.c       2022-04-04 15:16:50.738014123 +0100
--- src/channel.c       2022-04-04 15:44:12.318053555 +0100
***************
*** 44,54 ****
--- 44,61 ----
  # define sock_write(sd, buf, len) send((SOCKET)sd, buf, len, 0)
  # define sock_read(sd, buf, len) recv((SOCKET)sd, buf, len, 0)
  # define sock_close(sd) closesocket((SOCKET)sd)
+ // Support for Unix-domain sockets was added in Windows SDK 17061.
+ # define UNIX_PATH_MAX 108
+ typedef struct sockaddr_un {
+     ADDRESS_FAMILY sun_family;
+     char sun_path[UNIX_PATH_MAX];
+ } SOCKADDR_UN, *PSOCKADDR_UN;
  #else
  # include <netdb.h>
  # include <netinet/in.h>
  # include <arpa/inet.h>
  # include <sys/socket.h>
+ # include <sys/un.h>
  # ifdef HAVE_LIBGEN_H
  #  include <libgen.h>
  # endif
***************
*** 929,934 ****
--- 936,1002 ----
  }
  
  /*
+  * Open a socket channel to the UNIX socket at "path".
+  * Returns the channel for success.
+  * Returns NULL for failure.
+  */
+     static channel_T *
+ channel_open_unix(
+       const char *path,
+       void (*nb_close_cb)(void))
+ {
+     channel_T         *channel = NULL;
+     int                       sd = -1;
+     size_t            path_len = STRLEN(path);
+     struct sockaddr_un        server;
+     size_t            server_len;
+     int                       waittime = -1;
+ 
+     if (*path == NUL || path_len >= sizeof(server.sun_path))
+     {
+       semsg(_(e_invalid_argument_str), path);
+       return NULL;
+     }
+ 
+     channel = add_channel();
+     if (channel == NULL)
+     {
+       ch_error(NULL, "Cannot allocate channel.");
+       return NULL;
+     }
+ 
+     CLEAR_FIELD(server);
+     server.sun_family = AF_UNIX;
+     STRNCPY(server.sun_path, path, sizeof(server.sun_path) - 1);
+ 
+     ch_log(channel, "Trying to connect to %s", path);
+ 
+     server_len = offsetof(struct sockaddr_un, sun_path) + path_len + 1;
+     sd = channel_connect(channel, (struct sockaddr *)&server, (int)server_len,
+                                                                  &waittime);
+ 
+     if (sd < 0)
+     {
+       channel_free(channel);
+       return NULL;
+     }
+ 
+     ch_log(channel, "Connection made");
+ 
+     channel->CH_SOCK_FD = (sock_T)sd;
+     channel->ch_nb_close_cb = nb_close_cb;
+     channel->ch_hostname = (char *)vim_strsave((char_u *)path);
+     channel->ch_port = 0;
+     channel->ch_to_be_closed |= (1U << PART_SOCK);
+ 
+ #ifdef FEAT_GUI
+     channel_gui_register_one(channel, PART_SOCK);
+ #endif
+ 
+     return channel;
+ }
+ 
+ /*
   * Open a socket channel to "hostname":"port".
   * "waittime" is the time in msec to wait for the connection.
   * When negative wait forever.
***************
*** 1301,1308 ****
      char_u    *address;
      char_u    *p;
      char      *rest;
!     int               port;
      int               is_ipv6 = FALSE;
      jobopt_T    opt;
      channel_T *channel = NULL;
  
--- 1369,1377 ----
      char_u    *address;
      char_u    *p;
      char      *rest;
!     int               port = 0;
      int               is_ipv6 = FALSE;
+     int               is_unix = FALSE;
      jobopt_T    opt;
      channel_T *channel = NULL;
  
***************
*** 1319,1326 ****
        return NULL;
      }
  
!     // parse address
!     if (*address == '[')
      {
        // ipv6 address
        is_ipv6 = TRUE;
--- 1388,1405 ----
        return NULL;
      }
  
!     if (*address == NUL)
!     {
!       semsg(_(e_invalid_argument_str), address);
!       return NULL;
!     }
! 
!     if (!STRNCMP(address, "unix:", 5))
!     {
!       is_unix = TRUE;
!       address += 5;
!     }
!     else if (*address == '[')
      {
        // ipv6 address
        is_ipv6 = TRUE;
***************
*** 1333,1338 ****
--- 1412,1418 ----
      }
      else
      {
+       // ipv4 address
        p = vim_strchr(address, ':');
        if (p == NULL)
        {
***************
*** 1340,1366 ****
            return NULL;
        }
      }
!     port = strtol((char *)(p + 1), &rest, 10);
!     if (*address == NUL || port <= 0 || port >= 65536 || *rest != NUL)
!     {
!       semsg(_(e_invalid_argument_str), address);
!       return NULL;
!     }
!     if (is_ipv6)
      {
!       // strip '[' and ']'
!       ++address;
!       *(p - 1) = NUL;
      }
-     else
-       *p = NUL;
  
      // parse options
      clear_job_options(&opt);
      opt.jo_mode = MODE_JSON;
      opt.jo_timeout = 2000;
      if (get_job_options(&argvars[1], &opt,
!           JO_MODE_ALL + JO_CB_ALL + JO_WAITTIME + JO_TIMEOUT_ALL, 0) == FAIL)
        goto theend;
      if (opt.jo_timeout < 0)
      {
--- 1420,1451 ----
            return NULL;
        }
      }
! 
!     if (!is_unix)
      {
!       port = strtol((char *)(p + 1), &rest, 10);
!       if (port <= 0 || port >= 65536 || *rest != NUL)
!       {
!           semsg(_(e_invalid_argument_str), address);
!           return NULL;
!       }
!       if (is_ipv6)
!       {
!           // strip '[' and ']'
!           ++address;
!           *(p - 1) = NUL;
!       }
!       else
!           *p = NUL;
      }
  
      // parse options
      clear_job_options(&opt);
      opt.jo_mode = MODE_JSON;
      opt.jo_timeout = 2000;
      if (get_job_options(&argvars[1], &opt,
!           JO_MODE_ALL + JO_CB_ALL + JO_TIMEOUT_ALL
!               + (is_unix? 0 : JO_WAITTIME), 0) == FAIL)
        goto theend;
      if (opt.jo_timeout < 0)
      {
***************
*** 1368,1374 ****
        goto theend;
      }
  
!     channel = channel_open((char *)address, port, opt.jo_waittime, NULL);
      if (channel != NULL)
      {
        opt.jo_set = JO_ALL;
--- 1453,1462 ----
        goto theend;
      }
  
!     if (is_unix)
!       channel = channel_open_unix((char *)address, NULL);
!     else
!       channel = channel_open((char *)address, port, opt.jo_waittime, NULL);
      if (channel != NULL)
      {
        opt.jo_set = JO_ALL;
***************
*** 3268,3275 ****
  
      if (channel->ch_hostname != NULL)
      {
!       dict_add_string(dict, "hostname", (char_u *)channel->ch_hostname);
!       dict_add_number(dict, "port", channel->ch_port);
        channel_part_info(channel, dict, "sock", PART_SOCK);
      }
      else
--- 3356,3369 ----
  
      if (channel->ch_hostname != NULL)
      {
!       if (channel->ch_port)
!       {
!           dict_add_string(dict, "hostname", (char_u *)channel->ch_hostname);
!           dict_add_number(dict, "port", channel->ch_port);
!       }
!       else
!           // Unix-domain socket.
!           dict_add_string(dict, "path", (char_u *)channel->ch_hostname);
        channel_part_info(channel, dict, "sock", PART_SOCK);
      }
      else
*** ../vim-8.2.4683/src/testdir/check.vim       2021-10-16 21:58:23.206049605 
+0100
--- src/testdir/check.vim       2022-04-04 15:39:23.550236560 +0100
***************
*** 95,101 ****
    endif
  endfunc
  
! " Command to check for running on Linix
  command CheckLinux call CheckLinux()
  func CheckLinux()
    if !has('linux')
--- 95,101 ----
    endif
  endfunc
  
! " Command to check for running on Linux
  command CheckLinux call CheckLinux()
  func CheckLinux()
    if !has('linux')
*** ../vim-8.2.4683/src/testdir/shared.vim      2021-05-02 18:14:55.466643569 
+0100
--- src/testdir/shared.vim      2022-04-04 15:39:23.550236560 +0100
***************
*** 15,24 ****
    if has('unix')
      " We also need the job feature or the pkill command to make sure the 
server
      " can be stopped.
!     if !(executable('python') && (has('job') || executable('pkill')))
        return ''
      endif
!     let s:python = 'python'
    elseif has('win32')
      " Use Python Launcher for Windows (py.exe) if available.
      " NOTE: if you get a "Python was not found" error, disable the Python
--- 15,30 ----
    if has('unix')
      " We also need the job feature or the pkill command to make sure the 
server
      " can be stopped.
!     if !(has('job') || executable('pkill'))
        return ''
      endif
!     if executable('python')
!       let s:python = 'python'
!     elseif executable('python3')
!       let s:python = 'python3'
!     else
!       return ''
!     end
    elseif has('win32')
      " Use Python Launcher for Windows (py.exe) if available.
      " NOTE: if you get a "Python was not found" error, disable the Python
*** ../vim-8.2.4683/src/testdir/test_channel.py 2021-07-30 20:56:07.110143138 
+0100
--- src/testdir/test_channel.py 2022-04-04 15:39:23.550236560 +0100
***************
*** 22,28 ****
  class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
  
      def setup(self):
!         self.request.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
  
      def handle(self):
          print("=== socket opened ===")
--- 22,29 ----
  class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
  
      def setup(self):
!         if self.server.address_family != socket.AF_UNIX:
!             self.request.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
  
      def handle(self):
          print("=== socket opened ===")
*** ../vim-8.2.4683/src/testdir/test_channel.vim        2022-03-30 
10:14:41.489657276 +0100
--- src/testdir/test_channel.vim        2022-04-04 15:39:23.550236560 +0100
***************
*** 23,28 ****
--- 23,31 ----
    if g:testfunc =~ '_ipv6()$' 
      let s:localhost = '[::1]:'
      let s:testscript = 'test_channel_6.py'
+   elseif g:testfunc =~ '_unix()$'
+     let s:localhost = 'unix:Xtestsocket'
+     let s:testscript = 'test_channel_unix.py'
    else
      let s:localhost = 'localhost:'
      let s:testscript = 'test_channel.py'
***************
*** 39,44 ****
--- 42,56 ----
    call RunServer(s:testscript, a:testfunc, a:000)
  endfunc
  
+ " Returns the address of the test server.
+ func s:address(port)
+   if s:localhost =~ '^unix:'
+     return s:localhost
+   else
+     return s:localhost . a:port
+   end
+ endfunc
+ 
  " Return a list of open files.
  " Can be used to make sure no resources leaked.
  " Returns an empty list on systems where this is not supported.
***************
*** 65,71 ****
    let s:chopt.drop = 'never'
    " Also add the noblock flag to try it out.
    let s:chopt.noblock = 1
!   let handle = ch_open(s:localhost . a:port, s:chopt)
    if ch_status(handle) == "fail"
      call assert_report("Can't open channel")
      return
--- 77,83 ----
    let s:chopt.drop = 'never'
    " Also add the noblock flag to try it out.
    let s:chopt.noblock = 1
!   let handle = ch_open(s:address(a:port), s:chopt)
    if ch_status(handle) == "fail"
      call assert_report("Can't open channel")
      return
***************
*** 77,83 ****
    let dict = handle->ch_info()
    call assert_true(dict.id != 0)
    call assert_equal('open', dict.status)
!   call assert_equal(a:port, string(dict.port))
    call assert_equal('open', dict.sock_status)
    call assert_equal('socket', dict.sock_io)
  
--- 89,98 ----
    let dict = handle->ch_info()
    call assert_true(dict.id != 0)
    call assert_equal('open', dict.status)
!   if has_key(dict, 'port')
!     " Channels using Unix sockets have no 'port' entry.
!     call assert_equal(a:port, string(dict.port))
!   end
    call assert_equal('open', dict.sock_status)
    call assert_equal('socket', dict.sock_io)
  
***************
*** 252,264 ****
  
  func Test_communicate_ipv6()
    CheckIPv6
  
    call Test_communicate()
  endfunc
  
  " Test that we can open two channels.
  func Ch_two_channels(port)
!   let handle = ch_open(s:localhost . a:port, s:chopt)
    call assert_equal(v:t_channel, type(handle))
    if handle->ch_status() == "fail"
      call assert_report("Can't open channel")
--- 267,285 ----
  
  func Test_communicate_ipv6()
    CheckIPv6
+   call Test_communicate()
+ endfunc
  
+ func Test_communicate_unix()
+   CheckUnix
    call Test_communicate()
+   call delete('Xtestsocket')
  endfunc
  
+ 
  " Test that we can open two channels.
  func Ch_two_channels(port)
!   let handle = ch_open(s:address(a:port), s:chopt)
    call assert_equal(v:t_channel, type(handle))
    if handle->ch_status() == "fail"
      call assert_report("Can't open channel")
***************
*** 267,273 ****
  
    call assert_equal('got it', ch_evalexpr(handle, 'hello!'))
  
!   let newhandle = ch_open(s:localhost . a:port, s:chopt)
    if ch_status(newhandle) == "fail"
      call assert_report("Can't open second channel")
      return
--- 288,294 ----
  
    call assert_equal('got it', ch_evalexpr(handle, 'hello!'))
  
!   let newhandle = ch_open(s:address(a:port), s:chopt)
    if ch_status(newhandle) == "fail"
      call assert_report("Can't open second channel")
      return
***************
*** 292,300 ****
    call Test_two_channels()
  endfunc
  
  " Test that a server crash is handled gracefully.
  func Ch_server_crash(port)
!   let handle = ch_open(s:localhost . a:port, s:chopt)
    if ch_status(handle) == "fail"
      call assert_report("Can't open channel")
      return
--- 313,327 ----
    call Test_two_channels()
  endfunc
  
+ func Test_two_channels_unix()
+   CheckUnix
+   call Test_two_channels()
+   call delete('Xtestsocket')
+ endfunc
+ 
  " Test that a server crash is handled gracefully.
  func Ch_server_crash(port)
!   let handle = ch_open(s:address(a:port), s:chopt)
    if ch_status(handle) == "fail"
      call assert_report("Can't open channel")
      return
***************
*** 314,319 ****
--- 341,352 ----
    call Test_server_crash()
  endfunc
  
+ func Test_server_crash_unix()
+   CheckUnix
+   call Test_server_crash()
+   call delete('Xtestsocket')
+ endfunc
+ 
  """""""""
  
  func Ch_handler(chan, msg)
***************
*** 323,329 ****
  endfunc
  
  func Ch_channel_handler(port)
!   let handle = ch_open(s:localhost . a:port, s:chopt)
    if ch_status(handle) == "fail"
      call assert_report("Can't open channel")
      return
--- 356,362 ----
  endfunc
  
  func Ch_channel_handler(port)
!   let handle = ch_open(s:address(a:port), s:chopt)
    if ch_status(handle) == "fail"
      call assert_report("Can't open channel")
      return
***************
*** 352,357 ****
--- 385,396 ----
    call Test_channel_handler()
  endfunc
  
+ func Test_channel_handler_unix()
+   CheckUnix
+   call Test_channel_handler()
+   call delete('Xtestsocket')
+ endfunc
+ 
  """""""""
  
  let g:Ch_reply = ''
***************
*** 367,373 ****
  endfunc
  
  func Ch_channel_zero(port)
!   let handle = (s:localhost .. a:port)->ch_open(s:chopt)
    if ch_status(handle) == "fail"
      call assert_report("Can't open channel")
      return
--- 406,412 ----
  endfunc
  
  func Ch_channel_zero(port)
!   let handle = (s:address(a:port))->ch_open(s:chopt)
    if ch_status(handle) == "fail"
      call assert_report("Can't open channel")
      return
***************
*** 415,420 ****
--- 454,466 ----
    call Test_zero_reply()
  endfunc
  
+ func Test_zero_reply_unix()
+   CheckUnix
+   call Test_zero_reply()
+   call delete('Xtestsocket')
+ endfunc
+ 
+ 
  """""""""
  
  let g:Ch_reply1 = ""
***************
*** 436,442 ****
  endfunc
  
  func Ch_raw_one_time_callback(port)
!   let handle = ch_open(s:localhost . a:port, s:chopt)
    if ch_status(handle) == "fail"
      call assert_report("Can't open channel")
      return
--- 482,488 ----
  endfunc
  
  func Ch_raw_one_time_callback(port)
!   let handle = ch_open(s:address(a:port), s:chopt)
    if ch_status(handle) == "fail"
      call assert_report("Can't open channel")
      return
***************
*** 462,467 ****
--- 508,519 ----
    call Test_raw_one_time_callback()
  endfunc
  
+ func Test_raw_one_time_callback_unix()
+   CheckUnix
+   call Test_raw_one_time_callback()
+   call delete('Xtestsocket')
+ endfunc
+ 
  """""""""
  
  " Test that trying to connect to a non-existing port fails quickly.
***************
*** 1398,1404 ****
  
  " Test that "unlet handle" in a handler doesn't crash Vim.
  func Ch_unlet_handle(port)
!   let s:channelfd = ch_open(s:localhost . a:port, s:chopt)
    eval s:channelfd->ch_sendexpr("test", {'callback': 
function('s:UnletHandler')})
    call WaitForAssert({-> assert_equal('what?', g:Ch_unletResponse)})
  endfunc
--- 1450,1456 ----
  
  " Test that "unlet handle" in a handler doesn't crash Vim.
  func Ch_unlet_handle(port)
!   let s:channelfd = ch_open(s:address(a:port), s:chopt)
    eval s:channelfd->ch_sendexpr("test", {'callback': 
function('s:UnletHandler')})
    call WaitForAssert({-> assert_equal('what?', g:Ch_unletResponse)})
  endfunc
***************
*** 1422,1428 ****
  
  " Test that "unlet handle" in a handler doesn't crash Vim.
  func Ch_close_handle(port)
!   let s:channelfd = ch_open(s:localhost . a:port, s:chopt)
    call ch_sendexpr(s:channelfd, "test", {'callback': 
function('Ch_CloseHandler')})
    call WaitForAssert({-> assert_equal('what?', g:Ch_unletResponse)})
  endfunc
--- 1474,1480 ----
  
  " Test that "unlet handle" in a handler doesn't crash Vim.
  func Ch_close_handle(port)
!   let s:channelfd = ch_open(s:address(a:port), s:chopt)
    call ch_sendexpr(s:channelfd, "test", {'callback': 
function('Ch_CloseHandler')})
    call WaitForAssert({-> assert_equal('what?', g:Ch_unletResponse)})
  endfunc
***************
*** 1439,1445 ****
  """"""""""
  
  func Ch_open_ipv6(port)
!   let handle = ch_open('[::1]:' .. a:port, s:chopt)
    call assert_notequal('fail', ch_status(handle))
  endfunc
  
--- 1491,1497 ----
  """"""""""
  
  func Ch_open_ipv6(port)
!   let handle = ch_open(s:address(a:port), s:chopt)
    call assert_notequal('fail', ch_status(handle))
  endfunc
  
***************
*** 1479,1485 ****
  func Ch_open_delay(port)
    " Wait up to a second for the port to open.
    let s:chopt.waittime = 1000
!   let channel = ch_open(s:localhost . a:port, s:chopt)
    if ch_status(channel) == "fail"
      call assert_report("Can't open channel")
      return
--- 1531,1537 ----
  func Ch_open_delay(port)
    " Wait up to a second for the port to open.
    let s:chopt.waittime = 1000
!   let channel = ch_open(s:address(a:port), s:chopt)
    if ch_status(channel) == "fail"
      call assert_report("Can't open channel")
      return
***************
*** 1505,1511 ****
  endfunc
  
  function Ch_test_call(port)
!   let handle = ch_open(s:localhost . a:port, s:chopt)
    if ch_status(handle) == "fail"
      call assert_report("Can't open channel")
      return
--- 1557,1563 ----
  endfunc
  
  function Ch_test_call(port)
!   let handle = ch_open(s:address(a:port), s:chopt)
    if ch_status(handle) == "fail"
      call assert_report("Can't open channel")
      return
***************
*** 1529,1534 ****
--- 1581,1592 ----
    call Test_call()
  endfunc
  
+ func Test_call_unix()
+   CheckUnix
+   call Test_call()
+   call delete('Xtestsocket')
+ endfunc
+ 
  """""""""
  
  let g:Ch_job_exit_ret = 'not yet'
***************
*** 1605,1611 ****
  endfunc
  
  function Ch_test_close_callback(port)
!   let handle = ch_open(s:localhost . a:port, s:chopt)
    if ch_status(handle) == "fail"
      call assert_report("Can't open channel")
      return
--- 1663,1669 ----
  endfunc
  
  function Ch_test_close_callback(port)
!   let handle = ch_open(s:address(a:port), s:chopt)
    if ch_status(handle) == "fail"
      call assert_report("Can't open channel")
      return
***************
*** 1625,1632 ****
    call Test_close_callback()
  endfunc
  
  function Ch_test_close_partial(port)
!   let handle = ch_open(s:localhost . a:port, s:chopt)
    if ch_status(handle) == "fail"
      call assert_report("Can't open channel")
      return
--- 1683,1696 ----
    call Test_close_callback()
  endfunc
  
+ func Test_close_callback_unix()
+   CheckUnix
+   call Test_close_callback()
+   call delete('Xtestsocket')
+ endfunc
+ 
  function Ch_test_close_partial(port)
!   let handle = ch_open(s:address(a:port), s:chopt)
    if ch_status(handle) == "fail"
      call assert_report("Can't open channel")
      return
***************
*** 1651,1656 ****
--- 1715,1726 ----
    call Test_close_partial()
  endfunc
  
+ func Test_close_partial_unix()
+   CheckUnix
+   call Test_close_partial()
+   call delete('Xtestsocket')
+ endfunc
+ 
  func Test_job_start_fails()
    " this was leaking memory
    call assert_fails("call job_start([''])", "E474:")
***************
*** 1920,1926 ****
  endfunc
  
  function Ch_test_close_lambda(port)
!   let handle = ch_open(s:localhost . a:port, s:chopt)
    if ch_status(handle) == "fail"
      call assert_report("Can't open channel")
      return
--- 1990,1996 ----
  endfunc
  
  function Ch_test_close_lambda(port)
!   let handle = ch_open(s:address(a:port), s:chopt)
    if ch_status(handle) == "fail"
      call assert_report("Can't open channel")
      return
***************
*** 1942,1947 ****
--- 2012,2023 ----
    call Test_close_lambda()
  endfunc
  
+ func Test_close_lambda_unix()
+   CheckUnix
+   call Test_close_lambda()
+   call delete('Xtestsocket')
+ endfunc
+ 
  func s:test_list_args(cmd, out, remove_lf)
    try
      let g:out = ''
***************
*** 2243,2248 ****
--- 2319,2326 ----
    let job = job_start("cat ", #{in_io: 'null'})
    call WaitForAssert({-> assert_equal("dead", job_status(job))})
    call assert_equal(0, job_info(job).exitval)
+ 
+   call delete('Xtestsocket')
  endfunc
  
  func Test_ch_getbufnr()
*** ../vim-8.2.4683/src/testdir/test_channel_unix.py    2022-04-04 
15:45:57.774034889 +0100
--- src/testdir/test_channel_unix.py    2022-04-04 15:39:23.550236560 +0100
***************
*** 0 ****
--- 1,50 ----
+ #!/usr/bin/env python
+ #
+ # Server that will accept connections from a Vim channel.
+ # Used by test_channel.vim.
+ #
+ # This requires Python 2.6 or later.
+ 
+ from __future__ import print_function
+ from test_channel import ThreadedTCPServer, ThreadedTCPRequestHandler, \
+     writePortInFile
+ import socket
+ import threading
+ import os
+ 
+ try:
+     FileNotFoundError
+ except NameError:
+     # Python 2
+     FileNotFoundError = (IOError, OSError)
+ 
+ class ThreadedUnixServer(ThreadedTCPServer):
+     address_family = socket.AF_UNIX
+ 
+ def main(path):
+     server = ThreadedUnixServer(path, ThreadedTCPRequestHandler)
+ 
+     # Start a thread with the server.  That thread will then start a new 
thread
+     # for each connection.
+     server_thread = threading.Thread(target=server.serve_forever)
+     server_thread.start()
+ 
+     # Signal the test harness we're ready, the port value has no meaning.
+     writePortInFile(1234)
+ 
+     print("Listening on {0}".format(server.server_address))
+ 
+     # Main thread terminates, but the server continues running
+     # until server.shutdown() is called.
+     try:
+         while server_thread.is_alive():
+             server_thread.join(1)
+     except (KeyboardInterrupt, SystemExit):
+         server.shutdown()
+ 
+ if __name__ == "__main__":
+     try:
+         os.remove("Xtestsocket")
+     except FileNotFoundError:
+         pass
+     main("Xtestsocket")
*** ../vim-8.2.4683/src/testdir/test_cmdline.vim        2022-03-31 
12:33:56.485701120 +0100
--- src/testdir/test_cmdline.vim        2022-04-04 15:39:23.550236560 +0100
***************
*** 620,627 ****
          \ ':5s':        'substitute',
          \ "'<,'>s":     'substitute',
          \ ":'<,'>s":    'substitute',
!         \ 'CheckUni':   'CheckUnix',
!         \ 'CheckUnix':  'CheckUnix',
    \ }
  
    for [in, want] in items(tests)
--- 620,627 ----
          \ ':5s':        'substitute',
          \ "'<,'>s":     'substitute',
          \ ":'<,'>s":    'substitute',
!         \ 'CheckLin':   'CheckLinux',
!         \ 'CheckLinux': 'CheckLinux',
    \ }
  
    for [in, want] in items(tests)
*** ../vim-8.2.4683/src/version.c       2022-04-04 15:16:50.746014138 +0100
--- src/version.c       2022-04-04 15:40:33.482194513 +0100
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     4684,
  /**/

-- 
You can be stopped by the police for biking over 65 miles per hour.
You are not allowed to walk across a street on your hands.
                [real standing laws in Connecticut, United States of America]

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20220404155956.63F871C039E%40moolenaar.net.

Raspunde prin e-mail lui