|
|
| (6 intermediate revisions by the same user not shown) |
| Line 1: |
Line 1: |
| -- Module:TranscludeModuleCode | | --[[ |
| -- Extracts a snippet of content from a specified page using either:
| | * Name: CodeToText |
| -- 1. A defined line range (from/to parameters)
| | * Author: Mark W. Datysgeld |
| -- 2. Hook markers like emojis (hook parameter)
| | * Description: Utility for extracting content snippets from wiki pages using emoji hook markers placed at the beginning and end of desired content sections |
| --
| | * Notes: Example usage: {{#invoke:CodeToText|showSnippet|page=Module:Example|hook=⭐}}; Supports emoji hooks like 🪝, 📌, 🔖, ⭐ for both inline and block content extraction |
| -- 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 = {} | | 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 31: |
Line 13: |
| return "Error: 'page' parameter is required" | | return "Error: 'page' parameter is required" |
| end | | end |
|
| | |
| local hook = frame.args.hook | | local hook = frame.args.hook |
| | | if not hook then |
| -- Fallback to line numbers if hook isn't provided
| | return "Error: 'hook' parameter is required" |
| 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 | | end |
|
| |
|
| Line 54: |
Line 29: |
| end | | end |
|
| |
|
| local result
| | -- Try inline hooks first |
|
| | local inlineSnippet = content:match(hook .. "(.-)" .. hook) |
| -- If hook is provided, use it to extract the snippet | | if inlineSnippet then |
| if hook then
| | return inlineSnippet |
| -- 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 | | end |
| | | |
| -- Cache the result before returning | | -- Find block hooks |
| snippetCache[cacheKey] = result | | local s, e = content:find(hook, 1, true) |
| return result | | if not s then |
| | return "Error: Need at least 2 instances of hook '" .. hook .. "' in '" .. pageName .. "'" |
| | end |
| | |
| | local s2, e2 = content:find(hook, e + 1, true) |
| | if not s2 then |
| | return "Error: Need at least 2 instances of hook '" .. hook .. "' in '" .. pageName .. "'" |
| | end |
| | |
| | -- Extract text between the two hooks, excluding the hook lines |
| | local snippet = content:sub(e + 1, s2 - 1) |
| | |
| | -- Trim leading and trailing newlines |
| | if snippet:sub(1,1) == "\n" then |
| | snippet = snippet:sub(2) |
| | end |
| | if snippet:sub(-1) == "\n" then |
| | snippet = snippet:sub(1, -2) |
| | end |
| | |
| | return snippet |
| end | | end |
|
| |
|
| return p | | return p |