ronantakizawa/codereview-bench huggingface dataset:
Repository: neovim/neovim
File: runtime/lua/vim/lsp/semantic_tokens.lua (Lua)

Code before:
      local highlighter = STHighlighter.active[buf]
      if not highlighter then
        return true
      end
      if M.is_enabled({ bufnr = buf }) then
        highlighter:on_change()
      end
    end,
    on_reload = function(_, buf)
      local highlighter = STHighlighter.active[buf]
      if highlighter and M.is_enabled({ bufnr = bufnr }) then
        highlighter:reset()
        highlighter:send_request()
      end
    end,
  })

  api.nvim_create_autocmd({ 'BufWinEnter', 'InsertLeave' }, {
    buffer = self.bufnr,
    group = self.augroup,
    callback = function()
      if M.is_enabled({ bufnr = bufnr }) then
        self:send_request()
      end
    end,
  })

  return self
end

---@package
function STHighlighter:on_attach(client_id)
  local state = self.client_state[client_id]
  if not state then
    state = {
      namespace = api.nvim_create_namespace('nvim.lsp.semantic_tokens:' .. client_id),
      active_request = {},
      current_result = {},
    }
    self.client_state[client_id] = state
  end
end

---@package
function STHighlighter:on_detach(client_id)
  local state = self.client_state[client_id]
  if state then
    --TODO: delete namespace if/when that becomes possible
    api.nvim_buf_clear_namespace(self.bufnr, state.namespace, 0, -1)
    self.client_state[client_id] = nil
  end

Review comment (suggestion):
Here's another one. Seems like maybe it'd be find to just call send_request() and let that function handle checking the enabled flag.

Code after:
  api.nvim_buf_attach(bufnr, false, {
    on_lines = function(_, buf)
      local highlighter = STHighlighter.active[buf]
      if not highlighter then
        return true
      end
      if M.is_enabled({ bufnr = buf }) then
        highlighter:on_change()
      end
    end,
    on_reload = function(_, buf)
      local highlighter = STHighlighter.active[buf]
      if highlighter and M.is_enabled({ bufnr = bufnr }) then
        highlighter:reset()
        highlighter:send_request()
      end
    end,
  })

  api.nvim_create_autocmd({ 'BufWinEnter', 'InsertLeave' }, {
    buffer = self.bufnr,
    group = self.augroup,
    callback = function()
      if M.is_enabled({ bufnr = bufnr }) then
        self:send_request()
      end
    end,
  })

  return self
end

---@package
function STHighlighter:on_attach(client_id)
  local state = self.client_state[client_id]
  if not state then
    state = {
      namespace = api.nvim_create_namespace('nvim.lsp.semantic_tokens:' .. client_id),
      active_request = {},
      current_result = {},
    }
    self.client_state[client_id] = state
  end
end

---@package
function STHighlighter:on_detach(client_id)
  local state = self.client_state[client_id]
  if state then
    --TODO: delete namespace if/when that becomes possible
    api.nvim_buf_clear_namespace(self.bufnr, state.namespace, 0, -1)
Repository: neovim/neovim
File: src/nvim/eval/funcs.c (C)

Code before:
  const int lnum = (n > 0 ? match_pos.lnum : 0);
  const int col = (n > 0 ? match_pos.col : 0);

  tv_list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
  tv_list_append_number(rettv->vval.v_list, (varnumber_T)col);
  if (flags & SP_SUBPAT) {
    tv_list_append_number(rettv->vval.v_list, (varnumber_T)n);
  }
}

/// "serverlist()" function
static void f_serverlist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
  size_t n;
  char **addrs = server_address_list(&n);
  dict_T *addrs_dict = tv_dict_alloc();

  // Copy addrs into a linked list.
  list_T *const l = tv_list_alloc_ret(rettv, (ptrdiff_t)n);
  for (size_t i = 0; i < n; i++) {
    tv_list_append_allocated_string(l, addrs[i]);
    tv_dict_add_bool(addrs_dict, addrs[i], strlen(addrs[i]), true);
  }

  Error err = ERROR_INIT;
  Object rv = NLUA_EXEC_STATIC("return vim.fs.serverlist(...)", (Array)ARRAY_DICT_INIT, kRetObject,
                               NULL, &err);

  if (ERROR_SET(&err)) {
    ELOG("Error in function 'serverlist': %s", err.msg);
    return;
  }

  for (size_t i = 0; i < rv.data.array.size; i++) {
    char *curr_server = rv.data.array.items[i].data.string.data;
    // Ensure that servers aren't listed twice
    if (tv_dict_find(addrs_dict, curr_server, -1) == NULL) {
      tv_list_append_allocated_string(l, curr_server);
    }
  }

  xfree(addrs);
  tv_dict_free(addrs_dict);
}

