Repository: neovim/neovim
File: runtime/lua/vim/diagnostic.lua (Lua)

Code before:
---@param bufnr integer Buffer number
---@param diagnostics vim.Diagnostic.Set[]
---@param opts? vim.diagnostic.Opts Display options to pass to |vim.diagnostic.show()|
function M.set(namespace, bufnr, diagnostics, opts)
  vim.validate('namespace', namespace, 'number')
  vim.validate('bufnr', bufnr, 'number')
  vim.validate('diagnostics', diagnostics, vim.islist, 'a list of diagnostics')
  vim.validate('opts', opts, 'table', true)

  bufnr = vim._resolve_bufnr(bufnr)

  for _, diagnostic in ipairs(diagnostics) do
    norm_diag(bufnr, namespace, diagnostic)
  end

  --- @cast diagnostics vim.Diagnostic[]

  if vim.tbl_isempty(diagnostics) then
    diagnostic_cache[bufnr][namespace] = nil
  else
    diagnostic_cache[bufnr][namespace] = diagnostics
  end

  once_buf_loaded(bufnr, function()
    local ns = M.get_namespace(namespace)

    if not ns.user_data.location_ns then
      ns.user_data.location_ns =
        api.nvim_create_namespace(string.format('nvim.%s.diagnostic', ns.name))
    end

    api.nvim_buf_clear_namespace(bufnr, ns.user_data.location_ns, 0, -1)

    local lines = api.nvim_buf_get_lines(bufnr, 0, -1, true)
    -- set extmarks at diagnostic locations to preserve logical positions despite text changes
    for _, diagnostic in ipairs(diagnostics) do
      local last_row = #lines - 1
      local row = math.max(0, math.min(diagnostic.lnum, last_row))
      local row_len = #lines[row + 1]
      local col = math.max(0, math.min(diagnostic.col, row_len - 1))

      local end_row = math.max(0, math.min(diagnostic.end_lnum or row, last_row))
      local end_row_len = #lines[end_row + 1]
      local end_col = math.max(0, math.min(diagnostic.end_col or col, end_row_len))

      if end_row == row then
        -- avoid starting an extmark beyond end of the line
        if end_col == col then
          end_col = math.min(end_col + 1, end_row_len)
        end
      else

Review comment (bug):
This is a whole new blob of code that future developers must study. We really need to give hints where we can. In this case, the key idea seems to be (correct if wrong):


```suggestion
  -- Compute positions, set them as extmarks, and store in diagnostic._extmark_id
  -- (used by get_logical_location to adjust positions). 
  once_buf_loaded(bufnr, function()
```

None of this will be obvious in the future. We need to leave hints.

Code after:
---@param bufnr integer Buffer number
---@param diagnostics vim.Diagnostic.Set[]
---@param opts? vim.diagnostic.Opts Display options to pass to |vim.diagnostic.show()|
function M.set(namespace, bufnr, diagnostics, opts)
  vim.validate('namespace', namespace, 'number')
  vim.validate('bufnr', bufnr, 'number')
  vim.validate('diagnostics', diagnostics, vim.islist, 'a list of diagnostics')
  vim.validate('opts', opts, 'table', true)

  bufnr = vim._resolve_bufnr(bufnr)

  for _, diagnostic in ipairs(diagnostics) do
    norm_diag(bufnr, namespace, diagnostic)
  end

  --- @cast diagnostics vim.Diagnostic[]

  if vim.tbl_isempty(diagnostics) then
    diagnostic_cache[bufnr][namespace] = nil
  else
    diagnostic_cache[bufnr][namespace] = diagnostics
  end

  -- Compute positions, set them as extmarks, and store in diagnostic._extmark_id
  -- (used by get_logical_pos to adjust positions).
  once_buf_loaded(bufnr, function()
    local ns = M.get_namespace(namespace)

    if not ns.user_data.location_ns then
      ns.user_data.location_ns =
        api.nvim_create_namespace(string.format('nvim.%s.diagnostic', ns.name))
    end

    api.nvim_buf_clear_namespace(bufnr, ns.user_data.location_ns, 0, -1)

    local lines = api.nvim_buf_get_lines(bufnr, 0, -1, true)
    -- set extmarks at diagnostic locations to preserve logical positions despite text changes
    for _, diagnostic in ipairs(diagnostics) do
      local last_row = #lines - 1
      local row = math.max(0, math.min(diagnostic.lnum, last_row))
      local row_len = #lines[row + 1]
      local col = math.max(0, math.min(diagnostic.col, row_len - 1))

      local end_row = math.max(0, math.min(diagnostic.end_lnum or row, last_row))
      local end_row_len = #lines[end_row + 1]
      local end_col = math.max(0, math.min(diagnostic.end_col or col, end_row_len))

      if end_row == row then
        -- avoid starting an extmark beyond end of the line
        if end_col == col then
          end_col = math.min(end_col + 1, end_row_len)