-- BEGIN kst/parsers/ksml/coal local VERSION = "COAL" local color = { ["WHITE"] = colors.white, ["ORANGE"] = colors.orange, ["MAGENTA"] = colors.magenta, ["LIGHTBLUE"] = colors.lightBlue, ["YELLOW"] = colors.yellow, ["LIME"] = colors.lime, ["PINK"] = colors.pink, ["GRAY"] = colors.gray, -- gray ["GREY"] = colors.gray, -- grey ["LIGHTGRAY"] = colors.lightGray, --gray ["LIGHTGREY"] = colors.lightGray, --grey ["CYAN"] = colors.cyan, ["PURPLE"] = colors.purple, ["BLUE"] = colors.blue, ["BROWN"] = colors.brown, ["GREEN"] = colors.green, ["RED"] = colors.red, ["BLACK"] = colors.black } local function wrap(word,width) -- width might not be provided local lines = {""} width = arg or term.getSize()~= 51 and term.getSize() or 50 xmin = term.getCursorPos() xmax = xmin+width for wordspace in word:gmatch("%w+%s+") do if #(lines[#lines]..wordspace)>width then lines[#lines+1] = wordspace else lines[#lines] = lines[#lines]..wordspace end end for k,v in pairs(lines) do print(v) local _,y = term.getCursorPos() term.setCursorPos(xmin,y) end end if not oldSetTColor then oldSetTColor = term.setTextColor end if not oldSetBColor then oldSetBColor = term.setBackgroundColor end local tColor = {} local bColor = {} _G.term.setTextColor = function(color) if colors[color] or type(color) == "number" then table.insert(tColor,color) end return oldSetTColor(color) end _G.term.getTextColor = function() return tColor[#tColor] or colors.black end _G.term.setBackgroundColor = function(color) if colors[color] or type(color) == "number" then table.insert(bColor,color) end return oldSetBColor end _G.term.getBackgroundColor = function() return bColor[#bColor] or colors.black end tags = { ["closing"] = { -- anything with a closing tag ["C"] = function(arg,content) --go through colors here local oldColor = term.getTextColor() if color[arg] then term.setTextColor(color[arg]) end for i=1, #content do if type(content[i]) == "string" then term.write(content[i]) elseif type(content[i]) == "table" then -- it is another tag if tags[content[i].tag] ~= nil then tags[content[i].tag](content[i].arg) elseif tags.closing[content[i].tag] ~= nil then tags.closing[content[i].tag](content[i].arg, content[i].contents) end end end term.setTextColor(oldColor) --table.remove(buffer.color,#buffer.color) -- removing the currently used color from the buffer end, ["HL"] = function(arg,content) -- Maybe Word wrapping should go here? see [P] k local ccolor = term.getBackgroundColor() term.setBackgroundColor(colors.arg) term.write(content) term.setBackgroundColor(ccolor) end, ["TITLE"] = function(arg,content) --append the content to the page title --local pTitle = --todo --this should be declared in the gui end, ["TAB"] = function(arg,content) --display this in the tab text, but not the title bar end, ["NOTAB"] = function(arg,content) --display this in the title bar, but not the tab text end, ["P"] = function(args,content) for i=1, #content do if type(content[i]) == "string" then wrap(content[i],args) elseif type(content[i]) == "table" then -- it is another tag if tags[content[i].tag] ~= nil then tags[content[i].tag](content[i].arg) elseif tags.closing[content[i]] ~= nil then tags.closing[content[i].tag](content[i].arg, content[i].contents) end end end end, ["CELL"] = function(args,content) --makes a [P] but wrap X chars from where the tag started --int between 1 and 50 (50 being the width of the window) local xArg,yArg = args:match("(%d+),(%d+)") if tonumber(x) == nil or tonumber(y) == nil then return end local x,y = term.getCursorPos() local cellWindow = window.create(term.current(),x,y,xArg,yArg) local oldCur = term.current() term.redirect(cellWindow) for i=1, #content do if type(content[i]) == "string" then wrap(content[i],xArg) elseif type(content[i]) == "table" then -- it is another tag if tags[content[i].tag] ~= nil then tags[content[i].tag](content[i].arg) elseif tags.closing[content[i]] ~= nil then tags.closing[content[i].tag](content[i].arg, content[i].contents) end end end term.redirect(term.current) end, ["CENTER"] = function(args,content) local pos = {term.getCursorPos()} if pos[1] ~= 1 then term.setCursorPos(1,pos[2]+1) end for i=1, #content do if type(content[i]) == "string" then local x,y = term.getSize() local cy = pos[2] term.setCursorPos(x/2-(#content[#content]/2),cy) print(content[i]) elseif type(content[i]) == "table" then -- it is another tag if tags[content[i].tag] ~= nil then tags[content[i].tag](content[i].arg) elseif tags.closing[content[i]] ~= nil then tags.closing[content[i].tag](content[i].arg, content[i].contents) end end end end, ["A"] = function(args,content) --link. argument is .kst URL -- need to register a button by getting starting 2 positions, and ending 2 for i = 1, #content do if type(content[i]) == "string" then term.write(content[i],args) elseif type(content[i]) == "table" then -- it is another tag if tags[content[i].tag] ~= nil then tags[content[i].tag](content[i].arg) elseif tags.closing[content[i]] ~= nil then tags.closing[content[i].tag](content[i].arg, content[i].contents) end end end end, ["D"] = function(args,content) --downloads file at URL to computer, otherwise same as [A] end, ["NFP"] = function(args,content) --don't use the paintutils api either - we need to measure its length --draw a paintutils image end, ["NFT"] = function(args,content) --draw a nitropaint image end, ["SKCH"] = function(arg,content) --draw an image in oeed's format --by no means important for release end, ["SCRIPT"] = function(arg,content) -- sandboxed lua, but our own functions that we parse --by no means important for release end, ["LIST"] = function(arg,content) -- going to have to put special stuff in parser for this -- alternatively we could just make one for list items -- this could handle things nested in it differently, which would work --by no means important for release end, ["H"] = function(arg,content) -- write in block letters (we can load NFP images for this) --by no means important for release end, ["SET"] = function(arg,content) --sets cookie "arg" equal to "content" --by no means important for release end }, ["EAT"] = function(arg) --deletes cookie "arg" end, ["FEAST"] = function() --deletes all cookies set by the site end, ["BG"] = function(arg) term.setBackgroundColor(color[arg]) end, ["BR"] = function() --linebreak local x,y = term.getCursorPos() term.setCursorPos(1,y+1) end, ["LN"] = function() --linebreak, but only if the cursor is not at the beginning local x,y = term.getCursorPos() if x ~= 1 then term.setCursorPos(1,y+1) end end, ["CR"] = function() --carraige return - move cursor x to the first spot in the container local x,y = term.getCursorPos() term.setCursorPos(1,y) end, ["LF"] = function() --move cursor down one (linefeed) local x,y = term.getCursorPos() term.setCursorPos(x,y+1) end, ["UP"] = function() --move cursor up one local x,y = term.getCursorPos() term.setCursorPos(x,y-1) end, ["SKIP"] = function(args) --move right X places local pos = {term.getCursorPos()} arg = tonumber(args) or 0 term.setCursorPos(pos[1]+arg,pos[2]) end, ["BS"] = function(args) --move left X places local pos = {term.getCursorPos()} arg = tonumber(args) or 0 term.setCursorPos(pos[1]+arg,pos[2]) end, ["TOP"] = function(args) --move cursor to top left corner of page or cell term.setCursorPos(1,1) end, ["CLEAR"] = function(args) --disregard everything before the last instance of this tag - actually don't, because containers term.clear() end, ["END"] = function(args) --disregard everything after the first instance of this tag --this function technically should never be reached return "doneloading" end, ["NSFW"] = function(args) --throw an error if the NSFW filter is on --this variable should be defined in the gui, not here local nsfw = true end, ["HR"] = function(args) --draw a horizontal bar --a bunch of gray dashes that are as wide as the container local pos = {term.getCursorPos()} if pos[1] ~= 1 then term.setCursorPos(1,pos[2]+1) end local ccolor = {term.getTextColor()} term.setTextColor(args) for i = 1,(pos[1]-1)-pos[1] do term.write("-") end term.setTextColor(ccolor) end, ["REFRESH"] = function(arg) --refresh the page in X seconds. no faster than 2? seconds end, ["REDIRECT"] = function(arg) --same as [A] but go directly to the specified page end, --afterwards, in order by importance - lists, scripts, SKCH/NFA images, big letters, forms, tables } setmetatable(tags,{ __call = function(self,tag,arg) arg = ":"..arg or "" if self[tag] ~= nil or self.closing[tag] ~= nil then return true else return "["..tag..arg.."]" end end}) local function prerequisition(siteContents) -- [END] -- This might leave a [ on the page. I can't remember if we fixed that siteContents = siteContents:sub(1,siteContents:find("%[END%]")-1) -- [ID] siteContents = siteContents:gsub("%[ID%]",os.getComputerID()) -- [HOSTNAME] - get the server's name from the DNS -- [CHECK:arg] - replace with contents of cookie "arg" -- [CLOSE] - just don't parse, close the tab end local function parser(siteContents) siteContents = prerequisition(siteContents) local siteData = {} local curPath = "" local function getfield (f) local v = siteData -- start with the table of globals if f ~= "" then for w in string.gmatch(f, "[%w_]+") do w = tonumber(w) or w v = v[w] end end if type(v) == "nil" then print(f) print(textutils.serialize(siteData)) end return v end local function setfield (f,v) local t = siteData -- start with the table of globals for w, d in string.gmatch(f, "([%w_]+)(.?)") do w = tonumber(w) or w if d == "." then -- not last field? t[w] = t[w] or {} -- create table if absent t = t[w] -- get the table else if type(t[#t]) == "string" and type(v) == "string" then t[#t] = t[#t] .. v else t[w] = v -- do the assignment end end end end local function processBlock(str) local content = {} repeat local bx,ex = str:find("%[[^ %s%]]+%]") if bx==nil then table.insert(content,str) str = "" else local tag = str:sub(bx,ex) local argLoc = tag:find(":") or #tag local t = tag:sub(2,argLoc-1) local a = tag:sub(argLoc+1, #tag-1) if type(tags.closing[t]) ~= "nil" then table.insert(content,str:sub(1,bx-1)) table.insert(content,{tag = t,arg = a,contents = {}}) str = str:sub(ex+1,#str) elseif type(tags[t]) ~= "nil" then table.insert(content,str:sub(1,bx-1)) table.insert(content,{tag = t, arg = a}) str = str:sub(ex+1, #str) elseif type(tags.closing[t:sub(2,#t)]) ~= "nil" then table.insert(content,str:sub(1,bx-1)) table.insert(content,{tag = t}) str = str:sub(ex+1, #str) else if type(content[#content]) =="string" then content[#content] = content[#content]..str:sub(1,ex) str = str:sub(ex+1,#str) else table.insert(content,str:sub(1,ex)) str = str:sub(ex+1,#str) end end end until #str == 0 return content end local function tokenise(...) local sLine = table.concat({...}," ") local tWords = {} local bQuoted = false for match in string.gmatch(sLine .. "\"", "(.-)\"") do if bquoted == false then table.insert( tWords, match ) else for m in string.gmatch( match, "[^ \t]+%s*" ) do table.insert( tWords, m ) end end end return tWords end for _,block in pairs(tokenise(siteContents)) do local contents = processBlock(block) for i = 1, #contents do local curFile = getfield(curPath) if type(contents[i]) == "string" then -- its a word not a tag if type(curFile[#curFile]) == "string" then setfield( curPath.."."..#curFile , contents[i] ) elseif type(curFile[#curFile]) == "table" then setfield( curPath.."."..(#curFile+1) , contents[i] ) elseif #curFile == 0 then setfield( curPath.."."..1 , contents[i] ) end elseif type(contents[i]) == "table" then -- its a tag if contents[i].tag:sub(1,1)=="/" then local str = curPath:sub(1,-10) curPath = str:sub(1,-(#str:gsub("%w+%.",""))+2) elseif type(tags[contents[i].tag]) ~= "nil" then setfield( curPath.."."..(#curFile+1) , contents[i]) elseif type(tags.closing[contents[i].tag]) ~= "nil" then curPath = curPath.."."..#curFile+1 setfield( curPath , contents[i] ) curPath = curPath..".".."contents" end else error("Invalid data type during parsing: " .. type(contents[i])) end end end return siteData end local function assemble(tbl) for i = 1, #tbl do if type(tbl[i]) == "string" then term.write(tbl[i]) elseif type(tbl[i]) == "table" then if tags[tbl[i].tag] then tags[tbl[i].tag](tbl[i].arg) elseif tags.closing[tbl[i].tag] then tags.closing[tbl[i].tag](tbl[i].arg,tbl[i].contents) end end end end -- END kst/parsers/ksml/coal -- BEGIN kristscape local headers = {} local function readurl(url) local addressbar = url if addressbar:find("://") == nil then addressbar = "http://" .. addressbar end addressbar = addressbar:gsub(".com",".kst") addressbar = addressbar:gsub(".org",".kst") addressbar = addressbar:gsub(".net",".kst") local protocol = string.sub(addressbar,1,string.find(addressbar,"://")-1) local name = "" if protocol == "http" then name = string.sub(url,8,string.find(url,".kst")-1) name = http.get("http://krist.ceriat.net/?a="..name,nil,headers).readAll() elseif protocol == "rdnt" elseif protocol == "knet" elseif protocol == "file" elseif protocol == "scape" name = string.sub(url,string.find(url,"://")+3,string.find(url,"/"-1)) end url = url:sub(url:find("://")) local destination = url:sub(url:find("/")+1) return addressbar, protocol, destination end --END kristscape --[[To Do list 1: Finish Tags 2: Refresh 3: Redirect 4: Cells 5: Bugfixes 6: Donuts ]]-- --[[Tags no longer in use ["COLORLINKS"] = function(arg) --true or false - if true (default) [A] will draw in cyan text end, Reason no longer in use:actually don't do this one. we can just put a [C] tag in the link's text, and have [A] add cyan to the color table ]]-- --[[ New parser example { --start of the site Contents { -- opening of a new tag tag = "C", arg = "arg", contents = { -- what is between the opening and closing tag "Hello my name is text", { -- opening of a tag tag = "BG", arg = "RED", contents = { -- only closing tags will have this "More Txt" } }, "Some more text" } --closing of a tag } --closing of the tag } ]]--