/// "serverstart()" function
static void f_serverstart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
  rettv->v_type = VAR_STRING;
  rettv->vval.v_string = NULL;  // Address of the new server


Review comment (suggestion):
put the logic in `runtime/lua/vim/_core/server.lua` and then use `require('vim._core.sever...')` here. 

Code after:
  if (check_secure()) {
    return;
  }

  if (argvars[0].v_type != VAR_STRING) {
    emsg(_(e_invarg));
    return;
  }

  rettv->v_type = VAR_NUMBER;
  rettv->vval.v_number = 0;
  if (argvars[0].vval.v_string) {
    bool rv = server_stop(argvars[0].vval.v_string);
    rettv->vval.v_number = (rv ? 1 : 0);
  }
}

/// Set the cursor or mark position.
/// If "charpos" is true, then use the column number as a character offset.
/// Otherwise use the column number as a byte offset.
static void set_position(typval_T *argvars, typval_T *rettv, bool charpos)
{
  colnr_T curswant = -1;

  rettv->vval.v_number = -1;
  const char *const name = tv_get_string_chk(argvars);
  if (name == NULL) {
    return;
  }

  pos_T pos;
  int fnum;
  if (list2fpos(&argvars[1], &pos, &fnum, &curswant, charpos) != OK) {
    return;
  }

  if (pos.col != MAXCOL && --pos.col < 0) {
    pos.col = 0;
  }
  if (name[0] == '.' && name[1] == NUL) {
    // set cursor; "fnum" is ignored
    curwin->w_cursor = pos;
    if (curswant >= 0) {
      curwin->w_curswant = curswant - 1;
      curwin->w_set_curswant = false;
    }
    check_cursor(curwin);
    rettv->vval.v_number = 0;
  } else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL) {
    // set mark
    if (setmark_pos((uint8_t)name[1], &pos, fnum, NULL) == OK) {
Repository: neovim/neovim
File: runtime/lua/vim/_core/server.lua (Lua)

Code before:
local M = {}

--- Helper function for serverlist(), this returns all the currently running servers
--- in stdpath("run"). Does not include named pipes or TCP servers.
---
--- @return string[] A list of currently running servers in stdpath("run")
function M.serverlist()
  local socket_paths = vim.fs.find(function(name, _)
    return name:match('nvim.*')
  end, { path = vim.fn.stdpath('run'), type = 'socket', limit = math.huge })

  local running_sockets = {}
  for _, socket in ipairs(socket_paths) do
    local ok, chan = pcall(vim.fn.sockconnect, 'pipe', socket, { rpc = true })
    if ok and chan then
      if vim.fn.rpcrequest(chan, 'nvim_get_chan_info', 0).id then
        table.insert(running_sockets, socket)
      end
      vim.fn.chanclose(chan)
    end
  end

  return running_sockets
end

return M


Review comment (suggestion):
not a blocker for your work, but let's mention a TODO here.
```suggestion
  -- TODO: also get named pipes on Windows
  local socket_paths = vim.fs.find(function(name, _)
```

Code after:
local M = {}

--- Called by builtin serverlist(). Returns all running servers.
--- in stdpath("run"). Does not include named pipes or TCP servers.
---
--- @param listed string[] Already listed servers
--- @return string[] A list of currently running servers in stdpath("run")
function M.serverlist(listed)
  -- TODO: also get named pipes on Windows
  local socket_paths = vim.fs.find(function(name, _)
    return name:match('nvim.*')
  end, { path = vim.fn.stdpath('run'), type = 'socket', limit = math.huge })

  local running_sockets = {}
  for _, socket in ipairs(socket_paths) do
    -- Don't list servers twice
    if not vim.list_contains(listed, socket) then
      local ok, chan = pcall(vim.fn.sockconnect, 'pipe', socket, { rpc = true })
      if ok and chan then
        -- Check that the server is responding
        -- TODO: do we need a timeout or error handling here?
        if vim.fn.rpcrequest(chan, 'nvim_get_chan_info', 0).id then
          table.insert(running_sockets, socket)
        end
        vim.fn.chanclose(chan)
      end
    end
  end

  return running_sockets
end

return M
Repository: neovim/neovim
File: runtime/lua/vim/_core/server.lua (Lua)

Code before:
local M = {}

--- Helper function for serverlist(), this returns all the currently running servers
--- in stdpath("run"). Does not include named pipes or TCP servers.
---
--- @return string[] A list of currently running servers in stdpath("run")
function M.serverlist()
  -- TODO: also get named pipes on Windows
  local socket_paths = vim.fs.find(function(name, _)
    return name:match('nvim.*')
  end, { path = vim.fn.stdpath('run'), type = 'socket', limit = math.huge })

  local running_sockets = {}
  for _, socket in ipairs(socket_paths) do
    local ok, chan = pcall(vim.fn.sockconnect, 'pipe', socket, { rpc = true })
    if ok and chan then
      if vim.fn.rpcrequest(chan, 'nvim_get_chan_info', 0).id then
        table.insert(running_sockets, socket)
      end
      vim.fn.chanclose(chan)
    end
  end

  return running_sockets
end

return M


Review comment (refactor):
"helper function" is just noise
```suggestion
--- Called by builtin serverlist(). Returns all running servers
```

Code after:
local M = {}

--- Called by builtin serverlist(). Returns all running servers.
--- in stdpath("run"). Does not include named pipes or TCP servers.
---
--- @param listed string[] Already listed servers
--- @return string[] A list of currently running servers in stdpath("run")
function M.serverlist(listed)
  -- TODO: also get named pipes on Windows
  local socket_paths = vim.fs.find(function(name, _)
    return name:match('nvim.*')
  end, { path = vim.fn.stdpath('run'), type = 'socket', limit = math.huge })

  local running_sockets = {}
  for _, socket in ipairs(socket_paths) do
    -- Don't list servers twice
    if not vim.list_contains(listed, socket) then
      local ok, chan = pcall(vim.fn.sockconnect, 'pipe', socket, { rpc = true })
      if ok and chan then
        -- Check that the server is responding
        -- TODO: do we need a timeout or error handling here?
        if vim.fn.rpcrequest(chan, 'nvim_get_chan_info', 0).id then
          table.insert(running_sockets, socket)
        end
        vim.fn.chanclose(chan)
      end
    end
  end
Repository: neovim/neovim
File: src/nvim/eval/funcs.c (C)

Code before:
  size_t n;
  char **addrs = server_address_list(&n);
  dict_T *addrs_dict = tv_dict_alloc();

  // Copy addrs into a linked list.
  list_T *const l = tv_list_alloc_ret(rettv, (ptrdiff_t)n);
  for (size_t i = 0; i < n; i++) {
    tv_list_append_allocated_string(l, addrs[i]);
    tv_dict_add_bool(addrs_dict, addrs[i], strlen(addrs[i]), true);
  }

  if (argvars[0].v_type != VAR_DICT) {
    return;
  }

  if (!tv_dict_get_bool(argvars[0].vval.v_dict, "peer", false)) {
    return;
  }

  Error err = ERROR_INIT;
  Object rv = NLUA_EXEC_STATIC("return require('vim._core.server').serverlist(...)",
                               (Array)ARRAY_DICT_INIT, kRetObject,
                               NULL, &err);

  if (ERROR_SET(&err)) {
    ELOG("Error in function 'serverlist': %s", err.msg);
    return;
  }

  for (size_t i = 0; i < rv.data.array.size; i++) {
    char *curr_server = rv.data.array.items[i].data.string.data;
    // Ensure that servers aren't listed twice
    if (tv_dict_find(addrs_dict, curr_server, -1) == NULL) {
      tv_list_append_allocated_string(l, curr_server);
    }
  }

  xfree(addrs);
  tv_dict_free(addrs_dict);
}

/// "serverstart()" function
static void f_serverstart(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
  rettv->v_type = VAR_STRING;
  rettv->vval.v_string = NULL;  // Address of the new server

  if (check_secure()) {
    return;
  }


Review comment (bug):
do not write "error in" in errors, it's redundant.
```suggestion
    ELOG("vim._core.serverlist failed: %s", err.msg);
```

Code after:
    rettv->vval.v_number = (rv ? 1 : 0);
  }
}

