Module:User:DTLHS/etymtree

From Wiktionary, the free dictionary
Jump to navigation Jump to search

This is a private module sandbox of DTLHS, for his own experimentation. Items in this module may be added and removed at DTLHS's discretion; do not rely on this module's stability.


require "math"

local p = {}

function getLevel(line)
    local result = 1
    while string.sub(line, result, result) == "*" do
        result = result + 1
    end
    return result - 1
end

function getLangname(line, level)
    local result = string.sub(line, level + 2)
    return string.sub(result, 1, (result:find(':')) - 1)
end

function getWord(line, level, langname)
    return string.sub(line, level + 4 + string.len(langname))
end

function getTree(sourcepage)
    -- load entire tree
    local result = {}
    local i = 1
    
    local treeName = "Template:etymtree/" .. sourcepage
    local tree = "\n" .. mw.title.new( treeName ):getContent() .. "\n"

    for line in tree:gmatch("[^\n]+") do
        if string.sub(line, 1, 1) == "*" then
            local level = getLevel(line)
            local langname = getLangname(line, level)
            local word = getWord(line, level, langname)
            result[i] = {level, langname, word, line}
            i = i + 1
        end
    end

    return result
end

function lineMatch(tree, i, target_langcode, target_word)
    local t = "{{l|" .. target_langcode .. "|" .. target_word
    local line = tree[i][3]
    if string.find(line, t) ~= nil then
        return true
    end
    return false
end

function getIndex(tree, target_langcode, target_word)
    for i, v in ipairs(tree) do
        local l = lineMatch(tree, i, target_langcode, target_word)
        if l == true then
            return i
        end
    end
    return nil
end

function getParent(tree, i)
    local data = tree[i]
    local level = data[1]
    local j = i - 1
    while true do
		if tree[j] == nil then
			return tree[j]
		end

        if tree[j][1] == (level - 1) then
            return j
        end
        j = j - 1

    end
end

function getParents(tree, i)
	local result = {}
	local parent = getParent(tree, i)
	while parent ~= nil do
		table.insert(result, parent)
		parent = getParent(tree, parent)
	end
	return result
end

function getChildren(tree, i)
	local result = {}
	local j = i + 1
	local level = tree[i][1]

	while (tree[j] ~= nil) and (tree[j][1] > level) do
		table.insert(result, j)
		j = j + 1
	end
	return result
end

function getSisters(tree, i)
	local result = {}
	local level = tree[i][1]
	local langname = tree[i][2]
    local parent = getParent(tree, i)
    local children = getChildren(tree, parent)
	for i, v in ipairs(children) do
        if (tree[v][1] == level) then
    		table.insert(result, v)
        end
	end
	return result
end

function getDerivedTerms(tree, i)
	local result = {}
	local children = getChildren(tree, i)
	local parent_langname = tree[i][2]
	for i, v in ipairs(children) do
		if (tree[v][2] == parent_langname) then
			table.insert(result, v)
		end
	end
	return result
end

function getRelatedTerms(tree, i)
	local result = {}
	local sisters = getSisters(tree, i)
	local langname = tree[i][2]
	for j, v in ipairs(sisters) do
		if (v ~= i) and (tree[v][2] == langname) then
			table.insert(result, v)
		end
	end
	return result
end

function getCognates(tree, i)
	local result = {}
	local sisters = getSisters(tree, i)
	local langname = tree[i][2]
	for j, v in ipairs(sisters) do
		if (v ~= i) and (tree[v][2] ~= langname) then
			table.insert(result, v)
		end
	end
	return result
end

function makeWikiTable(t, title, columns)
	local l = tablelength(t)
	local n = math.ceil(l / columns)
	local width = 96 / columns

	local result = '<div class="NavFrame">\n'
	result = result .. '<div class="NavHead" style="text-align:left">' .. title .. '</div>'
	result = result .. '\n<div class="NavContent">'
	result = result .. '<div style="width:auto;margin:0px;overflow:auto;">\n{| border=0  width=100%\n|-\n| bgcolor="#F8F8FF" valign=top align=left|'

	for i, v in ipairs(t) do

		result = result .. "\n" .. v
		-- if (math.mod(i, n) == 0) and (i ~= (n + 1)) and (n ~= 1) then
		--	result = result .. '\n| width=1% |\n| bgcolor="#F8F8FF" valign=top align=left width=' .. tostring(width) .. '%|'
		-- end

	end
	return result .. "\n" .. "|}</div></div></div>"
end

function formattedEtymology(tree, i)
	local result = ""
	local parents = getParents(tree, i)
	for j, v in ipairs(parents) do
		langname = tree[v][2]
		word = tree[v][3]
        if word ~= (nil or "" or " ") then
    		result = result .. " from " .. langname .. " " .. word .. ","
        end
        if word == (nil or "" or " ") then
            result = result .. " from " .. langname .. ","
        end
	end
	result = string.sub(result, 2, -2)
	return string.upper(string.sub(result, 1, 1)) .. string.sub(result, 2) .. '.'
end

function formattedDescendants(tree, i)
	local result = {}
	local base_level = tree[i][1]
	local children = getChildren(tree, i)
	for i, v in ipairs(children) do
        if tree[v][3] ~= (nil or "" or " ") then
    		child = tree[v][4]
	    	child = string.sub(child, base_level + 1)
		    table.insert(result, child)
        end
	end
	return makeWikiTable(result, "Descendants", 1)
end

function formattedDerivedTerms(tree, i)
	local result = {}
	local base_level = tree[i][1]
	local derived_terms = getDerivedTerms(tree, i)
	for i, v in ipairs(derived_terms) do
        if tree[v][3] ~= (nil or "" or " ") then
		    derived = tree[v][4]
		    derived = string.sub(derived, base_level + 1)
		    table.insert(result, derived)
        end
	end
	return makeWikiTable(result, "Derived terms", 1)
end

function formattedRelatedTerms(tree, i)
	local result = {}
	local base_level = tree[i][1]
	local related_terms = getRelatedTerms(tree, i)
	for i, v in ipairs(related_terms) do
        if tree[v][3] ~= (nil or "" or " ") then
    		related = tree[v][4]
	    	related = string.sub(related, base_level)
		    table.insert(result, related)
        end
	end
	return makeWikiTable(result, "Related terms", 1)
end

function formattedCognates(tree, i)
	local result = {}
	local base_level = tree[i][1]
	local cognates = getCognates(tree, i)
	for i, v in ipairs(cognates) do
        if tree[v][3] ~= (nil or "" or " ") then
    		cognate = tree[v][4]
	    	cognate = string.sub(cognate, base_level)
		    table.insert(result, cognate)
        end
	end
	return makeWikiTable(result, "Cognates", 1)
end

function tablelength(T)
	local count = 0
	for _ in pairs(T) do count = count + 1 end
	return count
end

function p.main(frame)
    local args = frame:getParent().args
    
    local sourcepage = args[1]
    local langcode = args[2]
    local term = args[3]
        
    local tree = getTree(sourcepage)
    local i = getIndex(tree, langcode, term)
    
    local etymology = formattedEtymology(tree, i)
    local descendants = formattedDescendants(tree, i)
    local derived_terms = formattedDerivedTerms(tree, i)
    local related_terms = formattedRelatedTerms(tree, i)
    local cognates = formattedCognates(tree, i)
    
    return frame:preprocess(etymology .. "\n" .. descendants .. "\n" .. derived_terms .. "\n" .. related_terms .. "\n" .. cognates)
end

return p