This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
KaoS's profile picture

OS help

Started by KaoS, 03 September 2012 - 06:04 AM
KaoS #1
Posted 03 September 2012 - 08:04 AM
Could you guys maybe help me out here, I am making a moving border around the file browser for my OS, it works perfectly but when you run a program the border keeps scrolling and gets in the way, I found a way around it with the running variable in the code but when I edit something it stops working, please test it and see if you can find where I am going wrong, you will need the program to launch (the OS) and my latest menu api

OS:
http://pastebin.com/2P2pjvJu
Spoiler


local running=1
local size={term.getSize()}
function KaoSOS()
local function count(input)
if type(input)~="table" then
print("incorrect input: "..tostring(input))
sleep(2)
return
end
local int=0
for a in pairs(input) do
int=int+1
end
return int
end

local function getlongest(input)
if type(input)~="table" then
print("incorrect input")
return
end
local int=0
for k,v in pairs(input) do
for a,b in pairs(v) do
if string.len(:D/>/>>int then
int=#b
end
end
end
return int
end

function addparam(params)
print('Current parameters: ')
for k,v in pairs(params) do
print(v)
end
write('enter new parameter: ')
params[(#params or 0)+1]=read()
return 'added'
end

function createnew()
term.clear()
term.setCursorPos(1,1)
write('enter new file name: ')
local new=read()
if new=='' then
print('Invalid entry')
sleep(2)
elseif fs.exists(new) then
print('File already exists')
sleep(2)
else
shell.run('edit',new)
end
end

function check(input)
return menu2.generate({{{'run',{function() running=0 shell.run(input) running=1 term.clear() end}}, {'run with parameters',{runwith,input}}},{{'edit',{function() running=0 shell.run("edit",input) running=1 term.clear() end}}, {'delete',{fs.delete,input}}}},15,3,2,size[1]-4,size[2]-2)
end

function runwith(input,params)
local params=params or {}
while menu2.generate({{{'done',{function() running=0 shell.run(input,unpack(params)) running=1 term.clear() end}},{'add param',{addparam,params}}}},15,3,2,size[1]-4,size[2]-2)=='added' do
end
end

while true do
local tall={}
if shell.dir()=='' then
tall['tdirs']={{}}
else
tall['tdirs']={{{'[..]',{shell.setDir,shell.resolve("..")}}}}
end
tall['tfiles']={{{'#new',{createnew}}}}
for k,v in pairs(fs.list(shell.dir())) do
if fs.isDir(shell.resolve(v)) then
var='tdirs'
else
var='tfiles'
end
if #tall[var][#tall[var]]==3 then
tall[var][#tall[var]+1]={}
end
tall[var][#tall[var]][#tall[var][#tall[var]]+1]={((var=='tdirs' and '['..v..']') or v),{((var=='tdirs' and shell.setDir) or check),shell.resolve(v)}}
end
for k,v in pairs(tall['tfiles']) do
tall['tdirs'][#tall['tdirs']+1]=v
end
local size={term.getSize()}
--drawborder()
running=1
menu2.generate(tall['tdirs'],15,3,2,size[1]-4,size[2]-2)
end
end



local function drawborder()
local size={term.getSize()}
for i=1,size[2] do
term.setCursorPos(2,i)
if i==1 then
write('/'..string.rep('-',size[1]-4)..'')
elseif i==size[2] then
write(''..string.rep('-',size[1]-4)..'/')
else
write('|')
term.setCursorPos(size[1]-1,i)
write('|')
end
end
end

function cyclingborder(processor,delim)
while true do
if processor<=size[1]-4 then
side='top'
break
else
processor=processor-(size[1]-2)
if processor<=size[2] then
side='right'
break
else
processor=processor-size[2]
if processor<=size[1]-4 then
side='bottom'
break
else
processor=processor-(size[1]-2)
if processor<=size[2] then
side='left'
break
else
processor=processor-size[2]
end
end
end
end
end
term.setCursorPos((side=='top' and processor+2) or (side=='bottom' and size[1]-processor-1) or (side=='left' and 2) or (side=='right' and size[1]-1),(side=='top' and 1) or (side=='bottom' and size[2]) or (side=='left' and size[2]-processor) or (side=='right' and processor))
write(delim or '*')
end



co1=coroutine.create(function() local a=0 while true do a=a+1 drawborder() cyclingborder(a) cyclingborder(a+1) cyclingborder(a+2) cyclingborder(a+3) sleep(0.1) end end)
co2=coroutine.create(KaoSOS)
term.clear()
os.queueEvent('start')
while true do
events={os.pullEvent()}
coroutine.resume(co2,unpack(events))
if running==1 then coroutine.resume(co1,unpack(events)) end
end

Menu API:
http://pastebin.com/X9cC2MS3
Spoiler


--[SYNTAX:
apiname.generate(table, separator, x1, y1, x2, y2, delim1, delim2)

an example of its use can be found at http://pastebin.com/LTBY9xcW

table - a table of all the options selectable and what to do if each option is selected
the format of table is:
table[y][x][1]='displayed option'
table[y][x][2]=another table where the first value is the function to call (exclude the brackets after it and do not make it a string, it is a function) and all values after it are passed to the function as arguments

separator - the x distance between the first character of each option (default is 10)

x1,y1,x2 and y2 are used to generate a box in which the menu is generated
x1 and y1 are the co-ordinates of the top left corner
x2 and y2 are the co-ordinates of the bottom right corner

delim1 and 2 are the character to display before and after the selected option (default is '>' and '<')
]

function generate(input,dist,offsetx,offsety,limx,limy,delim1,delim2)
--[Required functions]
local function pullfirst(input)
local first=input[1]
local temp={}
for k,v in pairs(input) do
if k~=1 then
temp[#temp+1]=v
end
end
return first,temp
end

local function cleararea(...)
local pos={term.getCursorPos()}
local args={...}
for y=args[2], args[2]+args[4]-1 do
term.setCursorPos(args[1],y)
write(string.rep(' ',args[3]-args[1]+1))
end
term.setCursorPos(pos[1],pos[2])
end

--[Gathering initial information and declaring variables]
local scrolledx=0
local scrolledy=0
local selectedx=1
local selectedy=1
local lastx=0
dist=dist or 10
local columnmaxlen={}
local maxlen=0
for b,y in pairs(input) do
for a,x in pairs(y) do
if columnmaxlen[a] or 0<string.len(x[1]) then
columnmaxlen[a]=string.len(x[1])
end
end
end
for a,b in pairs(columnmaxlen) do
if string.len(:P/>/>>maxlen then
maxlen=string.len(:)/>/>
end
end

while true do
--[Render the menu]
cleararea(offsetx,offsety,limx,limy)
lastx=0
for b,y in pairs(input) do
for a,x in pairs(y) do
currentlen=dist*(a-scrolledx-1)+columnmaxlen[a]

if b>scrolledy and b<=limy-offsety+scrolledy+1 and a>scrolledx and currentlen<limx-offsetx+1 then
lastx=(lastx<=a and a) or lastx
if a==selectedx and b==selectedy then
term.setCursorPos(offsetx+a*dist-scrolledx*dist-dist,offsety+b-1-scrolledy)
write((delim1 or '>')..x[1]..(delim2 or delim1 or '<'))
else
term.setCursorPos(offsetx+1+a*dist-scrolledx*dist-dist,offsety+b-1-scrolledy)
write(x[1])
end
end
end
end
print('')

--[Detect keypresses for interface and adjust variables accordingly]
while true do
local event,key=os.pullEvent('key')
if key==203 and selectedx>1 then
selectedx=selectedx-1
if selectedx<=scrolledx then
scrolledx=scrolledx-1
end
break
elseif key==205 and selectedx<#input[selectedy] then
selectedx=selectedx+1
if selectedx>lastx then
scrolledx=scrolledx+1
end
break
elseif key==200 and selectedy>1 then
selectedy=selectedy-1
if selectedy<=scrolledy then
scrolledy=scrolledy-1
end
break
elseif key==208 and selectedy<#input then
selectedy=selectedy+1
if selectedy>limy-offsety+scrolledy+1 then
scrolledy=scrolledy+1
end
break
elseif key==28 then
local cmd={pullfirst(input[selectedy][selectedx][2])}
return cmd[1](unpack(cmd[2]))
end
end
if selectedx>#input[selectedy] then
selectedx=#input[selectedy]
end
end
end

EDIT: in case that was unclear: the border stops generating after you edit a file from the browser
Edited on 04 September 2012 - 09:36 AM
KaoS #2
Posted 03 September 2012 - 04:03 PM
'cmon guys, no ideas?
BigSHinyToys #3
Posted 04 September 2012 - 12:04 PM
This is the problem line

co1=coroutine.create(function() local a=0 while true do a=a+1 drawborder() cyclingborder(a) cyclingborder(a+1) cyclingborder(a+2) cyclingborder(a+3) sleep(0.1) end end)

the sleep(0.1) is causing the program to not run correctly. This is because it is waiting for a specific timer to go off that never will. because you haven't given it that event .

You need a custom sleep you can manually unfreeze.

This should do it.
http://pastebin.com/BhWtD800

as you can see I copied sleep from the BIOS added another way to break it other than the timer event. then i make that event happen after the shell.run() has ended with os.qeueEvent()
KaoS #4
Posted 04 September 2012 - 12:15 PM
I see!!! thanks man, couldn't I just queue the timer event on resume?
BigSHinyToys #5
Posted 04 September 2012 - 12:21 PM
you need to call it only when you have lost the previous timer event. I mean when it happened but your program was not waiting for it.
calling it all the time will cause a lot of lag not recommended.
KaoS #6
Posted 04 September 2012 - 12:36 PM
yeah I mean when I set running to 1 I should queue it once
BigSHinyToys #7
Posted 04 September 2012 - 12:43 PM
yes that is when my misunderstanding sorry
KaoS #8
Posted 04 September 2012 - 12:44 PM
thanks for the help, you are truly a life saver
KaoS #9
Posted 04 September 2012 - 01:44 PM
thought I'd add that os.queueEvent('timer') did not solve the issue, had to use:


running=0 local events={os.pullEvent('timer')} shell.run("edit",input) os.queueEvent(unpack(events)) running=1
because the table reference of the second parameter must be the correct one (the queueEvent function returns an empty table because that generates a unique reference number that you can then use to make sure you get the right one)


if {}=={} then
print('true')
end
will never print true
BigSHinyToys #10
Posted 04 September 2012 - 01:52 PM
and now you know why I made a copy of the sleep function with a way to manually unstuck the loop.
os.queueEvent('timer') will not work but copying the events you did works too. I used that method to keep the returned data from turtle.forward() so when i restart my mining program it doesn't hang.
KaoS #11
Posted 04 September 2012 - 01:55 PM
indeed, I am going to take a more in depth look at pausing and resuming different threads without issue as well as the native commands as these may prove incredibly useful