/// Set the cursor or mark position.
/// If "charpos" is true, then use the column number as a character offset.
/// Otherwise use the column number as a byte offset.
static void set_position(typval_T *argvars, typval_T *rettv, bool charpos)
{
  colnr_T curswant = -1;

  rettv->vval.v_number = -1;
  const char *const name = tv_get_string_chk(argvars);
  if (name == NULL) {
    return;
  }

  pos_T pos;
  int fnum;
  if (list2fpos(&argvars[1], &pos, &fnum, &curswant, charpos) != OK) {
    return;
  }

  if (pos.col != MAXCOL && --pos.col < 0) {
    pos.col = 0;
  }
  if (name[0] == '.' && name[1] == NUL) {
    // set cursor; "fnum" is ignored
    curwin->w_cursor = pos;
    if (curswant >= 0) {
      curwin->w_curswant = curswant - 1;
      curwin->w_set_curswant = false;
    }
    check_cursor(curwin);
    rettv->vval.v_number = 0;
  } else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL) {
    // set mark
    if (setmark_pos((uint8_t)name[1], &pos, fnum, NULL) == OK) {
      rettv->vval.v_number = 0;
    }
  } else {
    emsg(_(e_invarg));
  }
}

/// "setcharpos()" function
static void f_setcharpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
  set_position(argvars, rettv, true);
}
Repository: neovim/neovim
File: src/nvim/eval/funcs.c (C)

