Jump to content

Module:CodeToText: Difference between revisions

// via Wikitext Extension for VSCode
// via Wikitext Extension for VSCode
Line 1: Line 1:
-- Module:TranscludeModuleCode
-- Module:TranscludeModuleCode
-- Extracts content snippets from a page using:
-- Extracts content snippets from a page using hook markers
-- 1. Line range (from/to parameters)
-- 2. Hook markers (hook parameter)
--  
--  
-- Finds content between matching hooks (e.g., 🪝, 📌, 🔖, ⭐)
-- Finds content between matching hooks (e.g., 🪝, 📌, 🔖, ⭐) placed at the beginning and end of desired content.
-- placed at the beginning and end of desired content.
--  
--  
-- Example:
-- Example:
Line 16: Line 13:


-- Helper function to create a cache key from parameters
-- Helper function to create a cache key from parameters
local function createCacheKey(pageName, hook, fromLine, toLine)
local function createCacheKey(pageName, hook)
     if hook then
     return pageName .. "|hook=" .. hook
        return pageName .. "|hook=" .. hook
    else
        return pageName .. "|from=" .. tostring(fromLine) .. "|to=" .. tostring(toLine)
    end
end
end


Line 31: Line 24:
      
      
     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
     end
     local toLine  = tonumber(frame.args.to)  or fromLine
      
      
     -- Check cache first for previously extracted snippets
     -- Check cache first for previously extracted snippets
     local cacheKey = createCacheKey(pageName, hook, fromLine, toLine)
     local cacheKey = createCacheKey(pageName, hook)
     if snippetCache[cacheKey] then
     if snippetCache[cacheKey] then
         return snippetCache[cacheKey]
         return snippetCache[cacheKey]
Line 54: Line 46:
     local result
     local result
      
      
     -- If hook is provided, use it to extract the snippet
     -- First, check for hooks on the same line
    if hook then
    local inlinePattern = hook .. "(.-)" .. hook
        -- First, check for inline hooks (hooks on the same line)
    local inlineMatch = content:match(inlinePattern)
        -- This is more efficient than splitting into lines first
   
        local inlinePattern = hook .. "(.-)" .. hook
    if inlineMatch then
        local inlineMatch = content:match(inlinePattern)
        -- We found inline hooks: use the content between them
        result = inlineMatch
    else
        -- Look for hooks on different lines
        local lines = {}
        local hookPositions = {}
          
          
         if inlineMatch then
         -- Find hook instances and count lines
            -- We found inline hooks - use the content between them
        local lineNumber = 0
            result = inlineMatch
         for line in content:gmatch("[^\r\n]+") do
         else
             lineNumber = lineNumber + 1
            -- Look for hooks on different lines
             local lines = {}
            local lineCount = 0
            local hookPositions = {}
              
              
-- Find hook instances and count lines
             if line:find(hook, 1, true) then
            local lineNumber = 0
                table.insert(hookPositions, lineNumber)
             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
             end
              
              
             if #hookPositions < 2 then
             -- Store all lines for later use
                return "Error: Need at least 2 instances of hook '" .. hook .. "' in '" .. pageName .. "'"
            lines[lineNumber] = line
            end
        end
           
       
-- Extract content between first two hook instances
        if #hookPositions < 2 then
            local startLine = hookPositions[1]
            return "Error: Need at least 2 instances of hook '" .. hook .. "' in '" .. pageName .. "'"
            local endLine = hookPositions[2]
           
            -- Always exclude the hook lines
            local startIndex = startLine + 1
            local endIndex = endLine - 1
           
-- Pre-allocate snippet 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
    else
       
-- Fallback to line number-based extraction
        -- Extract content between first two hook instances
-- Process only the needed lines for efficiency
        local startLine = hookPositions[1]
         local lineNumber = 0
        local endLine = hookPositions[2]
       
        -- Always exclude the hook lines
         local startIndex = startLine + 1
        local endIndex = endLine - 1
       
        -- Pre-allocate snippet table
        local snippetSize = math.max(0, endIndex - startIndex + 1)
         local snippet = {}
         local snippet = {}
        local snippetIndex = 0
          
          
         -- Only process lines up to toLine
         if snippetSize > 0 then
        for line in content:gmatch("[^\r\n]+") do
            for i = 1, snippetSize do
            lineNumber = lineNumber + 1
                 snippet[i] = lines[startIndex + i - 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")
        else
            result = ""
         end
         end
       
        result = table.concat(snippet, "\n")
     end
     end
      
      

Revision as of 04:48, 12 April 2025

Documentation for this module may be created at Module:CodeToText/doc

-- Module:TranscludeModuleCode
-- Extracts content snippets from a page using hook markers
-- 
-- Finds content between matching hooks (e.g., 🪝, 📌, 🔖, ⭐) placed at the beginning and end of desired content.
-- 
-- Example:
--   {{#invoke:TranscludeModuleCode|showSnippet|page=Module:Example|hook=⭐}}

local p = {}

-- Cache for extracted snippets (persists during page render)
local snippetCache = {}

-- Helper function to create a cache key from parameters
local function createCacheKey(pageName, hook)
    return pageName .. "|hook=" .. hook
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
    if not hook then
        return "Error: 'hook' parameter is required"
    end
    
    -- Check cache first for previously extracted snippets
    local cacheKey = createCacheKey(pageName, hook)
    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
    
    -- First, check for hooks on the same line
    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 hookPositions = {}
        
        -- Find hook instances and count lines
        local lineNumber = 0
        for line in content:gmatch("[^\r\n]+") do
            lineNumber = lineNumber + 1
            
            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
        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
        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
    
    -- Cache the result before returning
    snippetCache[cacheKey] = result
    return result
end

return p