Module:CodeToText: Difference between revisions
Appearance
// via Wikitext Extension for VSCode |
// via Wikitext Extension for VSCode |
||
| Line 13: | Line 13: | ||
local p = {} | local p = {} | ||
-- Cache for previously extracted snippets (persists during a single page render) | |||
local snippetCache = {} | |||
-- Helper function to create a cache key from parameters | |||
local function createCacheKey(pageName, hook, fromLine, toLine) | |||
if hook then | |||
return pageName .. "|hook=" .. hook | |||
else | |||
return pageName .. "|from=" .. tostring(fromLine) .. "|to=" .. tostring(toLine) | |||
end | |||
end | |||
function p.showSnippet(frame) | function p.showSnippet(frame) | ||
| Line 25: | Line 37: | ||
local fromLine = tonumber(frame.args.from) or 1 | local fromLine = tonumber(frame.args.from) or 1 | ||
local toLine = tonumber(frame.args.to) or fromLine | local toLine = tonumber(frame.args.to) or fromLine | ||
-- Check cache first for previously extracted snippets | |||
local cacheKey = createCacheKey(pageName, hook, fromLine, toLine) | |||
if snippetCache[cacheKey] then | |||
return snippetCache[cacheKey] | |||
end | |||
local titleObj = mw.title.new(pageName) | local titleObj = mw.title.new(pageName) | ||
| Line 36: | Line 54: | ||
end | end | ||
local | local result | ||
-- If hook is provided, use it to extract the snippet | -- If hook is provided, use it to extract the snippet | ||
if hook then | if hook then | ||
-- First, check | -- First, check for inline hooks (hooks on the same line) | ||
-- This is more efficient than splitting into lines first | |||
local inlinePattern = hook .. "(.-)" .. hook | |||
local inlineMatch = content:match(inlinePattern) | |||
-- | if inlineMatch then | ||
-- We found inline hooks - use the content between them | |||
result = inlineMatch | |||
else | |||
-- Look for hooks on different lines | |||
local lines = {} | |||
local lineCount = 0 | |||
local hookPositions = {} | local hookPositions = {} | ||
-- Find all instances of the hook | -- Find all instances of the hook and count lines | ||
for | local lineNumber = 0 | ||
for line in content:gmatch("[^\r\n]+") do | |||
lineNumber = lineNumber + 1 | |||
lineCount = lineNumber | |||
if line:find(hook, 1, true) then | if line:find(hook, 1, true) then | ||
table.insert(hookPositions, | table.insert(hookPositions, lineNumber) | ||
end | end | ||
-- Store all lines for later use | |||
lines[lineNumber] = line | |||
end | end | ||
| Line 91: | Line 98: | ||
local endIndex = endLine - 1 | local endIndex = endLine - 1 | ||
for i = | -- Pre-allocate snippet table with known size | ||
table. | local snippetSize = math.max(0, endIndex - startIndex + 1) | ||
local snippet = {} | |||
if snippetSize > 0 then | |||
for i = 1, snippetSize do | |||
snippet[i] = lines[startIndex + i - 1] | |||
end | |||
result = table.concat(snippet, "\n") | |||
else | |||
result = "" | |||
end | end | ||
end | end | ||
else | else | ||
-- Fallback to line number-based extraction | -- Fallback to line number-based extraction | ||
for | -- For line-based extraction, we can be more efficient by only processing the needed lines | ||
local lineNumber = 0 | |||
local snippet = {} | |||
local snippetIndex = 0 | |||
-- Only process lines up to toLine | |||
for line in content:gmatch("[^\r\n]+") do | |||
lineNumber = lineNumber + 1 | |||
-- Skip lines before fromLine | |||
if lineNumber >= fromLine then | |||
-- Stop once we've reached toLine | |||
if lineNumber > toLine then | |||
break | |||
end | |||
snippetIndex = snippetIndex + 1 | |||
snippet[snippetIndex] = line | |||
end | |||
end | end | ||
result = table.concat(snippet, "\n") | |||
end | end | ||
return | -- Cache the result before returning | ||
snippetCache[cacheKey] = result | |||
return result | |||
end | end | ||
return p | return p | ||
Revision as of 21:01, 7 April 2025
Documentation for this module may be created at Module:CodeToText/doc
-- Module:TranscludeModuleCode
-- Extracts a snippet of content from a specified page using either:
-- 1. A defined line range (from/to parameters)
-- 2. Hook markers like emojis (hook parameter)
--
-- The module finds content between matching instances of the same hook,
-- either on different lines or within the same line. Any emoji can be used
-- as a hook (🪝, 📌, 🔖, 🏷️, 🚩, ⭐, etc.) - just place the same emoji at
-- the beginning and end of the content you want to extract.
--
-- Example:
-- {{#invoke:TranscludeModuleCode|showSnippet|page=Module:Example|hook=⭐}}
local p = {}
-- Cache for previously extracted snippets (persists during a single page render)
local snippetCache = {}
-- Helper function to create a cache key from parameters
local function createCacheKey(pageName, hook, fromLine, toLine)
if hook then
return pageName .. "|hook=" .. hook
else
return pageName .. "|from=" .. tostring(fromLine) .. "|to=" .. tostring(toLine)
end
end
function p.showSnippet(frame)
local pageName = frame.args.page
if not pageName then
return "Error: 'page' parameter is required"
end
local hook = frame.args.hook
-- Fallback to line numbers if hook isn't provided
local fromLine = tonumber(frame.args.from) or 1
local toLine = tonumber(frame.args.to) or fromLine
-- Check cache first for previously extracted snippets
local cacheKey = createCacheKey(pageName, hook, fromLine, toLine)
if snippetCache[cacheKey] then
return snippetCache[cacheKey]
end
local titleObj = mw.title.new(pageName)
if not titleObj then
return "Failed to create mw.title object for '" .. pageName .. "'"
end
local content = titleObj:getContent()
if not content then
return "No content for '" .. pageName .. "'"
end
local result
-- If hook is provided, use it to extract the snippet
if hook then
-- First, check for inline hooks (hooks on the same line)
-- This is more efficient than splitting into lines first
local inlinePattern = hook .. "(.-)" .. hook
local inlineMatch = content:match(inlinePattern)
if inlineMatch then
-- We found inline hooks - use the content between them
result = inlineMatch
else
-- Look for hooks on different lines
local lines = {}
local lineCount = 0
local hookPositions = {}
-- Find all instances of the hook and count lines
local lineNumber = 0
for line in content:gmatch("[^\r\n]+") do
lineNumber = lineNumber + 1
lineCount = lineNumber
if line:find(hook, 1, true) then
table.insert(hookPositions, lineNumber)
end
-- Store all lines for later use
lines[lineNumber] = line
end
if #hookPositions < 2 then
return "Error: Need at least 2 instances of hook '" .. hook .. "' in '" .. pageName .. "'"
end
-- Extract content between first two hook instances (excluding the hook lines)
local startLine = hookPositions[1]
local endLine = hookPositions[2]
-- Always exclude the hook lines
local startIndex = startLine + 1
local endIndex = endLine - 1
-- Pre-allocate snippet table with known size
local snippetSize = math.max(0, endIndex - startIndex + 1)
local snippet = {}
if snippetSize > 0 then
for i = 1, snippetSize do
snippet[i] = lines[startIndex + i - 1]
end
result = table.concat(snippet, "\n")
else
result = ""
end
end
else
-- Fallback to line number-based extraction
-- For line-based extraction, we can be more efficient by only processing the needed lines
local lineNumber = 0
local snippet = {}
local snippetIndex = 0
-- Only process lines up to toLine
for line in content:gmatch("[^\r\n]+") do
lineNumber = lineNumber + 1
-- Skip lines before fromLine
if lineNumber >= fromLine then
-- Stop once we've reached toLine
if lineNumber > toLine then
break
end
snippetIndex = snippetIndex + 1
snippet[snippetIndex] = line
end
end
result = table.concat(snippet, "\n")
end
-- Cache the result before returning
snippetCache[cacheKey] = result
return result
end
return p