Code before:
/// "searchpos()" function
static void f_searchpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
  pos_T match_pos;
  int flags = 0;

  const int n = search_cmn(argvars, &match_pos, &flags);

  tv_list_alloc_ret(rettv, 2 + (!!(flags & SP_SUBPAT)));

  const int lnum = (n > 0 ? match_pos.lnum : 0);
  const int col = (n > 0 ? match_pos.col : 0);

  tv_list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
  tv_list_append_number(rettv->vval.v_list, (varnumber_T)col);
  if (flags & SP_SUBPAT) {
    tv_list_append_number(rettv->vval.v_list, (varnumber_T)n);
  }
}

/// "serverlist()" function
static void f_serverlist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
  size_t n;
  char **addrs = server_address_list(&n);
  dict_T *addrs_dict = tv_dict_alloc();

  // Copy addrs into a linked list.
  list_T *const l = tv_list_alloc_ret(rettv, (ptrdiff_t)n);
  for (size_t i = 0; i < n; i++) {
    tv_list_append_allocated_string(l, addrs[i]);
    tv_dict_add_bool(addrs_dict, addrs[i], strlen(addrs[i]), true);
  }

  if (argvars[0].v_type != VAR_DICT) {
    return;
  }

  if (!tv_dict_get_bool(argvars[0].vval.v_dict, "peer", false)) {
    return;
  }

  Error err = ERROR_INIT;
  Object rv = NLUA_EXEC_STATIC("return require('vim._core.server').serverlist(...)",
                               (Array)ARRAY_DICT_INIT, kRetObject,
                               NULL, &err);

  if (ERROR_SET(&err)) {
    ELOG("Error in function 'serverlist': %s", err.msg);
    return;
  }

Review comment (refactor):
is this only for checking duplicates? that's a good idea, but it's not obvious and having to study the code to find that out is unpleasant.

however, instead of doing it like this, could we pass the `addrs` and do the deduplication in Lua instead?

the entire point of the Lua script is that is where logic can "grow". we don't want to grow C code if we don't have to.

Code after:
  n--;
  for (size_t i = 0; i < n; i++) {
    xfree(addrs[i]);
  }
  xfree(addrs);
}

/// "serverstop()" function
static void f_serverstop(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
  if (check_secure()) {
    return;
  }

  if (argvars[0].v_type != VAR_STRING) {
    emsg(_(e_invarg));
    return;
  }

  rettv->v_type = VAR_NUMBER;
  rettv->vval.v_number = 0;
  if (argvars[0].vval.v_string) {
    bool rv = server_stop(argvars[0].vval.v_string);
    rettv->vval.v_number = (rv ? 1 : 0);
  }
}

