diff options
Diffstat (limited to 'runtime/lua/vim')
| -rw-r--r-- | runtime/lua/vim/_editor.lua | 17 | ||||
| -rw-r--r-- | runtime/lua/vim/filetype.lua | 86 | ||||
| -rw-r--r-- | runtime/lua/vim/filetype/detect.lua | 413 | ||||
| -rw-r--r-- | runtime/lua/vim/lsp.lua | 5 | ||||
| -rw-r--r-- | runtime/lua/vim/lsp/diagnostic.lua | 42 | ||||
| -rw-r--r-- | runtime/lua/vim/lsp/log.lua | 81 | ||||
| -rw-r--r-- | runtime/lua/vim/lsp/util.lua | 2 | 
7 files changed, 550 insertions, 96 deletions
| diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index 8e372b806c..119467de16 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -58,6 +58,7 @@ vim.log = {      INFO  = 2;      WARN  = 3;      ERROR = 4; +    OFF   = 5;    }  } @@ -735,6 +736,22 @@ function vim._cs_remote(rcid, server_addr, connect_error, args)    }  end +--- Display a deprecation notification to the user. +--- +---@param name        string     Deprecated function. +---@param alternative string|nil Preferred alternative function. +---@param version     string     Version in which the deprecated function will +---                              be removed. +---@param plugin      string|nil Plugin name that the function will be removed +---                              from. Defaults to "Nvim". +function vim.deprecate(name, alternative, version, plugin) +    local message = name .. ' is deprecated' +    plugin = plugin or "Nvim" +    message = alternative and (message .. ', use ' .. alternative .. ' instead.') or message +    message = message .. ' See :h deprecated\nThis function will be removed in ' .. plugin .. ' version ' .. version +    vim.notify_once(message, vim.log.levels.WARN) +end +  require('vim._meta')  return vim diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 911950171f..32f4f825c1 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -784,19 +784,19 @@ local extension = {    zsh = "zsh",    vala = "vala",    E = function() vim.fn["dist#ft#FTe"]() end, -  EU = function() vim.fn["dist#ft#EuphoriaCheck"]() end, -  EW = function() vim.fn["dist#ft#EuphoriaCheck"]() end, -  EX = function() vim.fn["dist#ft#EuphoriaCheck"]() end, -  EXU = function() vim.fn["dist#ft#EuphoriaCheck"]() end, -  EXW = function() vim.fn["dist#ft#EuphoriaCheck"]() end, +  EU = function(path, bufnr) return require("vim.filetype.detect").euphoria(bufnr) end, +  EW = function(path, bufnr) return require("vim.filetype.detect").euphoria(bufnr) end, +  EX = function(path, bufnr) return require("vim.filetype.detect").euphoria(bufnr) end, +  EXU = function(path, bufnr) return require("vim.filetype.detect").euphoria(bufnr) end, +  EXW = function(path, bufnr) return require("vim.filetype.detect").euphoria(bufnr) end,    PL = function() vim.fn["dist#ft#FTpl"]() end, -  R = function() vim.fn["dist#ft#FTr"]() end, +  R = function(path, bufnr) require("vim.filetype.detect").r(bufnr) end,    asm = function() vim.fn["dist#ft#FTasm"]() end,    bas = function() vim.fn["dist#ft#FTbas"]() end,    bi = function() vim.fn["dist#ft#FTbas"]() end,    bm = function() vim.fn["dist#ft#FTbas"]() end,    bash = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end, -  btm = function() vim.fn["dist#ft#FTbtm"]() end, +  btm = function(path, bufnr) return require("vim.filetype.detect").btm(bufnr) end,    c = function() vim.fn["dist#ft#FTlpc"]() end,    ch = function() vim.fn["dist#ft#FTchange"]() end,    com = function() vim.fn["dist#ft#BindzoneCheck"]('dcl') end, @@ -808,29 +808,29 @@ local extension = {    e = function() vim.fn["dist#ft#FTe"]() end,    ebuild = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end,    eclass = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end, -  ent = function() vim.fn["dist#ft#FTent"]() end, +  ent = function(path, bufnr) return require("vim.filetype.detect").ent(bufnr) end,    env = function() vim.fn["dist#ft#SetFileTypeSH"](vim.fn.getline(1)) end, -  eu = function() vim.fn["dist#ft#EuphoriaCheck"]() end, -  ew = function() vim.fn["dist#ft#EuphoriaCheck"]() end, -  ex = function() vim.fn["dist#ft#ExCheck"]() end, -  exu = function() vim.fn["dist#ft#EuphoriaCheck"]() end, -  exw = function() vim.fn["dist#ft#EuphoriaCheck"]() end, -  frm = function() vim.fn["dist#ft#FTfrm"]() end, +  eu = function(path, bufnr) return require("vim.filetype.detect").euphoria(bufnr) end, +  ew = function(path, bufnr) return require("vim.filetype.detect").euphoria(bufnr) end, +  ex = function(path, bufnr) return require("vim.filetype.detect").ex(bufnr) end, +  exu = function(path, bufnr) return require("vim.filetype.detect").euphoria(bufnr) end, +  exw = function(path, bufnr) return require("vim.filetype.detect").euphoria(bufnr) end, +  frm = function(path, bufnr) require("vim.filetype.detect").frm(bufnr) end,    fs = function() vim.fn["dist#ft#FTfs"]() end, -  h = function() vim.fn["dist#ft#FTheader"]() end, +  h = function(path, bufnr) require("vim.filetype.detect").header(bufnr) end,    htm = function() vim.fn["dist#ft#FThtml"]() end,    html = function() vim.fn["dist#ft#FThtml"]() end,    i = function() vim.fn["dist#ft#FTprogress_asm"]() end, -  idl = function() vim.fn["dist#ft#FTidl"]() end, +  idl = function(path, bufnr) require("vim.filetype.detect").idl(bufnr) end,    inc = function() vim.fn["dist#ft#FTinc"]() end, -  inp = function() vim.fn["dist#ft#Check_inp"]() end, +  inp = function(path, bufnr) require("vim.filetype.detect").inp(bufnr) end,    ksh = function() vim.fn["dist#ft#SetFileTypeSH"]("ksh") end,    lst = function() vim.fn["dist#ft#FTasm"]() end,    m = function() vim.fn["dist#ft#FTm"]() end,    mac = function() vim.fn["dist#ft#FTasm"]() end, -  mc = function() vim.fn["dist#ft#McSetf"]() end, +  mc = function(path, bufnr) require("vim.filetype.detect").mc(bufnr) end,    mm = function() vim.fn["dist#ft#FTmm"]() end, -  mms = function() vim.fn["dist#ft#FTmms"]() end, +  mms = function(path, bufnr) require("vim.filetype.detect").mms(bufnr) end,    p = function() vim.fn["dist#ft#FTprogress_pascal"]() end,    patch = function(path, bufnr)      local firstline = getline(bufnr, 1) @@ -844,22 +844,22 @@ local extension = {    pp = function() vim.fn["dist#ft#FTpp"]() end,    pro = function() vim.fn["dist#ft#ProtoCheck"]('idlang') end,    pt = function() vim.fn["dist#ft#FThtml"]() end, -  r = function() vim.fn["dist#ft#FTr"]() end, -  rdf = function() vim.fn["dist#ft#Redif"]() end, +  r = function(path, bufnr) require("vim.filetype.detect").r(bufnr) end, +  rdf = function(path, bufnr) require("vim.filetype.detect").redif(bufnr) end,    rules = function() vim.fn["dist#ft#FTRules"]() end, -  sc = function() vim.fn["dist#ft#FTsc"]() end, -  scd = function() vim.fn["dist#ft#FTscd"]() end, +  sc = function(path, bufnr) require("vim.filetype.detect").sc(bufnr) end, +  scd = function(path, bufnr) require("vim.filetype.detect").scd(bufnr) end,    sh = function() vim.fn["dist#ft#SetFileTypeSH"](vim.fn.getline(1)) end,    shtml = function() vim.fn["dist#ft#FThtml"]() end, -  sql = function() vim.fn["dist#ft#SQL"]() end, +  sql = function(path, bufnr) require("vim.filetype.detect").sql(bufnr) end,    stm = function() vim.fn["dist#ft#FThtml"]() end,    tcsh = function() vim.fn["dist#ft#SetFileTypeShell"]("tcsh") end,    tex = function() vim.fn["dist#ft#FTtex"]() end, -  tf = function() vim.fn["dist#ft#FTtf"]() end, -  w = function() vim.fn["dist#ft#FTprogress_cweb"]() end, -  xml = function() vim.fn["dist#ft#FTxml"]() end, -  y = function() vim.fn["dist#ft#FTy"]() end, -  zsql = function() vim.fn["dist#ft#SQL"]() end, +  tf = function(path, bufnr) require("vim.filetype.detect").tf(bufnr) end, +  w = function(path, bufnr) require("vim.filetype.detect").progress_cweb(bufnr) end, +  xml = function(path, bufnr) require("vim.filetype.detect").xml(bufnr) end, +  y = function(path, bufnr) require("vim.filetype.detect").y(bufnr) end, +  zsql = function(path, bufnr) require("vim.filetype.detect").sql(bufnr) end,    txt = function(path, bufnr)      --helpfiles match *.txt, but should have a modeline as last line      if not getline(bufnr, -1):match("vim:.*ft=help") then @@ -933,10 +933,10 @@ local filename = {    ["exim.conf"] = "exim",    exports = "exports",    [".fetchmailrc"] = "fetchmail", -  fvSchemes = function() vim.fn["dist#ft#FTfoam"]() end, -  fvSolution = function() vim.fn["dist#ft#FTfoam"]() end, -  fvConstraints = function() vim.fn["dist#ft#FTfoam"]() end, -  fvModels = function() vim.fn["dist#ft#FTfoam"]() end, +  fvSchemes = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, +  fvSolution = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, +  fvConstraints = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, +  fvModels = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end,    fstab = "fstab",    mtab = "fstab",    [".gdbinit"] = "gdb", @@ -1355,7 +1355,7 @@ local pattern = {    ["%.zcompdump.*"] = starsetf('zsh'),    ["%.zlog.*"] = starsetf('zsh'),    ["%.zsh.*"] = starsetf('zsh'), -  [".*%.[1-9]"] = function() vim.fn["dist#ft#FTnroff"]() end, +  [".*%.[1-9]"] = function(path, bufnr) return require("vim.filetype.detect").nroff(bufnr) end,    [".*%.[aA]"] = function() vim.fn["dist#ft#FTasm"]() end,    [".*%.[sS]"] = function() vim.fn["dist#ft#FTasm"]() end,    [".*%.properties_.._.._.*"] = starsetf('jproperties'), @@ -1434,14 +1434,14 @@ local pattern = {    ["mutt" .. string.rep("[%w_-]", 6)] = "mail",    ["neomutt" .. string.rep("[%w_-]", 6)] = "mail",    ["/tmp/SLRN[0-9A-Z.]+"] = "mail", -  ["[a-zA-Z0-9].*Dict"] = function() vim.fn["dist#ft#FTfoam"]() end, -  ["[a-zA-Z0-9].*Dict%..*"] = function() vim.fn["dist#ft#FTfoam"]() end, -  ["[a-zA-Z].*Properties"] = function() vim.fn["dist#ft#FTfoam"]() end, -  ["[a-zA-Z].*Properties%..*"] = function() vim.fn["dist#ft#FTfoam"]() end, -  [".*Transport%..*"] = function() vim.fn["dist#ft#FTfoam"]() end, -  [".*/constant/g"] = function() vim.fn["dist#ft#FTfoam"]() end, -  [".*/0/.*"] = function() vim.fn["dist#ft#FTfoam"]() end, -  [".*/0%.orig/.*"] = function() vim.fn["dist#ft#FTfoam"]() end, +  ["[a-zA-Z0-9].*Dict"] = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, +  ["[a-zA-Z0-9].*Dict%..*"] = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, +  ["[a-zA-Z].*Properties"] = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, +  ["[a-zA-Z].*Properties%..*"] = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, +  [".*Transport%..*"] = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, +  [".*/constant/g"] = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, +  [".*/0/.*"] = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, +  [".*/0%.orig/.*"] = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end,    [".*/etc/sensors%.d/[^.].*"] = starsetf('sensors'),    [".*%.git/.*"] = function(path, bufnr)      local firstline = getline(bufnr, 1) @@ -1490,7 +1490,7 @@ local function normalize_path(path, as_pattern)      if as_pattern then        -- Escape Lua's metacharacters when $HOME is used in a pattern.        -- The rest of path should already be properly escaped. -      normal = vim.env.HOME:gsub('[-^$()%%.%[%]+?]', '%%%0') .. normal:sub(2) +      normal = vim.pesc(vim.env.HOME) .. normal:sub(2)      else        normal = vim.env.HOME .. normal:sub(2)      end diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua new file mode 100644 index 0000000000..787b335251 --- /dev/null +++ b/runtime/lua/vim/filetype/detect.lua @@ -0,0 +1,413 @@ +local M = {} + +---@private +local function getlines(bufnr, start_lnum, end_lnum, opts) +  if not end_lnum then +    -- Return a single line as a string +    return vim.api.nvim_buf_get_lines(bufnr, start_lnum - 1, start_lnum, false)[1] +  end + +  local lines = vim.api.nvim_buf_get_lines(bufnr, start_lnum - 1, end_lnum, false) +  opts = opts or {} +  return opts.concat and (table.concat(lines) or "") or lines +end + +---@private +local function findany(s, patterns) +  for _, v in ipairs(patterns) do +    if s:find(v) then +      return true +    end +  end +  return false +end + +-- luacheck: push no unused args +-- luacheck: push ignore 122 + +function M.asm(path, bufnr) end + +function M.asm_syntax(path, bufnr) end + +function M.bas(path, bufnr) end + +function M.bindzone(path, bufnr) end + +function M.btm(bufnr) +  if vim.g.dosbatch_syntax_for_btm and vim.g.dosbatch_syntax_for_btm ~= 0 then +    vim.bo[bufnr].filetype = "dosbatch" +  else +    vim.bo[bufnr].filetype = "btm" +  end +end + +-- Returns true if file content looks like RAPID +local function is_rapid(bufnr, extension) +  if extension == "cfg" then +    local line = getlines(bufnr, 1):lower() +    return findany(line, { "eio:cfg", "mmc:cfg", "moc:cfg", "proc:cfg", "sio:cfg", "sys:cfg" }) +  end +  local first = "^%s*module%s+%S+%s*" +  -- Called from mod, prg or sys functions +  for _, line in ipairs(getlines(bufnr, 1, -1)) do +    if not line:find("^%s*$") then +      return findany(line:lower(), { "^%s*%%%%%%", first .. "(", first .. "$" }) +    end +  end +  -- Only found blank lines +  return false +end + +function M.cfg(bufnr) +  if vim.g.filetype_cfg then +    vim.bo[bufnr].filetype = vim.g.filetype_cfg +  elseif is_rapid(bufnr, "cfg") then +    vim.bo[bufnr].filetype = "rapid" +  else +    vim.bo[bufnr].filetype = "cfg" +  end +end + +function M.change(path, bufnr) end + +function M.csh(path, bufnr) end + +function M.dat(path, bufnr) end + +function M.dep3patch(path, bufnr) end + +function M.dtrace(path, bufnr) end + +function M.e(path, bufnr) end + +-- This function checks for valid cl syntax in the first five lines. +-- Look for either an opening comment, '#', or a block start, '{'. +-- If not found, assume SGML. +function M.ent(bufnr) +  for _, line in ipairs(getlines(bufnr, 1, 5)) do +    if line:find("^%s*[#{]") then +      vim.bo[bufnr].filetype = "cl" +      return +    elseif not line:find("^%s*$") then +      -- Not a blank line, not a comment, and not a block start, +      -- so doesn't look like valid cl code. +      break +    end +  end +  vim.bo[bufnr].filetype = "dtd" +end + +function M.euphoria(bufnr) +  if vim.g.filetype_euphoria then +    vim.bo[bufnr].filetype = vim.g.filetype_euphoria +  else +    vim.bo[bufnr].filetype = "euphoria3" +  end +end + +function M.ex(bufnr) +  if vim.g.filetype_euphoria then +    vim.bo[bufnr].filetype = vim.g.filetype_euphoria +  else +    for _, line in ipairs(getlines(bufnr, 1, 100)) do +      -- TODO: in the Vim regex, \> is used to match the end of the word, can this be omitted? +      if findany(line, { "^%-%-", "^ifdef", "^include" }) then +        vim.bo[bufnr].filetype = "euphoria3" +        return +      end +    end +    vim.bo[bufnr].filetype = "elixir" +  end +end + +-- This function checks the first 15 lines for appearance of 'FoamFile' +-- and then 'object' in a following line. +-- In that case, it's probably an OpenFOAM file +function M.foam(bufnr) +  local foam_file = false +  for _, line in ipairs(getlines(bufnr, 1, 15)) do +    if line:find("^FoamFile") then +      foam_file = true +    elseif foam_file and line:find("^%s*object") then +      vim.bo[bufnr].filetype = "foam" +      return +    end +  end +end + +function M.frm(bufnr) +  if vim.g.filetype_frm then +    vim.bo[bufnr].filetype = vim.g.filetype_frm +  else +    -- Always ignore case +    local lines = getlines(bufnr, 1, 5, { concat = true }):lower() +    if findany(lines, { "vb_name", "begin vb%.form", "begin vb%.mdiform" }) then +      vim.bo[bufnr].filetype = "vb" +    else +      vim.bo[bufnr].filetype = "form" +    end +  end +end + +function M.fs(path, bufnr) end + +function M.header(bufnr) +  for _, line in ipairs(getlines(bufnr, 1, 200)) do +    if findany(line, { "^@interface", "^@end", "^@class" }) then +      if vim.g.c_syntax_for_h then +        vim.bo[bufnr].filetype = "objc" +      else +        vim.bo[bufnr].filetype = "objcpp" +      end +      return +    end +  end +  if vim.g.c_syntax_for_h then +    vim.bo[bufnr].filetype = "c" +  elseif vim.g.ch_syntax_for_h then +    vim.bo[bufnr].filetype = "ch" +  else +    vim.bo[bufnr].filetype = "cpp" +  end +end + +function M.idl(bufnr) +  for _, line in ipairs(getlines(bufnr, 1, 50)) do +    -- Always ignore case +    line = line:lower() +    if findany(line, { '^%s*import%s+"unknwn"%.idl', '^%s*import%s+"objidl"%.idl' }) then +      vim.bo[bufnr].filetype = "msidl" +      return +    end +  end +  vim.bo[bufnr].filetype = "idl" +end + +function M.inc(path, bufnr) end + +function M.inp(bufnr) +  if getlines(bufnr, 1):find("^%*") then +    vim.bo[bufnr].filetype = "abaqus" +  else +    for _, line in ipairs(getlines(bufnr, 1, 500)) do +      if line:lower():find("^header surface data") then +        vim.bo[bufnr].filetype = "trasys" +        return +      end +    end +  end +end + +function M.lpc(path, bufnr) end + +function M.lprolog(path, bufnr) end + +function M.m(path, bufnr) end + +-- Rely on the file to start with a comment. +-- MS message text files use ';', Sendmail files use '#' or 'dnl' +function M.mc(bufnr) +  for _, line in ipairs(getlines(bufnr, 1, 20)) do +    if findany(line:lower(), { "^%s*#", "^%s*dnl" }) then +      -- Sendmail .mc file +      vim.bo[bufnr].filetype = "m4" +      return +    elseif line:find("^%s*;") then +      vim.bo[bufnr].filetype = "msmessages" +      return +    end +  end +  -- Default: Sendmail .mc file +  vim.bo[bufnr].filetype = "m4" +end + +function M.mm(path, bufnr) end + +function M.mms(bufnr) +  for _, line in ipairs(getlines(bufnr, 1, 20)) do +    if findany(line, { "^%s*%%", "^%s*//", "^%*" }) then +      vim.bo[bufnr].filetype = "mmix" +      return +    elseif line:find("^%s*#") then +      vim.bo[bufnr].filetype = "make" +      return +    end +  end +  vim.bo[bufnr].filetype = "mmix" +end + +function M.mod(path, bufnr) end + +-- This function checks if one of the first five lines start with a dot. In +-- that case it is probably an nroff file: 'filetype' is set and 1 is returned. +function M.nroff(bufnr) +  for _, line in ipairs(getlines(bufnr, 1, 5)) do +    if line:find("^%.") then +      vim.bo[bufnr].filetype = "nroff" +      return 1 +    end +  end +  return 0 +end + +function M.perl(path, bufnr) end + +function M.pl(path, bufnr) end + +function M.pp(path, bufnr) end + +function M.prg(path, bufnr) end + +function M.progress_asm(path, bufnr) end + +function M.progress_cweb(bufnr) +  if vim.g.filetype_w then +    vim.bo[bufnr].filetype = vim.g.filetype_w +  else +    if getlines(bufnr, 1):find("^&ANALYZE") or getlines(bufnr, 3):find("^&GLOBAL%-DEFINE") then +      vim.bo[bufnr].filetype = "progress" +    else +      vim.bo[bufnr].filetype = "cweb" +    end +  end +end + +function M.progress_pascal(path, bufnr) end + +function M.proto(path, bufnr) end + +function M.r(bufnr) +  local lines = getlines(bufnr, 1, 50) +  -- TODO: \< / \> which match the beginning / end of a word +  -- Rebol is easy to recognize, check for that first +  if table.concat(lines):lower():find("rebol") then +    vim.bo[bufnr].filetype = "rebol" +    return +  end + +  for _, line in ipairs(lines) do +    -- R has # comments +    if line:find("^%s*#") then +      vim.bo[bufnr].filetype = "r" +      return +    end +    -- Rexx has /* comments */ +    if line:find("^%s*/%*") then +      vim.bo[bufnr].filetype = "rexx" +      return +    end +  end + +  -- Nothing recognized, use user default or assume R +  if vim.g.filetype_r then +    vim.bo[bufnr].filetype = vim.g.filetype_r +  else +    -- Rexx used to be the default, but R appears to be much more popular. +    vim.bo[bufnr].filetype = "r" +  end +end + +function M.redif(bufnr) +  for _, line in ipairs(getlines(bufnr, 1, 5)) do +    if line:lower():find("^template%-type:") then +      vim.bo[bufnr].filetype = "redif" +    end +  end +end + +function M.rules(path, bufnr) end + +-- This function checks the first 25 lines of file extension "sc" to resolve +-- detection between scala and SuperCollider +function M.sc(bufnr) +  for _, line in ipairs(getlines(bufnr, 1, 25)) do +    if findany(line, { "[A-Za-z0-9]*%s:%s[A-Za-z0-9]", "var%s<", "classvar%s<", "%^this.*", "|%w*|", "%+%s%w*%s{", "%*ar%s" }) then +      vim.bo[bufnr].filetype = "supercollider" +      return +    end +  end +  vim.bo[bufnr].filetype = "scala" +end + +-- This function checks the first line of file extension "scd" to resolve +-- detection between scdoc and SuperCollider +function M.scd(bufnr) +  local first = "^%S+%(%d[0-9A-Za-z]*%)" +  local opt = [[%s+"[^"]*"]] +  local line = getlines(bufnr, 1) +  if findany(line, { first .. "$", first .. opt .. "$", first .. opt .. opt .. "$" }) then +    vim.bo[bufnr].filetype = "scdoc" +  else +    vim.bo[bufnr].filetype = "supercollider" +  end +end + +function M.sh(path, bufnr) end + +function M.shell(path, bufnr) end + +function M.sql(bufnr) +  if vim.g.filetype_sql then +    vim.bo[bufnr].filetype = vim.g.filetype_sql +  else +    vim.bo[bufnr].filetype = "sql" +  end +end + +function M.src(path, bufnr) end + +function M.sys(path, bufnr) end + +function M.tex(path, bufnr) end + +-- Determine if a *.tf file is TF mud client or terraform +function M.tf(bufnr) +  for _, line in ipairs(getlines(bufnr, 1, -1)) do +    -- Assume terraform file on a non-empty line (not whitespace-only) +    -- and when the first non-whitespace character is not a ; or / +    if not line:find("^%s*$") and not line:find("^%s*[;/]") then +      vim.bo[bufnr].filetype = "terraform" +      return +    end +  end +  vim.bo[bufnr].filetype = "tf" +end + +function M.xml(bufnr) +  for _, line in ipairs(getlines(bufnr, 1, 100)) do +    line = line:lower() +    local is_docbook4 = line:find("<!doctype.*docbook") +    local is_docbook5 = line:find([[ xmlns="http://docbook.org/ns/docbook"]]) +    if is_docbook4 or is_docbook5 then +      vim.b[bufnr].docbk_type = "xml" +      vim.b[bufnr].docbk_ver = is_docbook4 and 4 or 5 +      vim.bo[bufnr].filetype = "docbk" +      return +    end +    if line:find([[xmlns:xbl="http://www.mozilla.org/xbl"]]) then +      vim.bo[bufnr].filetype = "xbl" +      return +    end +  end +  vim.bo[bufnr].filetype = "xml" +end + +function M.y(bufnr) +  for _, line in ipairs(getlines(bufnr, 1, 100)) do +    if line:find("^%s*%%") then +      vim.bo[bufnr].filetype = "yacc" +      return +    end +    -- TODO: in the Vim regex, \> is used to match the end of the word after "class", +    -- can this be omitted? +    if findany(line, { "^%s*#", "^%class", "^%s*#%s*include" }) then +      vim.bo[bufnr].filetype = "racc" +    end +  end +  vim.bo[bufnr].filetype = "yacc" +end + +-- luacheck: pop +-- luacheck: pop + +return M diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 19ee75a1b6..00f1c26692 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -1790,13 +1790,14 @@ end  --  -- Can be used to lookup the number from the name or the  -- name from the number. --- Levels by name: "TRACE", "DEBUG", "INFO", "WARN", "ERROR" +-- Levels by name: "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF"  -- Level numbers begin with "TRACE" at 0  lsp.log_levels = log.levels  --- Sets the global log level for LSP logging.  --- ---- Levels by name: "TRACE", "DEBUG", "INFO", "WARN", "ERROR" +--- Levels by name: "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF" +---  --- Level numbers begin with "TRACE" at 0  ---  --- Use `lsp.log_levels` for reverse lookup. diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 6a8d6dcad7..28a236cc7e 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -251,7 +251,7 @@ end  ---@param client_id number  ---@private  function M.save(diagnostics, bufnr, client_id) -  vim.notify_once('vim.lsp.diagnostic.save is deprecated. See :h deprecated', vim.log.levels.WARN) +  vim.deprecate('vim.lsp.diagnostic.save', 'vim.diagnostic.set', '0.8' )    local namespace = M.get_namespace(client_id)    vim.diagnostic.set(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id))  end @@ -265,7 +265,7 @@ end  ---                        If nil, diagnostics of all clients are included.  ---@return table with diagnostics grouped by bufnr (bufnr: Diagnostic[])  function M.get_all(client_id) -  vim.notify_once('vim.lsp.diagnostic.get_all is deprecated. See :h deprecated', vim.log.levels.WARN) +  vim.deprecate('vim.lsp.diagnostic.get_all', 'vim.diagnostic.get', '0.8' )    local result = {}    local namespace    if client_id then @@ -287,7 +287,7 @@ end  ---                            Else, return just the diagnostics associated with the client_id.  ---@param predicate function|nil Optional function for filtering diagnostics  function M.get(bufnr, client_id, predicate) -  vim.notify_once('vim.lsp.diagnostic.get is deprecated. See :h deprecated', vim.log.levels.WARN) +  vim.deprecate('vim.lsp.diagnostic.get', 'vim.diagnostic.get', '0.8' )    predicate = predicate or function() return true end    if client_id == nil then      local all_diagnostics = {} @@ -349,7 +349,7 @@ end  ---@param severity DiagnosticSeverity  ---@param client_id number the client id  function M.get_count(bufnr, severity, client_id) -  vim.notify_once('vim.lsp.diagnostic.get_count is deprecated. See :h deprecated', vim.log.levels.WARN) +  vim.deprecate('vim.lsp.diagnostic.get_count', 'vim.diagnostic.get', '0.8' )    severity = severity_lsp_to_vim(severity)    local opts = { severity = severity }    if client_id ~= nil then @@ -366,7 +366,7 @@ end  ---@param opts table See |vim.lsp.diagnostic.goto_next()|  ---@return table Previous diagnostic  function M.get_prev(opts) -  vim.notify_once('vim.lsp.diagnostic.get_prev is deprecated. See :h deprecated', vim.log.levels.WARN) +  vim.deprecate('vim.lsp.diagnostic.get_prev', 'vim.diagnostic.get_prev', '0.8' )    if opts then      if opts.severity then        opts.severity = severity_lsp_to_vim(opts.severity) @@ -384,7 +384,7 @@ end  ---@param opts table See |vim.lsp.diagnostic.goto_next()|  ---@return table Previous diagnostic position  function M.get_prev_pos(opts) -  vim.notify_once('vim.lsp.diagnostic.get_prev_pos is deprecated. See :h deprecated', vim.log.levels.WARN) +  vim.deprecate('vim.lsp.diagnostic.get_prev_pos', 'vim.diagnostic.get_prev_pos', '0.8' )    if opts then      if opts.severity then        opts.severity = severity_lsp_to_vim(opts.severity) @@ -401,7 +401,7 @@ end  ---  ---@param opts table See |vim.lsp.diagnostic.goto_next()|  function M.goto_prev(opts) -  vim.notify_once('vim.lsp.diagnostic.goto_prev is deprecated. See :h deprecated', vim.log.levels.WARN) +  vim.deprecate('vim.lsp.diagnostic.goto_prev', 'vim.diagnostic.goto_prev', '0.8' )    if opts then      if opts.severity then        opts.severity = severity_lsp_to_vim(opts.severity) @@ -419,7 +419,7 @@ end  ---@param opts table See |vim.lsp.diagnostic.goto_next()|  ---@return table Next diagnostic  function M.get_next(opts) -  vim.notify_once('vim.lsp.diagnostic.get_next is deprecated. See :h deprecated', vim.log.levels.WARN) +  vim.deprecate('vim.lsp.diagnostic.get_next', 'vim.diagnostic.get_next', '0.8' )    if opts then      if opts.severity then        opts.severity = severity_lsp_to_vim(opts.severity) @@ -437,7 +437,7 @@ end  ---@param opts table See |vim.lsp.diagnostic.goto_next()|  ---@return table Next diagnostic position  function M.get_next_pos(opts) -  vim.notify_once('vim.lsp.diagnostic.get_next_pos is deprecated. See :h deprecated', vim.log.levels.WARN) +  vim.deprecate('vim.lsp.diagnostic.get_next_pos', 'vim.diagnostic.get_next_pos', '0.8' )    if opts then      if opts.severity then        opts.severity = severity_lsp_to_vim(opts.severity) @@ -452,7 +452,7 @@ end  ---  ---@deprecated Prefer |vim.diagnostic.goto_next()|  function M.goto_next(opts) -  vim.notify_once('vim.lsp.diagnostic.goto_next is deprecated. See :h deprecated', vim.log.levels.WARN) +  vim.deprecate('vim.lsp.diagnostic.goto_next', 'vim.diagnostic.goto_next', '0.8' )    if opts then      if opts.severity then        opts.severity = severity_lsp_to_vim(opts.severity) @@ -476,7 +476,7 @@ end  ---             - severity_limit (DiagnosticSeverity):  ---                 - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid.  function M.set_signs(diagnostics, bufnr, client_id, _, opts) -  vim.notify_once('vim.lsp.diagnostic.set_signs is deprecated. See :h deprecated', vim.log.levels.WARN) +  vim.deprecate('vim.lsp.diagnostic.set_signs', nil , '0.8' )    local namespace = M.get_namespace(client_id)    if opts and not opts.severity and opts.severity_limit then      opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)} @@ -497,7 +497,7 @@ end  ---             - severity_limit (DiagnosticSeverity):  ---                 - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid.  function M.set_underline(diagnostics, bufnr, client_id, _, opts) -  vim.notify_once('vim.lsp.diagnostic.set_underline is deprecated. See :h deprecated', vim.log.levels.WARN) +  vim.deprecate('vim.lsp.diagnostic.set_underline', nil , '0.8' )    local namespace = M.get_namespace(client_id)    if opts and not opts.severity and opts.severity_limit then      opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)} @@ -519,7 +519,7 @@ end  ---             - severity_limit (DiagnosticSeverity):  ---                 - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid.  function M.set_virtual_text(diagnostics, bufnr, client_id, _, opts) -  vim.notify_once('vim.lsp.diagnostic.set_virtual_text is deprecated. See :h deprecated', vim.log.levels.WARN) +  vim.deprecate('vim.lsp.diagnostic.set_virtual_text', nil , '0.8' )    local namespace = M.get_namespace(client_id)    if opts and not opts.severity and opts.severity_limit then      opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)} @@ -538,7 +538,7 @@ end  ---@return an array of [text, hl_group] arrays. This can be passed directly to  ---        the {virt_text} option of |nvim_buf_set_extmark()|.  function M.get_virtual_text_chunks_for_line(bufnr, _, line_diags, opts) -  vim.notify_once('vim.lsp.diagnostic.get_virtual_text_chunks_for_line is deprecated. See :h deprecated', vim.log.levels.WARN) +  vim.deprecate('vim.lsp.diagnostic.get_virtual_text_chunks_for_line', nil, '0.8' )    return vim.diagnostic._get_virt_text_chunks(diagnostic_lsp_to_vim(line_diags, bufnr), opts)  end @@ -556,7 +556,7 @@ end  ---@param position table|nil The (0,0)-indexed position  ---@return table {popup_bufnr, win_id}  function M.show_position_diagnostics(opts, buf_nr, position) -  vim.notify_once('vim.lsp.diagnostic.show_position_diagnostics is deprecated. See :h deprecated', vim.log.levels.WARN) +  vim.deprecate('vim.lsp.diagnostic.show_position_diagnostics', 'vim.diagnostic.open_float', '0.8' )    opts = opts or {}    opts.scope = "cursor"    opts.pos = position @@ -580,7 +580,7 @@ end  ---@param client_id number|nil the client id  ---@return table {popup_bufnr, win_id}  function M.show_line_diagnostics(opts, buf_nr, line_nr, client_id) -  vim.notify_once('vim.lsp.diagnostic.show_line_diagnostics is deprecated. See :h deprecated', vim.log.levels.WARN) +  vim.deprecate('vim.lsp.diagnostic.show_line_diagnostics', 'vim.diagnostic.open_float', '0.8' )    opts = opts or {}    opts.scope = "line"    opts.pos = line_nr @@ -604,7 +604,7 @@ end  ---       client. The default is to redraw diagnostics for all attached  ---       clients.  function M.redraw(bufnr, client_id) -  vim.notify_once('vim.lsp.diagnostic.redraw is deprecated. See :h deprecated', vim.log.levels.WARN) +  vim.deprecate('vim.lsp.diagnostic.redraw', 'vim.diagnostic.show', '0.8' )    bufnr = get_bufnr(bufnr)    if not client_id then      return vim.lsp.for_each_buffer_client(bufnr, function(client) @@ -632,7 +632,7 @@ end  ---         - {workspace}: (boolean, default true)  ---             - Set the list with workspace diagnostics  function M.set_qflist(opts) -  vim.notify_once('vim.lsp.diagnostic.set_qflist is deprecated. See :h deprecated', vim.log.levels.WARN) +  vim.deprecate('vim.lsp.diagnostic.set_qflist', 'vim.diagnostic.setqflist', '0.8' )    opts = opts or {}    if opts.severity then      opts.severity = severity_lsp_to_vim(opts.severity) @@ -664,7 +664,7 @@ end  ---         - {workspace}: (boolean, default false)  ---             - Set the list with workspace diagnostics  function M.set_loclist(opts) -  vim.notify_once('vim.lsp.diagnostic.set_loclist is deprecated. See :h deprecated', vim.log.levels.WARN) +  vim.deprecate('vim.lsp.diagnostic.set_loclist', 'vim.diagnostic.setloclist', '0.8' )    opts = opts or {}    if opts.severity then      opts.severity = severity_lsp_to_vim(opts.severity) @@ -692,7 +692,7 @@ end  -- send diagnostic information and the client will still process it. The  -- diagnostics are simply not displayed to the user.  function M.disable(bufnr, client_id) -  vim.notify_once('vim.lsp.diagnostic.disable is deprecated. See :h deprecated', vim.log.levels.WARN) +  vim.deprecate('vim.lsp.diagnostic.disable', 'vim.diagnostic.disable', '0.8' )    if not client_id then      return vim.lsp.for_each_buffer_client(bufnr, function(client)        M.disable(bufnr, client.id) @@ -713,7 +713,7 @@ end  ---       client. The default is to enable diagnostics for all attached  ---       clients.  function M.enable(bufnr, client_id) -  vim.notify_once('vim.lsp.diagnostic.enable is deprecated. See :h deprecated', vim.log.levels.WARN) +  vim.deprecate('vim.lsp.diagnostic.enable', 'vim.diagnostic.enable', '0.8' )    if not client_id then      return vim.lsp.for_each_buffer_client(bufnr, function(client)        M.enable(bufnr, client.id) diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua index e0b5653587..fff42fd011 100644 --- a/runtime/lua/vim/lsp/log.lua +++ b/runtime/lua/vim/lsp/log.lua @@ -8,7 +8,7 @@ local log = {}  -- Log level dictionary with reverse lookup as well.  --  -- Can be used to lookup the number from the name or the name from the number. --- Levels by name: "TRACE", "DEBUG", "INFO", "WARN", "ERROR" +-- Levels by name: "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF"  -- Level numbers begin with "TRACE" at 0  log.levels = vim.deepcopy(vim.log.levels) @@ -25,27 +25,47 @@ do    end    local logfilename = path_join(vim.fn.stdpath('cache'), 'lsp.log') +  -- TODO: Ideally the directory should be created in open_logfile(), right +  -- before opening the log file, but open_logfile() can be called from libuv +  -- callbacks, where using fn.mkdir() is not allowed. +  vim.fn.mkdir(vim.fn.stdpath('cache'), "p") +    --- Returns the log filename.    ---@returns (string) log filename    function log.get_filename()      return logfilename    end -  vim.fn.mkdir(vim.fn.stdpath('cache'), "p") -  local logfile = assert(io.open(logfilename, "a+")) - -  local log_info = vim.loop.fs_stat(logfilename) -  if log_info and log_info.size > 1e9 then -    local warn_msg = string.format( -      "LSP client log is large (%d MB): %s", -      log_info.size / (1000 * 1000), -      logfilename -    ) -    vim.notify(warn_msg) +  local logfile, openerr +  ---@private +  --- Opens log file. Returns true if file is open, false on error +  local function open_logfile() +    -- Try to open file only once +    if logfile then return true end +    if openerr then return false end + +    logfile, openerr = io.open(logfilename, "a+") +    if not logfile then +      local err_msg = string.format("Failed to open LSP client log file: %s", openerr) +      vim.notify(err_msg, vim.log.levels.ERROR) +      return false +    end + +    local log_info = vim.loop.fs_stat(logfilename) +    if log_info and log_info.size > 1e9 then +      local warn_msg = string.format( +        "LSP client log is large (%d MB): %s", +        log_info.size / (1000 * 1000), +        logfilename +      ) +      vim.notify(warn_msg) +    end + +    -- Start message for logging +    logfile:write(string.format("[START][%s] LSP logging initiated\n", os.date(log_date_format))) +    return true    end -  -- Start message for logging -  logfile:write(string.format("[START][%s] LSP logging initiated\n", os.date(log_date_format)))    for level, levelnr in pairs(log.levels) do      -- Also export the log level on the root object.      log[level] = levelnr @@ -63,23 +83,26 @@ do      -- ```      --      -- This way you can avoid string allocations if the log level isn't high enough. -    log[level:lower()] = function(...) -      local argc = select("#", ...) -      if levelnr < current_log_level then return false end -      if argc == 0 then return true end -      local info = debug.getinfo(2, "Sl") -      local header = string.format("[%s][%s] ...%s:%s", level, os.date(log_date_format), string.sub(info.short_src, #info.short_src - 15), info.currentline) -      local parts = { header } -      for i = 1, argc do -        local arg = select(i, ...) -        if arg == nil then -          table.insert(parts, "nil") -        else -          table.insert(parts, format_func(arg)) +    if level ~= "OFF" then +      log[level:lower()] = function(...) +        local argc = select("#", ...) +        if levelnr < current_log_level then return false end +        if argc == 0 then return true end +        if not open_logfile() then return false end +        local info = debug.getinfo(2, "Sl") +        local header = string.format("[%s][%s] ...%s:%s", level, os.date(log_date_format), string.sub(info.short_src, #info.short_src - 15), info.currentline) +        local parts = { header } +        for i = 1, argc do +          local arg = select(i, ...) +          if arg == nil then +            table.insert(parts, "nil") +          else +            table.insert(parts, format_func(arg)) +          end          end +        logfile:write(table.concat(parts, '\t'), "\n") +        logfile:flush()        end -      logfile:write(table.concat(parts, '\t'), "\n") -      logfile:flush()      end    end  end diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 77ab1d4224..72dfb3cd76 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -456,7 +456,7 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)    -- Remove final line if needed    local fix_eol = has_eol_text_edit -  fix_eol = fix_eol and (api.nvim_buf_get_option(bufnr, 'eol') or (api.nvim_buf_get_option(bufnr, 'fixeol') and not api.nvim_buf_get_option('binary'))) +  fix_eol = fix_eol and (api.nvim_buf_get_option(bufnr, 'eol') or (api.nvim_buf_get_option(bufnr, 'fixeol') and not api.nvim_buf_get_option(bufnr, 'binary')))    fix_eol = fix_eol and get_line(bufnr, max - 1) == ''    if fix_eol then      vim.api.nvim_buf_set_lines(bufnr, -2, -1, false, {}) | 
