local Y=require("yaru.core") local gfx=require("yaru.gfx") local vgpu=require("yaru.vgpu") local ui=require("yaru.ui") local computer=require("computer") local process=require("process") local term=require("term") local thread=require("thread") local M={} local INPUT={key_down=true,key_up=true,touch=true,drag=true,drop=true,scroll=true,clipboard=true} local counter=0 function M.open(cmd,cwd) counter=counter+1 local id=counter local kb,scr="yaru-term-kb-"..id,"yaru-term-screen-"..id local cw,ch=80,24 local vg=vgpu.new(cw,ch,{screen=scr,address="yaru-term-gpu-"..id}) local win win=Y.newWindow{app="terminal",title="Terminal",w=cw,h=ch+1,minW=30,minH=6,termId=id} vg.onChange=function() Y.redraw(win) computer.pushSignal("yaru_redraw") end local window=term.internal.open(0,0,cw,ch) term.bind(vg.proxy,window) window.keyboard=kb window.fullscreen=false local function resize(w,h) w,h=math.max(10,w),math.max(3,h) if w==vg.w and h==vg.h then return end vg.resize(w,h) window.width,window.height=w,h if window.x>w then window.x=w end if window.y>h then window.y=h end computer.pushSignal("screen_resized",scr,w,h) end vg.onResize=function(w,h) win.w,win.h=w,h+1 resize(w,h) Y.redraw() return true end function win.resized(w)resize(w.w,w.h-1)end local t=thread.create(function() local data=process.info().data data.window=window data.yaruTerm=id data.componentOverride={gpu=vg.proxy} local orig=data.pull data.pull=function(tbl,timeout) local sig=table.pack(orig(tbl,timeout)) local name=sig[1] if INPUT[name]then if sig[2]~=kb and sig[2]~=scr then return end elseif name=="yaru_redraw"then return elseif name=="interrupted"then if not(Y.focus==win)then return end end return table.unpack(sig,1,sig.n) end os.setenv("YARU_TERM",tostring(id)) os.setenv("TERM","term-256color") if cwd then os.setenv("YARU_CWD",cwd)end local shell=require("shell") if cmd then io.write("\27[32m$ \27[37m"..cmd.."\n") local ok,err=shell.execute(cmd) if not ok and err then io.stderr:write(tostring(err).."\n")end io.write("\n\27[33m[process finished — press any key to close]\27[37m") require("event").pull("key_down",kb) else local sh=shell.getShell() sh() end end) win.thread=t function win.draw(w,cw2,ch2) if vg.w~=cw2 or vg.h~=ch2 then resize(cw2,ch2)end local SW,SH=Y.size() if vg.scroll>0 and not vg.noscroll and Y.focus==w and not Y.overlay and w.x>=1 and w.x+w.w-1<=SW and w.y+w.h-1<=SH then gfx.scrollHint(w.x,w.y+1,vg.w,vg.h,vg.scroll) end vg.scroll,vg.noscroll=0,false vg.changed=false gfx.blit(vg.grid,vg.w,vg.h,1,1) end function win.focusIn()window.blink=true end function win.blur()window.blink=false end local function fwd(name,...)computer.pushSignal(name,...)end function win.key(w,char,code) local K=Y.K if Y.mods.ctrl()and Y.mods.shift()then if code==K.v then fwd("clipboard",kb,Y.clipboard,"")return end if code==0x2E then return end if code==K.t then Y.launch("terminal")return end end fwd("key_down",kb,char,code,"") end function win.keyUp(w,char,code)fwd("key_up",kb,char,code,"")end function win.paste(w,s)fwd("clipboard",kb,s,"")end function win.touch(w,x,y,btn,kind) if y<1 then return end fwd(kind,scr,x,y,btn,"") end function win.scroll(w,x,y,dir)fwd("scroll",scr,x,y,dir,"")end function win.cleanup(w) if t:status()~="dead"then pcall(t.kill,t)end end win.tickInterval=1 local pdata=getmetatable(t).process.data function win.tick(w) if t:status()=="dead"then return Y.closeWin(w,true)end local vars=rawget(pdata,"vars")or{} local host=vars.HOSTNAME or"openos" local pwd=(vars.PWD or"/home"):gsub("^/home","~") local title=(vars.USER or"user").."@"..host..": "..pwd if title~=w.title then w.title=title;Y.redraw(w)end end end return M