From 61b73140bd792550e7ac1b8620c1a5104cf8115e Mon Sep 17 00:00:00 2001 From: Rikard Blixt Date: Sat, 18 Apr 2026 19:38:36 +0200 Subject: [PATCH 1/9] refactor: improve IDE require resolver --- .vscode/settings.json | 7 ++- lua/plugins/sumneko_plugin.lua | 83 ++++++++++++++-------------------- 2 files changed, 39 insertions(+), 51 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index acda9e63d38..58ec78f77e0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -21,5 +21,10 @@ "**/wikis/*/*/*/*/*.lua": "${dirname(-4)}: ${dirname(-5)}/${dirname(-6)}/${dirname}/${filename}", "**/wikis/*/*/*/*/*/*.lua": "${dirname(-4)}: ${dirname(-5)}/${dirname(-6)}/${dirname(-7)}/${dirname}/${filename}", "**/*.lua": "${dirname}: ${filename}" - } + }, + "Lua.runtime.special": { + "Lua.import": "require", + "Lua.requireIfExists": "require", + "mw.loadData": "require" + }, } diff --git a/lua/plugins/sumneko_plugin.lua b/lua/plugins/sumneko_plugin.lua index 32ea5db5f29..f15fc228028 100644 --- a/lua/plugins/sumneko_plugin.lua +++ b/lua/plugins/sumneko_plugin.lua @@ -3,67 +3,50 @@ -- The setting "Lua.runtime.plugin" needs to be set to "plugins/sumneko_plugin.lua" -- See more at https://github.com/sumneko/lua-language-server/wiki/Plugin -local liquipedia = {} - local importFunctions = {} -importFunctions.functions = {'require', 'mw%.loadData', 'Lua%.import', 'Lua%.requireIfExists'} - ----Transforms a MediaWiki module name, e.g. `Module:Array`, into a lua repository name, e.g. `Array` ----@param name string ----@return string -function importFunctions.luaifyModuleName(name) - local normModuleName = name - :gsub('Module:', '')-- Remove starting Module: - - return normModuleName -end - -function importFunctions._row(name) - local normModuleName = importFunctions.luaifyModuleName(name) - - return ' ---@module \'' .. normModuleName .. '\'' -end - -function importFunctions.annotate(text, funcName, diffs) - for module, positionEndOfRow in text:gmatch(funcName .. '%s*%(?%s*[\'"](.-)[\'"]%s*%)?.-()\r?\n') do - table.insert(diffs, - {start = positionEndOfRow, finish = positionEndOfRow - 1, text = importFunctions._row(module)} - ) - end -end - -function liquipedia.annotate(text, diffs) - for _, funcName in pairs(importFunctions.functions) do - importFunctions.annotate(text, funcName, diffs) - end -end - ----@class diff ----@field start integer # The number of bytes at the beginning of the replacement ----@field finish integer # The number of bytes at the end of the replacement ----@field text string # What to replace +---@param uri string +---@param name string # Argument of require() +---@param source string # The source file uri +---@return string[]? -- luacheck: push ignore --- setting non-standard global variable 'OnSetText' (but it's mandatory) ----@param uri string # The uri of file ----@param text string # The content of file ----@return nil|diff[] ----@diagnostic disable-next-line: global-element -function OnSetText(uri, text) +function ResolveRequire(uri, name, source) -- luacheck: pop ignore - if text:sub(1, 3) ~= '---' then + local fileName = importFunctions.luaifyModuleName(name) + + -- Extract the base path (up to and including /lua/) and the wiki name from the source URI + local basePath, wiki = source:match('^(file://.-/lua)/wikis/([^/]+)/') + if not basePath then return nil end - if text:sub(1, 8) == '---@meta' then - return nil + -- Check if the file exists in the same wiki + local wikiPath = basePath .. '/wikis/' .. wiki .. '/' .. fileName .. '.lua' + local wikiFile = io.open(wikiPath:gsub('^file://', ''), 'r') + if wikiFile then + wikiFile:close() + return {wikiPath} + end + + -- Fall back to commons wiki + local commonsPath = basePath .. '/wikis/commons/' .. fileName .. '.lua' + local commonsFile = io.open(commonsPath:gsub('^file://', ''), 'r') + if commonsFile then + commonsFile:close() + return {commonsPath} end - local diffs = {} + return nil +end - liquipedia.annotate(text, diffs) +---Transforms a MediaWiki module name, e.g. `Module:Array`, into a lua repository name, e.g. `Array` +---@param name string +---@return string +function importFunctions.luaifyModuleName(name) + local normModuleName = name + :gsub('Module:', '')-- Remove starting Module: - return diffs + return normModuleName end return importFunctions From 1bda17df097c961d62e7ee54be76794a28aee4c3 Mon Sep 17 00:00:00 2001 From: Rikard Blixt Date: Sat, 18 Apr 2026 19:48:09 +0200 Subject: [PATCH 2/9] good point --- lua/plugins/sumneko_plugin.lua | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lua/plugins/sumneko_plugin.lua b/lua/plugins/sumneko_plugin.lua index f15fc228028..ae9cc29c9cf 100644 --- a/lua/plugins/sumneko_plugin.lua +++ b/lua/plugins/sumneko_plugin.lua @@ -11,14 +11,17 @@ local importFunctions = {} ---@return string[]? -- luacheck: push ignore function ResolveRequire(uri, name, source) --- luacheck: pop ignore +-- luacheck: pop local fileName = importFunctions.luaifyModuleName(name) - -- Extract the base path (up to and including /lua/) and the wiki name from the source URI - local basePath, wiki = source:match('^(file://.-/lua)/wikis/([^/]+)/') + -- Extract the base path (up to and including /lua/) from the source URI. + -- Also try to extract the wiki name when the source is under /wikis//. + -- Files outside of /wikis/ (e.g. spec/, definitions/) default to commons. + local basePath = source:match('^(file://.-/lua)[/$]') if not basePath then return nil end + local wiki = source:match('^file://.-/lua/wikis/([^/]+)/') or 'commons' -- Check if the file exists in the same wiki local wikiPath = basePath .. '/wikis/' .. wiki .. '/' .. fileName .. '.lua' From e06fc272d80216c402fb4a8eb98ce5bba91d963c Mon Sep 17 00:00:00 2001 From: hjpalpha Date: Sun, 19 Apr 2026 13:39:25 +0200 Subject: [PATCH 3/9] just some indent fixes (spaces to tabs) --- .vscode/settings.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 58ec78f77e0..db3aa8a0768 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -23,8 +23,8 @@ "**/*.lua": "${dirname}: ${filename}" }, "Lua.runtime.special": { - "Lua.import": "require", + "Lua.import": "require", "Lua.requireIfExists": "require", "mw.loadData": "require" - }, + }, } From c7ba41b3278a65ae1cd5ef7d10160ee3d2b47ab0 Mon Sep 17 00:00:00 2001 From: Rikard Blixt Date: Wed, 29 Apr 2026 12:09:11 +0200 Subject: [PATCH 4/9] windows matcher --- lua/plugins/sumneko_plugin.lua | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lua/plugins/sumneko_plugin.lua b/lua/plugins/sumneko_plugin.lua index ae9cc29c9cf..acf3e28f805 100644 --- a/lua/plugins/sumneko_plugin.lua +++ b/lua/plugins/sumneko_plugin.lua @@ -5,12 +5,14 @@ local importFunctions = {} ----@param uri string ----@param name string # Argument of require() ----@param source string # The source file uri +local IS_WINDOWS = package.config:sub(1,1) ~= '/' + +---@param repoRoot string # Documentation of this parameter is unclear. Seems to be repo root +---@param name string # Argument of require() +---@param source string # The source file uri ---@return string[]? -- luacheck: push ignore -function ResolveRequire(uri, name, source) +function ResolveRequire(repoRoot, name, source) -- luacheck: pop local fileName = importFunctions.luaifyModuleName(name) @@ -21,6 +23,13 @@ function ResolveRequire(uri, name, source) if not basePath then return nil end + + if IS_WINDOWS then + -- On Windows, the file URI starts with file:///C:/path/to/repo, so we need to remove the extra slash + -- Also need to unescape the :, otherwise %3 would be treated as a capture group result in later patterns + basePath = basePath:gsub('^file:///', 'file://'):gsub('%%3A', ':') + end + local wiki = source:match('^file://.-/lua/wikis/([^/]+)/') or 'commons' -- Check if the file exists in the same wiki From 37f652f7e15a5a4edba3a9d995be1b1b86c870ea Mon Sep 17 00:00:00 2001 From: Rikard Blixt Date: Wed, 29 Apr 2026 12:10:54 +0200 Subject: [PATCH 5/9] add this too for safety --- lua/plugins/sumneko_plugin.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lua/plugins/sumneko_plugin.lua b/lua/plugins/sumneko_plugin.lua index acf3e28f805..6ec619c7dfb 100644 --- a/lua/plugins/sumneko_plugin.lua +++ b/lua/plugins/sumneko_plugin.lua @@ -29,6 +29,8 @@ function ResolveRequire(repoRoot, name, source) -- Also need to unescape the :, otherwise %3 would be treated as a capture group result in later patterns basePath = basePath:gsub('^file:///', 'file://'):gsub('%%3A', ':') end + -- See the unescaping of : above + basePath = basePath:gsub('%20', ' ') local wiki = source:match('^file://.-/lua/wikis/([^/]+)/') or 'commons' From 95e7b8e54abffe693e12af7c12849283c748f793 Mon Sep 17 00:00:00 2001 From: Rikard Blixt Date: Wed, 6 May 2026 09:02:58 +0200 Subject: [PATCH 6/9] Apply suggestion from @Rathoz --- lua/plugins/sumneko_plugin.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/plugins/sumneko_plugin.lua b/lua/plugins/sumneko_plugin.lua index 6ec619c7dfb..94fedf3c5dc 100644 --- a/lua/plugins/sumneko_plugin.lua +++ b/lua/plugins/sumneko_plugin.lua @@ -30,7 +30,7 @@ function ResolveRequire(repoRoot, name, source) basePath = basePath:gsub('^file:///', 'file://'):gsub('%%3A', ':') end -- See the unescaping of : above - basePath = basePath:gsub('%20', ' ') + basePath = basePath:gsub('%%20', ' ') local wiki = source:match('^file://.-/lua/wikis/([^/]+)/') or 'commons' From 45208fde9ebdcf23ec151a8b769e44a5d6d5ec91 Mon Sep 17 00:00:00 2001 From: Rikard Blixt Date: Wed, 6 May 2026 12:41:13 +0200 Subject: [PATCH 7/9] fix uri vs io paths for windows, refactor --- lua/plugins/sumneko_plugin.lua | 39 ++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/lua/plugins/sumneko_plugin.lua b/lua/plugins/sumneko_plugin.lua index 94fedf3c5dc..b6a634a3edd 100644 --- a/lua/plugins/sumneko_plugin.lua +++ b/lua/plugins/sumneko_plugin.lua @@ -24,33 +24,36 @@ function ResolveRequire(repoRoot, name, source) return nil end + -- See the unescaping of : below + basePath = basePath:gsub('%%20', ' ') + local ioPath if IS_WINDOWS then -- On Windows, the file URI starts with file:///C:/path/to/repo, so we need to remove the extra slash -- Also need to unescape the :, otherwise %3 would be treated as a capture group result in later patterns - basePath = basePath:gsub('^file:///', 'file://'):gsub('%%3A', ':') + basePath = basePath:gsub('%%3A', ':') + ioPath = basePath:gsub('^file:///', '') + else + ioPath = basePath:gsub('^file://', '') end - -- See the unescaping of : above - basePath = basePath:gsub('%%20', ' ') - local wiki = source:match('^file://.-/lua/wikis/([^/]+)/') or 'commons' + local targetWiki = source:match('^file://.-/lua/wikis/([^/]+)/') - -- Check if the file exists in the same wiki - local wikiPath = basePath .. '/wikis/' .. wiki .. '/' .. fileName .. '.lua' - local wikiFile = io.open(wikiPath:gsub('^file://', ''), 'r') - if wikiFile then + local function getFileForWiki(wiki) + if not wiki then + return + end + local pathSuffix = '/wikis/' .. wiki .. '/' .. fileName .. '.lua' + local wikiFile = io.open(ioPath .. pathSuffix, 'r') + print(wikiFile, ioPath .. pathSuffix) + if not wikiFile then + return + end wikiFile:close() - return {wikiPath} - end - - -- Fall back to commons wiki - local commonsPath = basePath .. '/wikis/commons/' .. fileName .. '.lua' - local commonsFile = io.open(commonsPath:gsub('^file://', ''), 'r') - if commonsFile then - commonsFile:close() - return {commonsPath} + print(basePath .. pathSuffix) + return {basePath .. pathSuffix} end - return nil + return getFileForWiki(targetWiki) or getFileForWiki('commons') or nil end ---Transforms a MediaWiki module name, e.g. `Module:Array`, into a lua repository name, e.g. `Array` From d786546594563f40c941a338a4667d636ef9b930 Mon Sep 17 00:00:00 2001 From: Rikard Blixt Date: Wed, 6 May 2026 12:53:56 +0200 Subject: [PATCH 8/9] remove excessive logging --- lua/plugins/sumneko_plugin.lua | 2 -- 1 file changed, 2 deletions(-) diff --git a/lua/plugins/sumneko_plugin.lua b/lua/plugins/sumneko_plugin.lua index b6a634a3edd..f9d5a75f4b5 100644 --- a/lua/plugins/sumneko_plugin.lua +++ b/lua/plugins/sumneko_plugin.lua @@ -44,12 +44,10 @@ function ResolveRequire(repoRoot, name, source) end local pathSuffix = '/wikis/' .. wiki .. '/' .. fileName .. '.lua' local wikiFile = io.open(ioPath .. pathSuffix, 'r') - print(wikiFile, ioPath .. pathSuffix) if not wikiFile then return end wikiFile:close() - print(basePath .. pathSuffix) return {basePath .. pathSuffix} end From e2baaf45c1576b32c86436d0fce350109b6d73b5 Mon Sep 17 00:00:00 2001 From: hjpalpha Date: Wed, 6 May 2026 18:11:45 +0200 Subject: [PATCH 9/9] as oer discussion on discord --- lua/plugins/sumneko_plugin.lua | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lua/plugins/sumneko_plugin.lua b/lua/plugins/sumneko_plugin.lua index f9d5a75f4b5..2bf79728c70 100644 --- a/lua/plugins/sumneko_plugin.lua +++ b/lua/plugins/sumneko_plugin.lua @@ -25,15 +25,14 @@ function ResolveRequire(repoRoot, name, source) end -- See the unescaping of : below - basePath = basePath:gsub('%%20', ' ') - local ioPath + local ioPath = basePath:gsub('%%20', ' ') if IS_WINDOWS then -- On Windows, the file URI starts with file:///C:/path/to/repo, so we need to remove the extra slash -- Also need to unescape the :, otherwise %3 would be treated as a capture group result in later patterns - basePath = basePath:gsub('%%3A', ':') - ioPath = basePath:gsub('^file:///', '') + ioPath = ioPath:gsub('%%3A', ':') + ioPath = ioPath:gsub('^file:///', '') else - ioPath = basePath:gsub('^file://', '') + ioPath = ioPath:gsub('^file://', '') end local targetWiki = source:match('^file://.-/lua/wikis/([^/]+)/')