/// Set the cursor or mark position.
/// If "charpos" is true, then use the column number as a character offset.
/// Otherwise use the column number as a byte offset.
static void set_position(typval_T *argvars, typval_T *rettv, bool charpos)
{
  colnr_T curswant = -1;

  rettv->vval.v_number = -1;
  const char *const name = tv_get_string_chk(argvars);
  if (name == NULL) {
    return;
  }

  pos_T pos;
  int fnum;
  if (list2fpos(&argvars[1], &pos, &fnum, &curswant, charpos) != OK) {
    return;
  }

  if (pos.col != MAXCOL && --pos.col < 0) {
    pos.col = 0;
  }
  if (name[0] == '.' && name[1] == NUL) {
    // set cursor; "fnum" is ignored
Repository: neovim/neovim
File: runtime/lua/vim/_core/server.lua (Lua)

Code before:
local M = {}

--- Called by builtin serverlist(). Returns all running servers.
--- in stdpath("run"). Does not include named pipes or TCP servers.
---
--- @param listed string[] Already listed servers
--- @return string[] A list of currently running servers in stdpath("run")
function M.serverlist(listed)
  -- TODO: also get named pipes on Windows
  local socket_paths = vim.fs.find(function(name, _)
    return name:match('nvim.*')
  end, { path = vim.fn.stdpath('run'), type = 'socket', limit = math.huge })

  local running_sockets = {}
  for _, socket in ipairs(socket_paths) do
    -- Don't list servers twice
    if not vim.list_contains(listed, socket) then
      local ok, chan = pcall(vim.fn.sockconnect, 'pipe', socket, { rpc = true })
      if ok and chan then
        if vim.fn.rpcrequest(chan, 'nvim_get_chan_info', 0).id then
          table.insert(running_sockets, socket)
        end
        vim.fn.chanclose(chan)
      end
    end
  end

  return running_sockets
end

return M


Review comment (bug):
think about edge cases and failure possibilities in all code.

```suggestion
        -- Check that the server is responding.
        -- TODO: do we need a timeout or error handling here?
        if vim.fn.rpcrequest(chan, 'nvim_get_chan_info', 0).id then
```

Code after:
local M = {}

--- Called by builtin serverlist(). Returns all running servers.
--- in stdpath("run"). Does not include named pipes or TCP servers.
---
--- @param listed string[] Already listed servers
--- @return string[] A list of currently running servers in stdpath("run")
function M.serverlist(listed)
  -- TODO: also get named pipes on Windows
  local socket_paths = vim.fs.find(function(name, _)
    return name:match('nvim.*')
  end, { path = vim.fn.stdpath('run'), type = 'socket', limit = math.huge })

  local running_sockets = {}
  for _, socket in ipairs(socket_paths) do
    -- Don't list servers twice
    if not vim.list_contains(listed, socket) then
      local ok, chan = pcall(vim.fn.sockconnect, 'pipe', socket, { rpc = true })
      if ok and chan then
        -- Check that the server is responding
        -- TODO: do we need a timeout or error handling here?
        if vim.fn.rpcrequest(chan, 'nvim_get_chan_info', 0).id then
          table.insert(running_sockets, socket)
        end
        vim.fn.chanclose(chan)
      end
    end
  end

  return running_sockets
end

return M
Repository: neovim/neovim
File: runtime/lua/vim/filetype/detect.lua (Lua)

Code before:
    end
  end
end

--- @type vim.filetype.mapfn
function M.conf(path, bufnr)
  if fn.did_filetype() ~= 0 or path:find(vim.g.ft_ignore_pat) then
    return
  end
  if path:find('%.conf$') then
    return 'conf'
  end
  for _, line in ipairs(getlines(bufnr, 1, 5)) do
    if line:find('^#') then
      return 'conf'
    end
  end
end

--- Debian Control
--- @type vim.filetype.mapfn
function M.control(_, bufnr)
  local line1 = getline(bufnr, 1)
  if line1 and findany(line1, { '^Source:', '^Package:' }) then
    return 'debcontrol'
  elseif line1 and findany(line1, { '^Tests:', '^Test-Command:' }) then
    return 'autopkgtest'
  end
end

--- Debian Copyright
--- @type vim.filetype.mapfn
function M.copyright(_, bufnr)
  if getline(bufnr, 1):find('^Format:') then
    return 'debcopyright'
  end
end

--- @type vim.filetype.mapfn
function M.cpp(_, _)
  return vim.g.cynlib_syntax_for_cpp and 'cynlib' or 'cpp'
end

--- @type vim.filetype.mapfn
function M.csh(path, bufnr)
  if fn.did_filetype() ~= 0 then
    -- Filetype was already detected
    return
  end
  local contents = getlines(bufnr)
  if vim.g.filetype_csh then

Review comment (suggestion):
```suggestion
  elseif line1 and findany(line1, { '^Tests:', '^Test%-Command:' }) then
```

Code after:
    end
  end
end

--- @type vim.filetype.mapfn
function M.conf(path, bufnr)
  if fn.did_filetype() ~= 0 or path:find(vim.g.ft_ignore_pat) then
    return
  end
  if path:find('%.conf$') then
    return 'conf'
  end
  for _, line in ipairs(getlines(bufnr, 1, 5)) do
    if line:find('^#') then
      return 'conf'
    end
  end
end

--- Debian Control
--- @type vim.filetype.mapfn
function M.control(_, bufnr)
  local line1 = getline(bufnr, 1)
  if line1 and findany(line1, { '^Source:', '^Package:' }) then
    return 'debcontrol'
  elseif line1 and findany(line1, { '^Tests:', '^Test%-Command:' }) then
    return 'autopkgtest'
  end
end

--- Debian Copyright
--- @type vim.filetype.mapfn
function M.copyright(_, bufnr)
  if getline(bufnr, 1):find('^Format:') then
    return 'debcopyright'
  end
end

--- @type vim.filetype.mapfn
function M.cpp(_, _)
  return vim.g.cynlib_syntax_for_cpp and 'cynlib' or 'cpp'
end

--- @type vim.filetype.mapfn
function M.csh(path, bufnr)
  if fn.did_filetype() ~= 0 then
    -- Filetype was already detected
    return
  end
  local contents = getlines(bufnr)
  if vim.g.filetype_csh then
Repository: neovim/neovim
File: runtime/lua/vim/lsp/diagnostic.lua (Lua)

Code before:
---@brief This module provides functionality for requesting LSP diagnostics for a document/workspace
---and populating them using |vim.Diagnostic|s. `DiagnosticRelatedInformation` is supported: it is
---included in the window shown by |vim.diagnostic.open_float()|. When the cursor is on a line with
---related information, |gf| can be used to jump to the problematic location.

local lsp = vim.lsp
local protocol = lsp.protocol
local ms = protocol.Methods
local util = lsp.util

local api = vim.api

local M = {}

local augroup = api.nvim_create_augroup('nvim.lsp.diagnostic', {})

---@class (private) vim.lsp.diagnostic.BufState
---@field pull_kind 'document'|'workspace'|'disabled' Whether diagnostics are being updated via document pull, workspace pull, or disabled.
---@field client_result_id table<integer, string?> Latest responded `resultId`

---@type table<integer, vim.lsp.diagnostic.BufState>
local bufstates = {}

local DEFAULT_CLIENT_ID = -1

---@param severity lsp.DiagnosticSeverity
---@return vim.diagnostic.Severity
local function severity_lsp_to_vim(severity)
  if type(severity) == 'string' then

Review comment (suggestion):
```suggestion
---related information, |gf| jumps to the problem location.
```

Code after:
---@brief This module provides functionality for requesting LSP diagnostics for a document/workspace
---and populating them using |vim.Diagnostic|s. `DiagnosticRelatedInformation` is supported: it is
---included in the window shown by |vim.diagnostic.open_float()|. When the cursor is on a line with
---related information, |gf| jumps to the problem location.

local lsp = vim.lsp
local protocol = lsp.protocol
local ms = protocol.Methods
local util = lsp.util

local api = vim.api

local M = {}

local augroup = api.nvim_create_augroup('nvim.lsp.diagnostic', {})

---@class (private) vim.lsp.diagnostic.BufState
---@field pull_kind 'document'|'workspace'|'disabled' Whether diagnostics are being updated via document pull, workspace pull, or disabled.
---@field client_result_id table<integer, string?> Latest responded `resultId`

---@type table<integer, vim.lsp.diagnostic.BufState>
local bufstates = {}

local DEFAULT_CLIENT_ID = -1

---@param severity lsp.DiagnosticSeverity
---@return vim.diagnostic.Severity
local function severity_lsp_to_vim(severity)
  if type(severity) == 'string' then