_init_packages.lua 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. local pathtrails = {} --- @type table<string,true> ta
  2. vim._so_trails = {} --- @type string[]
  3. for s in (package.cpath .. ';'):gmatch('[^;]*;') do
  4. s = s:sub(1, -2) -- Strip trailing semicolon
  5. -- Find out path patterns. pathtrail should contain something like
  6. -- /?.so, \?.dll. This allows not to bother determining what correct
  7. -- suffixes are.
  8. local pathtrail = s:match('[/\\][^/\\]*%?.*$')
  9. if pathtrail and not pathtrails[pathtrail] then
  10. pathtrails[pathtrail] = true
  11. table.insert(vim._so_trails, pathtrail)
  12. end
  13. end
  14. --- @param name string
  15. function vim._load_package(name)
  16. local basename = name:gsub('%.', '/')
  17. local paths = { 'lua/' .. basename .. '.lua', 'lua/' .. basename .. '/init.lua' }
  18. local found = vim.api.nvim__get_runtime(paths, false, { is_lua = true })
  19. if #found > 0 then
  20. local f, err = loadfile(found[1])
  21. return f or error(err)
  22. end
  23. local so_paths = {}
  24. for _, trail in ipairs(vim._so_trails) do
  25. local path = 'lua' .. trail:gsub('?', basename) -- so_trails contains a leading slash
  26. table.insert(so_paths, path)
  27. end
  28. found = vim.api.nvim__get_runtime(so_paths, false, { is_lua = true })
  29. if #found > 0 then
  30. -- Making function name in Lua 5.1 (see src/loadlib.c:mkfuncname) is
  31. -- a) strip prefix up to and including the first dash, if any
  32. -- b) replace all dots by underscores
  33. -- c) prepend "luaopen_"
  34. -- So "foo-bar.baz" should result in "luaopen_bar_baz"
  35. local dash = name:find('-', 1, true)
  36. local modname = dash and name:sub(dash + 1) or name
  37. local f, err = package.loadlib(found[1], 'luaopen_' .. modname:gsub('%.', '_'))
  38. return f or error(err)
  39. end
  40. return nil
  41. end
  42. -- TODO(bfredl): dedicated state for this?
  43. if vim.api then
  44. -- Insert vim._load_package after the preloader at position 2
  45. table.insert(package.loaders, 2, vim._load_package)
  46. end
  47. -- builtin functions which always should be available
  48. require('vim.shared')
  49. vim._submodules = {
  50. inspect = true,
  51. version = true,
  52. fs = true,
  53. glob = true,
  54. iter = true,
  55. re = true,
  56. text = true,
  57. provider = true,
  58. }
  59. -- These are for loading runtime modules in the vim namespace lazily.
  60. setmetatable(vim, {
  61. --- @param t table<any,any>
  62. __index = function(t, key)
  63. if vim._submodules[key] then
  64. t[key] = require('vim.' .. key)
  65. return t[key]
  66. elseif key == 'inspect_pos' or key == 'show_pos' then
  67. require('vim._inspector')
  68. return t[key]
  69. elseif vim.startswith(key, 'uri_') then
  70. --- @type any?
  71. local val = require('vim.uri')[key]
  72. if val ~= nil then
  73. -- Expose all `vim.uri` functions on the `vim` module.
  74. t[key] = val
  75. return t[key]
  76. end
  77. end
  78. end,
  79. })
  80. --- <Docs described in |vim.empty_dict()| >
  81. ---@private
  82. --- TODO: should be in vim.shared when vim.shared always uses nvim-lua
  83. --- @diagnostic disable-next-line:duplicate-set-field
  84. function vim.empty_dict()
  85. return setmetatable({}, vim._empty_dict_mt)
  86. end
  87. -- only on main thread: functions for interacting with editor state
  88. if vim.api and not vim.is_thread() then
  89. require('vim._editor')
  90. end