pattern info with clickable links

For scripts to aid with computation or simulation in cellular automata.
Post Reply
User avatar
Andrew
Moderator
Posts: 935
Joined: June 2nd, 2009, 2:08 am
Location: Melbourne, Australia
Contact:

pattern info with clickable links

Post by Andrew » October 4th, 2023, 5:13 pm

Here's a Lua script that displays the current pattern's comments in Golly's help window, but with clickable links to any http sites or pattern references, so maybe a nice alternative to View > Pattern Info. For best results, save the script as pattern-info.lua and use Preferences > Keyboard to create a keyboard shortcut (eg. alt-I) to run it.

Code: Select all

-- Displays the current pattern's comments in the help window,
-- with clickable links to http sites and pattern files.
-- Author: Andrew Trevorrow (andrew@trevorrow.com)

local g = golly()

--------------------------------------------------------------------------------

function ModifyComments(comments)
    comments = comments:gsub("\n", "<br>\n")
    comments = "\n"..comments -- simplifies the following changes
    
    comments = comments:gsub("\n#N ", "\nName: ", 1)
    comments = comments:gsub("\n#O ", "\nAuthor: ", 1)
    
    -- remove "#C " or "#D " or "# " from start of each line
    -- (#D is used in .mcl files in Patterns/Generations/)
    comments = comments:gsub("\n#[CD] ", "\n")
    comments = comments:gsub("\n# ", "\n")
    -- fix lines with only #C/#D/# (eg. Turmites/AlienCounter.rle)
    comments = comments:gsub("\n#[CD]<br>", "\n<p>\n")
    comments = comments:gsub("\n#<br>", "\n<p>\n")
    
    -- replace space(s) at start of each line with non-breaking spaces
    comments = comments:gsub("\n  ", "\n&nbsp;&nbsp;&nbsp;")
    comments = comments:gsub("\n ", "\n&nbsp;&nbsp;&nbsp;&nbsp;")

    -- this makes tabular info less ugly (esp in osc stamp collection)
    comments = comments:gsub("  ", "\n&nbsp;&nbsp;&nbsp;")
    
    -- escape % for later use as replacement string
    comments = comments:gsub("%%", "%%%%")
    
    -- go thru comments line by line to convert http links and pattern links
    local newlines = {}
    local nextline = comments:gmatch("(.-)\n")
    while true do
        local line = nextline()
        if not line then break end
        local prefix, link, suffix = line:match("^(.*)(http[^ <%),]+)(.+)$")
        if link then
            line = prefix.."<a href=\""..link.."\">"..link.."</a>"..suffix
        else
            prefix, link, suffix = line:match("^(.*)(Patterns/[^ <%)]+)(.+)$")
            if link then
                line = prefix.."<a href=\"open:"..link.."\">"..link.."</a>"..suffix
            end
        end
        newlines[#newlines+1] = line
    end
    
    return table.concat(newlines)
end

--------------------------------------------------------------------------------

function Main()
    local pathname = g.getpath()
    if pathname == "" then g.exit("No current pattern.") end
    
    local comments = g.getinfo()
    if comments == "" then g.exit("No comments in current pattern.") end
    comments = ModifyComments(comments)
    
    -- extract the directory path and file name
    local pathsep = g.getdir("app"):sub(-1)
    local dirpath = pathname:sub(1, pathname:find(pathsep.."[^"..pathsep.."/]*$"))
    local filename = pathname:sub(#dirpath+1)

    -- create a temporary html file
    local htmlname = g.getdir("temp")..filename..".html"
    local f = io.open(htmlname, "w")
    if f then
        local htmldata =
[[
<html>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Pattern Info for FILENAME</title>
<body bgcolor="#FFFFCE">
<p>COMMENTS</p>
</body>
</html>
]]
        htmldata = htmldata:gsub("FILENAME", filename, 1)
        htmldata = htmldata:gsub("COMMENTS", comments, 1)
        f:write(htmldata)
        f:close()
    else
        g.exit("Failed to create temporary html file!")
    end
    g.open(htmlname)
end

--------------------------------------------------------------------------------

Main()
The script is quite handy for finding bad links. For example, if you load the loafer-gun in Patterns/HashLife/Constructions/ and then run the above script you'll see links to two pattern files. The 1st works fine but the 2nd fails because "blockic" and "blockish" need to be swapped.

Similarly, if you load the oscillator-stamp-collection and display its comments you'll find a link to http://www.argentum.freeserve.co.uk/lex_home.htm which no longer exists.

EDIT: I've fixed the above bad links for the next Golly release. Also corrected a few minor problems in the script.

EDIT #2: Modified the script so any Unicode characters will be displayed correctly (assuming the file is UTF-8 encoded).
Use Glu to explore CA rules on non-periodic tilings: DominoLife and HatLife

User avatar
Andrew
Moderator
Posts: 935
Joined: June 2nd, 2009, 2:08 am
Location: Melbourne, Australia
Contact:

Re: pattern info with clickable links

Post by Andrew » October 4th, 2023, 11:49 pm

Actually, if the aim is to find broken links, here's a more useful script:

Code: Select all

-- Finds all of Golly's supplied pattern files that have comments with http/pattern links
-- and displays the results in the help window.  Useful for finding broken links.
-- By Andrew Trevorrow (andrew@trevorrow.com).

local g = golly()

local appdir = g.getdir("app")
local pathsep = appdir:sub(-1)
local pattdir = appdir.."Patterns"..pathsep

--------------------------------------------------------------------------------

function Traverse(dir, level, links)
    -- recursively traverse given directory
    local files = g.getfiles(dir)
    if files == nil then
        g.exit("The given directory does not exist:\n"..dir)
    elseif #files == 0 then
        return links
    else
        table.sort(files)
    end
    local tab = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"
    local indent = ""
    for i = 1, level do indent = indent..tab end
    for _, name in ipairs(files) do
        if name:sub(1,1) == "." then
            -- ignore hidden file
        elseif name:sub(-1) == pathsep then
            -- name is a subdirectory
            links = Traverse(dir..name, level+1, links..indent.."<b>"..name.."</b><br>\n")
        else
            -- name is a file so load it and check if it has any comments
            local fullname = dir..name
            g.open(fullname)
            local comments = g.getinfo()
            if #comments > 0 and (comments:find("http") or comments:find("Patterns/")) then
                -- create an "open:" link to this file
                links = links..indent.."<a href=\"open:"..fullname.."\"><b>"..name.."</b></a><br>\n"
                links = links.."<br>"
                if comments:find("http") then
                    -- add http links
                    local nexthttplink = comments:gmatch("(http[^ <%)\n]+)")
                    while true do
                        local httplink = nexthttplink()
                        if not httplink then break end
                        links = links..indent..tab.."<a href=\""..httplink.."\">"..httplink.."</a><br>\n"
                    end
                end
                if comments:find("Patterns/") then
                    -- add open pattern links
                    local nextpattlink = comments:gmatch("(Patterns/[^ <%)\n]+)")
                    while true do
                        local pattlink = nextpattlink()
                        if not pattlink then break end
                        links = links..indent..tab.."<a href=\"open:"..pattlink.."\">"..pattlink.."</a><br>\n"
                    end
                end
                links = links.."<br>"
            end
        end
    end
    return links
end

--------------------------------------------------------------------------------

function ShowLinks(links)
    -- create a html file with given links and show in help window
    local htmlheader =
        "<html><title>Patterns with links</title>\n"..
        "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n"..
        "<body bgcolor=\"#FFFFCE\"><p>\n"
    local htmlfooter = "</body></html>"

    -- create the html data in a temporary file
    local htmlfile = g.getdir("temp").."links.html"
    local f = io.open(htmlfile,"w")
    if not f then
        g.exit("Failed to create file:\n"..htmlfile)
    end
    f:write(htmlheader)
    f:write("<b>"..pattdir.."</b><br>\n")
    f:write(links)
    f:write(htmlfooter)
    f:close()
    g.open(htmlfile)
    g.show("")
end

--------------------------------------------------------------------------------

g.addlayer()
ShowLinks(Traverse(pattdir, 1, ""))
g.dellayer()
Use Glu to explore CA rules on non-periodic tilings: DominoLife and HatLife

Post Reply