mirror of
https://github.com/kepler155c/opus
synced 2025-01-11 16:20:26 +00:00
format and installer branches
This commit is contained in:
parent
1eea0d7cd8
commit
5a32fe208e
1
startup
1
startup
@ -93,3 +93,4 @@ if bootOptions[bootOption].args then
|
||||
else
|
||||
print(bootOptions[bootOption].prompt)
|
||||
end
|
||||
|
||||
|
151
sys/apis/entry.lua
Normal file
151
sys/apis/entry.lua
Normal file
@ -0,0 +1,151 @@
|
||||
local class = require('class')
|
||||
|
||||
local os = _G.os
|
||||
|
||||
local Entry = class()
|
||||
|
||||
function Entry:init(args)
|
||||
self.pos = 0
|
||||
self.scroll = 0
|
||||
self.value = ''
|
||||
self.width = args.width
|
||||
self.limit = 1024
|
||||
end
|
||||
|
||||
function Entry:reset()
|
||||
self.pos = 0
|
||||
self.scroll = 0
|
||||
self.value = ''
|
||||
end
|
||||
|
||||
local function nextWord(line, cx)
|
||||
local result = { line:find("(%w+)", cx) }
|
||||
if #result > 1 and result[2] > cx then
|
||||
return result[2] + 1
|
||||
elseif #result > 0 and result[1] == cx then
|
||||
result = { line:find("(%w+)", result[2] + 1) }
|
||||
if #result > 0 then
|
||||
return result[1]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Entry:updateScroll()
|
||||
if self.pos - self.scroll > self.width then
|
||||
self.scroll = self.pos - (self.width)
|
||||
elseif self.pos < self.scroll then
|
||||
self.scroll = self.pos
|
||||
end
|
||||
end
|
||||
|
||||
function Entry:process(ie)
|
||||
local updated = false
|
||||
|
||||
if ie.code == 'left' then
|
||||
if self.pos > 0 then
|
||||
self.pos = math.max(self.pos - 1, 0)
|
||||
updated = true
|
||||
end
|
||||
|
||||
elseif ie.code == 'right' then
|
||||
local input = tostring(self.value)
|
||||
if self.pos < #input then
|
||||
self.pos = math.min(self.pos + 1, #input)
|
||||
updated = true
|
||||
end
|
||||
|
||||
elseif ie.code == 'home' then
|
||||
if self.pos ~= 0 then
|
||||
self.pos = 0
|
||||
updated = true
|
||||
end
|
||||
|
||||
elseif ie.code == 'end' then
|
||||
if self.pos ~= #tostring(self.value) then
|
||||
self.pos = #tostring(self.value)
|
||||
updated = true
|
||||
end
|
||||
|
||||
elseif ie.code == 'backspace' then
|
||||
if self.pos > 0 then
|
||||
local input = tostring(self.value)
|
||||
self.value = input:sub(1, self.pos - 1) .. input:sub(self.pos + 1)
|
||||
self.pos = self.pos - 1
|
||||
updated = true
|
||||
end
|
||||
|
||||
elseif ie.code == 'control-right' then
|
||||
local nx = nextWord(self.value, self.pos + 1)
|
||||
if nx then
|
||||
self.pos = math.min(nx - 1, #self.value)
|
||||
elseif self.pos < #self.value then
|
||||
self.pos = #self.value
|
||||
end
|
||||
updated = true
|
||||
|
||||
elseif ie.code == 'control-left' then
|
||||
if self.pos ~= 0 then
|
||||
local lx = 1
|
||||
while true do
|
||||
local nx = nextWord(self.value, lx)
|
||||
if not nx or nx >= self.pos then
|
||||
break
|
||||
end
|
||||
lx = nx
|
||||
end
|
||||
if not lx then
|
||||
self.pos = 0
|
||||
else
|
||||
self.pos = lx - 1
|
||||
end
|
||||
updated = true
|
||||
end
|
||||
|
||||
elseif ie.code == 'delete' then
|
||||
local input = tostring(self.value)
|
||||
if self.pos < #input then
|
||||
self.value = input:sub(1, self.pos) .. input:sub(self.pos + 2)
|
||||
self.update = true
|
||||
updated = true
|
||||
end
|
||||
|
||||
elseif ie.code == 'char' then
|
||||
local input = tostring(self.value)
|
||||
if #input < self.limit then
|
||||
self.value = input:sub(1, self.pos) .. ie.ch .. input:sub(self.pos + 1)
|
||||
self.pos = self.pos + 1
|
||||
self.update = true
|
||||
updated = true
|
||||
end
|
||||
|
||||
elseif ie.code == 'copy' then
|
||||
os.queueEvent('clipboard_copy', self.value)
|
||||
|
||||
elseif ie.code == 'paste' then
|
||||
local input = tostring(self.value)
|
||||
if #input + #ie.text > self.limit then
|
||||
ie.text = ie.text:sub(1, self.limit-#input)
|
||||
end
|
||||
self.value = input:sub(1, self.pos) .. ie.text .. input:sub(self.pos + 1)
|
||||
self.pos = self.pos + #ie.text
|
||||
updated = true
|
||||
|
||||
elseif ie.code == 'mouse_click' then
|
||||
-- need starting x passed in instead of hardcoding 3
|
||||
self.pos = math.min(ie.x - 3 + self.scroll, #self.value)
|
||||
updated = true
|
||||
|
||||
elseif ie.code == 'mouse_rightclick' then
|
||||
local input = tostring(self.value)
|
||||
if #input > 0 then
|
||||
self:reset()
|
||||
updated = true
|
||||
end
|
||||
end
|
||||
|
||||
self:updateScroll()
|
||||
|
||||
return updated
|
||||
end
|
||||
|
||||
return Entry
|
@ -24,15 +24,22 @@ end
|
||||
function input:toCode(ch, code)
|
||||
local result = { }
|
||||
|
||||
if not ch and code == 1 then
|
||||
ch = 'escape'
|
||||
end
|
||||
|
||||
if keyboard.state[keys.leftCtrl] or keyboard.state[keys.rightCtrl] or
|
||||
code == keys.leftCtrl or code == keys.rightCtrl then
|
||||
table.insert(result, 'control')
|
||||
end
|
||||
|
||||
if keyboard.state[keys.leftAlt] or keyboard.state[keys.rightAlt] or
|
||||
code == keys.leftAlt or code == keys.rightAlt then
|
||||
table.insert(result, 'alt')
|
||||
end
|
||||
-- the key-up event for alt keys is not generated if the minecraft
|
||||
-- window loses focus
|
||||
--
|
||||
-- if keyboard.state[keys.leftAlt] or keyboard.state[keys.rightAlt] or
|
||||
-- code == keys.leftAlt or code == keys.rightAlt then
|
||||
-- table.insert(result, 'alt')
|
||||
-- end
|
||||
|
||||
if keyboard.state[keys.leftShift] or keyboard.state[keys.rightShift] or
|
||||
code == keys.leftShift or code == keys.rightShift then
|
||||
@ -65,13 +72,13 @@ function input:translate(event, code, p1, p2)
|
||||
if p1 then -- key is held down
|
||||
if not modifiers[code] then
|
||||
self.fired = true
|
||||
return input:toCode(keys.getName(code), code)
|
||||
return { code = input:toCode(keys.getName(code), code) }
|
||||
end
|
||||
else
|
||||
self.state[code] = true
|
||||
if self:modifierPressed() and not modifiers[code] or code == 57 then
|
||||
self.fired = true
|
||||
return input:toCode(keys.getName(code), code)
|
||||
return { code = input:toCode(keys.getName(code), code) }
|
||||
else
|
||||
self.fired = false
|
||||
end
|
||||
@ -80,7 +87,7 @@ function input:translate(event, code, p1, p2)
|
||||
elseif event == 'char' then
|
||||
if not self:modifierPressed() then
|
||||
self.fired = true
|
||||
return input:toCode(code)
|
||||
return { code = event, ch = input:toCode(code) }
|
||||
end
|
||||
|
||||
elseif event == 'key_up' then
|
||||
@ -89,16 +96,18 @@ function input:translate(event, code, p1, p2)
|
||||
self.fired = true
|
||||
local ch = input:toCode(keys.getName(code), code)
|
||||
self.state[code] = nil
|
||||
return ch
|
||||
return { code = ch }
|
||||
end
|
||||
end
|
||||
self.state[code] = nil
|
||||
|
||||
elseif event == 'paste' then
|
||||
--self.state[keys.leftCtrl] = nil
|
||||
--self.state[keys.rightCtrl] = nil
|
||||
self.fired = true
|
||||
return input:toCode('paste', 255)
|
||||
if keyboard.state[keys.leftShift] or keyboard.state[keys.rightShift] then
|
||||
return { code = 'shift-paste', text = code }
|
||||
else
|
||||
return { code = 'paste', text = code }
|
||||
end
|
||||
|
||||
elseif event == 'mouse_click' then
|
||||
local buttons = { 'mouse_click', 'mouse_rightclick' }
|
||||
@ -108,7 +117,12 @@ function input:translate(event, code, p1, p2)
|
||||
elseif event == 'mouse_drag' then
|
||||
self.mfired = true
|
||||
self.fired = true
|
||||
return input:toCode('mouse_drag', 255)
|
||||
return {
|
||||
code = input:toCode('mouse_drag', 255),
|
||||
button = code,
|
||||
x = p1,
|
||||
y = p2,
|
||||
}
|
||||
|
||||
elseif event == 'mouse_up' then
|
||||
if not self.mfired then
|
||||
@ -130,15 +144,27 @@ function input:translate(event, code, p1, p2)
|
||||
self.mfired = input:toCode(self.mch, 255)
|
||||
end
|
||||
self.fired = true
|
||||
return self.mfired
|
||||
return {
|
||||
code = self.mfired,
|
||||
button = code,
|
||||
x = p1,
|
||||
y = p2,
|
||||
}
|
||||
|
||||
elseif event == "mouse_scroll" then
|
||||
local directions = {
|
||||
[ -1 ] = 'scrollUp',
|
||||
[ 1 ] = 'scrollDown'
|
||||
[ -1 ] = 'scroll_up',
|
||||
[ 1 ] = 'scroll_down'
|
||||
}
|
||||
self.fired = true
|
||||
return input:toCode(directions[code], 255)
|
||||
return {
|
||||
code = input:toCode(directions[code], 255),
|
||||
x = p1,
|
||||
y = p2,
|
||||
}
|
||||
|
||||
elseif event == 'terminate' then
|
||||
return { code = 'terminate' }
|
||||
end
|
||||
end
|
||||
|
||||
@ -146,7 +172,7 @@ function input:test()
|
||||
while true do
|
||||
local ch = self:translate(os.pullEvent())
|
||||
if ch then
|
||||
print('GOT: ' .. tostring(ch))
|
||||
Util.print(ch)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -9,23 +9,8 @@
|
||||
This work is under MIT-LICENSE
|
||||
Copyright (c) 2012-2013 Roland Yonaba.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
-- https://opensource.org/licenses/MIT
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
--]]
|
||||
|
||||
local _VERSION = ""
|
||||
|
@ -11,24 +11,7 @@ local sha1 = {
|
||||
|
||||
Copyright (c) 2013 Enrique Garcia Cota + Eike Decker + Jeffrey Friedl
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
https://opensource.org/licenses/MIT
|
||||
]]
|
||||
}
|
||||
|
||||
|
@ -50,8 +50,9 @@ function Terminal.scrollable(win, maxScroll)
|
||||
function win.write(text)
|
||||
local _, h = win.getSize()
|
||||
|
||||
text = tostring(text) or ''
|
||||
scrollTo(#lines - h)
|
||||
win.blit(tostring(text),
|
||||
win.blit(text,
|
||||
_rep(palette[win.getTextColor()], #text),
|
||||
_rep(palette[win.getBackgroundColor()], #text))
|
||||
local x, y = win.getCursorPos()
|
||||
|
@ -1,5 +1,3 @@
|
||||
_G.requireInjector()
|
||||
|
||||
local Grid = require('jumper.grid')
|
||||
local Pathfinder = require('jumper.pathfinder')
|
||||
local Point = require('point')
|
||||
|
@ -3,7 +3,6 @@ local class = require('class')
|
||||
local Event = require('event')
|
||||
local Input = require('input')
|
||||
local Peripheral = require('peripheral')
|
||||
local Terminal = require('terminal')
|
||||
local Transition = require('ui.transition')
|
||||
local Util = require('util')
|
||||
|
||||
@ -46,12 +45,12 @@ end
|
||||
local Manager = class()
|
||||
function Manager:init()
|
||||
local function keyFunction(event, code, held)
|
||||
local ch = Input:translate(event, code, held)
|
||||
local ie = Input:translate(event, code, held)
|
||||
|
||||
if ch and self.currentPage then
|
||||
if ie and self.currentPage then
|
||||
local target = self.currentPage.focused or self.currentPage
|
||||
self:inputEvent(target,
|
||||
{ type = 'key', key = ch, element = target })
|
||||
{ type = 'key', key = ie.code == 'char' and ie.ch or ie.code, element = target })
|
||||
self.currentPage:sync()
|
||||
end
|
||||
end
|
||||
@ -94,10 +93,10 @@ function Manager:init()
|
||||
-- this should be moved to the device !
|
||||
monitor_touch = function(_, side, x, y)
|
||||
Input:translate('mouse_click', 1, x, y)
|
||||
local ch = Input:translate('mouse_up', 1, x, y)
|
||||
local ie = Input:translate('mouse_up', 1, x, y)
|
||||
if self.currentPage then
|
||||
if self.currentPage.parent.device.side == side then
|
||||
self:click(ch, 1, x, y)
|
||||
self:click(ie.code, 1, x, y)
|
||||
end
|
||||
end
|
||||
end,
|
||||
@ -117,27 +116,27 @@ function Manager:init()
|
||||
end,
|
||||
|
||||
mouse_up = function(_, button, x, y)
|
||||
local ch = Input:translate('mouse_up', button, x, y)
|
||||
local ie = Input:translate('mouse_up', button, x, y)
|
||||
|
||||
if ch == 'control-shift-mouse_click' then -- hack
|
||||
if ie.code == 'control-shift-mouse_click' then -- hack
|
||||
local event = self.currentPage:pointToChild(x, y)
|
||||
_ENV.multishell.openTab({
|
||||
path = 'sys/apps/Lua.lua',
|
||||
args = { event.element },
|
||||
focused = true })
|
||||
|
||||
elseif ch and self.currentPage then
|
||||
elseif ie and self.currentPage then
|
||||
--if not self.currentPage.parent.device.side then
|
||||
self:click(ch, button, x, y)
|
||||
self:click(ie.code, button, x, y)
|
||||
--end
|
||||
end
|
||||
end,
|
||||
|
||||
mouse_drag = function(_, button, x, y)
|
||||
local ch = Input:translate('mouse_drag', button, x, y)
|
||||
if ch and self.currentPage then
|
||||
local ie = Input:translate('mouse_drag', button, x, y)
|
||||
if ie and self.currentPage then
|
||||
local event = self.currentPage:pointToChild(x, y)
|
||||
event.type = ch
|
||||
event.type = ie.code
|
||||
self:inputEvent(event.element, event)
|
||||
self.currentPage:sync()
|
||||
end
|
||||
@ -2298,7 +2297,7 @@ function UI.Wizard:enable()
|
||||
child:disable()
|
||||
end
|
||||
end
|
||||
self:emit({ type = 'enable_view', view = Util.find(self.pages, 'index', 1) })
|
||||
self:emit({ type = 'enable_view', next = Util.find(self.pages, 'index', 1) })
|
||||
end
|
||||
|
||||
function UI.Wizard:nextView()
|
||||
@ -2327,29 +2326,44 @@ end
|
||||
|
||||
function UI.Wizard:eventHandler(event)
|
||||
if event.type == 'nextView' then
|
||||
self:nextView()
|
||||
self:draw()
|
||||
return true
|
||||
local currentView = Util.find(self.pages, 'enabled', true)
|
||||
local nextView = Util.find(self.pages, 'index', currentView.index + 1)
|
||||
currentView:emit({ type = 'enable_view', next = nextView, current = currentView })
|
||||
|
||||
elseif event.type == 'previousView' then
|
||||
self:prevView()
|
||||
self:draw()
|
||||
local currentView = Util.find(self.pages, 'enabled', true)
|
||||
local nextView = Util.find(self.pages, 'index', currentView.index - 1)
|
||||
currentView:emit({ type = 'enable_view', prev = nextView, current = currentView })
|
||||
return true
|
||||
|
||||
elseif event.type == 'enable_view' then
|
||||
if Util.find(self.pages, 'index', event.view.index - 1) then
|
||||
if event.current then
|
||||
if event.next then
|
||||
self:addTransition('slideLeft')
|
||||
elseif event.prev then
|
||||
self:addTransition('slideRight')
|
||||
end
|
||||
event.current:disable()
|
||||
end
|
||||
|
||||
-- a new current view
|
||||
local current = event.next or event.prev
|
||||
current:enable()
|
||||
|
||||
if Util.find(self.pages, 'index', current.index - 1) then
|
||||
self.previousButton:enable()
|
||||
else
|
||||
self.previousButton:disable()
|
||||
end
|
||||
|
||||
if Util.find(self.pages, 'index', event.view.index + 1) then
|
||||
if Util.find(self.pages, 'index', current.index + 1) then
|
||||
self.nextButton.text = 'Next >'
|
||||
self.nextButton.event = 'nextView'
|
||||
else
|
||||
self.nextButton.text = 'Accept'
|
||||
self.nextButton.event = 'accept'
|
||||
end
|
||||
self:draw()
|
||||
end
|
||||
end
|
||||
|
||||
@ -2422,8 +2436,9 @@ UI.Embedded.defaults = {
|
||||
function UI.Embedded:setParent()
|
||||
UI.Window.setParent(self)
|
||||
self.win = window.create(UI.term.device, 1, 1, self.width, self.height, false)
|
||||
Canvas.convertWindow(self.win, UI.term.device, self.x, self.y)
|
||||
Terminal.scrollable(self.win, 100)
|
||||
Canvas.scrollingWindow(self.win, self.x, self.y)
|
||||
self.win.setParent(UI.term.device)
|
||||
self.win.setMaxScroll(100)
|
||||
|
||||
local canvas = self:getCanvas()
|
||||
self.win.canvas.parent = canvas
|
||||
|
@ -128,7 +128,7 @@ function Canvas:write(x, y, text, bg, fg)
|
||||
end
|
||||
|
||||
function Canvas:writeBlit(x, y, text, bg, fg)
|
||||
if y > 0 and y <= self.height and x <= self.width then
|
||||
if y > 0 and y <= #self.lines and x <= self.width then
|
||||
local width = #text
|
||||
|
||||
-- fix ffs
|
||||
@ -367,4 +367,132 @@ function Canvas.convertWindow(win, parent, wx, wy)
|
||||
win.clear()
|
||||
end
|
||||
|
||||
function Canvas.scrollingWindow(win, wx, wy)
|
||||
local w, h = win.getSize()
|
||||
local scrollPos = 0
|
||||
local maxScroll = h
|
||||
|
||||
-- canvas lines are are a sliding window within the local lines table
|
||||
local lines = { }
|
||||
|
||||
local parent
|
||||
local canvas = Canvas({
|
||||
x = wx,
|
||||
y = wy,
|
||||
width = w,
|
||||
height = h,
|
||||
isColor = win.isColor(),
|
||||
})
|
||||
win.canvas = canvas
|
||||
|
||||
local function scrollTo(p, forceRedraw)
|
||||
local ms = #lines - canvas.height -- max scroll
|
||||
p = math.min(math.max(p, 0), ms) -- normalize
|
||||
|
||||
if p ~= scrollPos or forceRedraw then
|
||||
scrollPos = p
|
||||
for i = 1, canvas.height do
|
||||
canvas.lines[i] = lines[i + scrollPos]
|
||||
end
|
||||
canvas:dirty()
|
||||
end
|
||||
end
|
||||
|
||||
function win.blit(text, fg, bg)
|
||||
local x, y = win.getCursorPos()
|
||||
win.canvas:writeBlit(x, y, text, bg, fg)
|
||||
win.redraw()
|
||||
end
|
||||
|
||||
function win.clear()
|
||||
lines = { }
|
||||
for i = 1, canvas.height do
|
||||
lines[i] = canvas.lines[i]
|
||||
end
|
||||
scrollPos = 0
|
||||
canvas:clear(win.getBackgroundColor(), win.getTextColor())
|
||||
win.redraw()
|
||||
end
|
||||
|
||||
function win.clearLine()
|
||||
local _, y = win.getCursorPos()
|
||||
|
||||
scrollTo(#lines - canvas.height)
|
||||
win.canvas:write(1,
|
||||
y,
|
||||
_rep(' ', win.canvas.width),
|
||||
win.getBackgroundColor(),
|
||||
win.getTextColor())
|
||||
win.redraw()
|
||||
end
|
||||
|
||||
function win.redraw()
|
||||
if parent and canvas.visible then
|
||||
local x, y = win.getCursorPos()
|
||||
for i = 1, canvas.height do
|
||||
local line = canvas.lines[i]
|
||||
if line and line.dirty then
|
||||
parent.setCursorPos(canvas.x, canvas.y + i - 1)
|
||||
parent.blit(line.text, line.fg, line.bg)
|
||||
line.dirty = false
|
||||
end
|
||||
end
|
||||
win.setCursorPos(x, y)
|
||||
end
|
||||
end
|
||||
|
||||
-- doesn't support negative scrolling...
|
||||
function win.scroll(n)
|
||||
for _ = 1, n do
|
||||
lines[#lines + 1] = {
|
||||
text = _rep(' ', canvas.width),
|
||||
fg = _rep(canvas.palette[win.getTextColor()], canvas.width),
|
||||
bg = _rep(canvas.palette[win.getBackgroundColor()], canvas.width),
|
||||
}
|
||||
end
|
||||
|
||||
while #lines > maxScroll do
|
||||
table.remove(lines, 1)
|
||||
end
|
||||
|
||||
scrollTo(maxScroll, true)
|
||||
win.redraw()
|
||||
end
|
||||
|
||||
function win.scrollDown()
|
||||
scrollTo(scrollPos + 1)
|
||||
win.redraw()
|
||||
end
|
||||
|
||||
function win.scrollUp()
|
||||
scrollTo(scrollPos - 1)
|
||||
win.redraw()
|
||||
end
|
||||
|
||||
function win.setMaxScroll(ms)
|
||||
maxScroll = ms
|
||||
end
|
||||
|
||||
function win.setParent(p)
|
||||
parent = p
|
||||
end
|
||||
|
||||
function win.write(str)
|
||||
str = tostring(str) or ''
|
||||
|
||||
local x, y = win.getCursorPos()
|
||||
scrollTo(#lines - canvas.height)
|
||||
win.blit(str,
|
||||
_rep(canvas.palette[win.getTextColor()], #str),
|
||||
_rep(canvas.palette[win.getBackgroundColor()], #str))
|
||||
win.setCursorPos(x + #str, y)
|
||||
end
|
||||
|
||||
function win.reposition(x, y, width, height)
|
||||
win.canvas.x, win.canvas.y = x, y
|
||||
win.canvas:resize(width or win.canvas.width, height or win.canvas.height)
|
||||
end
|
||||
|
||||
win.clear()
|
||||
end
|
||||
return Canvas
|
||||
|
@ -1,4 +1,3 @@
|
||||
-------------------------------------------------------------------------------
|
||||
--
|
||||
-- tek.lib.region
|
||||
-- Written by Timm S. Mueller <tmueller at schulze-mueller.de>
|
||||
@ -9,49 +8,11 @@
|
||||
-- * Franciska Schulze <fschulze at schulze-mueller.de>
|
||||
-- * Tobias Schwinger <tschwinger at isonews2.com>
|
||||
--
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining
|
||||
-- a copy of this software and associated documentation files (the
|
||||
-- "Software"), to deal in the Software without restriction, including
|
||||
-- without limitation the rights to use, copy, modify, merge, publish,
|
||||
-- distribute, sublicense, and/or sell copies of the Software, and to
|
||||
-- permit persons to whom the Software is furnished to do so, subject to
|
||||
-- the following conditions:
|
||||
-- https://opensource.org/licenses/MIT
|
||||
--
|
||||
-- The above copyright notice and this permission notice shall be
|
||||
-- included in all copies or substantial portions of the Software.
|
||||
--
|
||||
-- === Disclaimer ===
|
||||
--
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
-- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
-- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
-- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
-- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
--
|
||||
-- OVERVIEW::
|
||||
-- This library implements the management of regions, which are
|
||||
-- collections of non-overlapping rectangles.
|
||||
--
|
||||
-- FUNCTIONS::
|
||||
-- - Region:andRect() - ''And''s a rectangle to a region
|
||||
-- - Region:andRegion() - ''And''s a region to a region
|
||||
-- - Region:checkIntersect() - Checks if a rectangle intersects a region
|
||||
-- - Region:forEach() - Calls a function for each rectangle in a region
|
||||
-- - Region:get() - Get region's min/max extents
|
||||
-- - Region.intersect() - Returns the intersection of two rectangles
|
||||
-- - Region:isEmpty() - Checks if a Region is empty
|
||||
-- - Region.new() - Creates a new Region
|
||||
-- - Region:orRect() - ''Or''s a rectangle to a region
|
||||
-- - Region:orRegion() - ''Or''s a region to a region
|
||||
-- - Region:setRect() - Resets a region to the given rectangle
|
||||
-- - Region:shift() - Displaces a region
|
||||
-- - Region:subRect() - Subtracts a rectangle from a region
|
||||
-- - Region:subRegion() - Subtracts a region from a region
|
||||
-- - Region:xorRect() - ''Exclusive Or''s a rectangle to a region
|
||||
--
|
||||
-------------------------------------------------------------------------------
|
||||
-- Some comments have been removed to reduce file size, see:
|
||||
-- https://github.com/technosaurus/tekui/blob/master/etc/region.lua
|
||||
-- for the full source
|
||||
|
||||
local insert = table.insert
|
||||
local ipairs = ipairs
|
||||
@ -65,24 +26,18 @@ Region._VERSION = "Region 11.3"
|
||||
|
||||
Region.__index = Region
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- x0, y0, x1, y1 = Region.intersect(d1, d2, d3, d4, s1, s2, s3, s4):
|
||||
-- Returns the coordinates of a rectangle where a rectangle specified by
|
||||
-- the coordinates s1, s2, s3, s4 overlaps with the rectangle specified
|
||||
-- by the coordinates d1, d2, d3, d4. The return value is '''nil''' if
|
||||
-- the rectangles do not overlap.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region.intersect(d1, d2, d3, d4, s1, s2, s3, s4)
|
||||
if s3 >= d1 and s1 <= d3 and s4 >= d2 and s2 <= d4 then
|
||||
return max(s1, d1), max(s2, d2), min(s3, d3), min(s4, d4)
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- insertrect: insert rect to table, merging with an existing one if possible
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local function insertrect(d, s1, s2, s3, s4)
|
||||
for i = 1, min(4, #d) do
|
||||
local a = d[i]
|
||||
@ -108,10 +63,7 @@ local function insertrect(d, s1, s2, s3, s4)
|
||||
insert(d, 1, { s1, s2, s3, s4 })
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- cutrect: cut rect d into table of new rects, using rect s as a punch
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local function cutrect(d1, d2, d3, d4, s1, s2, s3, s4)
|
||||
if not Region.intersect(d1, d2, d3, d4, s1, s2, s3, s4) then
|
||||
return { { d1, d2, d3, d4 } }
|
||||
@ -135,10 +87,7 @@ local function cutrect(d1, d2, d3, d4, s1, s2, s3, s4)
|
||||
return r
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- cutregion: cut region d, using s as a punch
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local function cutregion(d, s1, s2, s3, s4)
|
||||
local r = { }
|
||||
for _, dr in ipairs(d) do
|
||||
@ -150,11 +99,8 @@ local function cutregion(d, s1, s2, s3, s4)
|
||||
return r
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- region = Region.new(r1, r2, r3, r4): Creates a new region from the given
|
||||
-- coordinates.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region.new(r1, r2, r3, r4)
|
||||
if r1 then
|
||||
return setmetatable({ region = { { r1, r2, r3, r4 } } }, Region)
|
||||
@ -162,39 +108,27 @@ function Region.new(r1, r2, r3, r4)
|
||||
return setmetatable({ region = { } }, Region)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- self = region:setRect(r1, r2, r3, r4): Resets an existing region
|
||||
-- to the specified rectangle.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region:setRect(r1, r2, r3, r4)
|
||||
self.region = { { r1, r2, r3, r4 } }
|
||||
return self
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- region:orRect(r1, r2, r3, r4): Logical ''or''s a rectangle to a region
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region:orRect(s1, s2, s3, s4)
|
||||
self.region = cutregion(self.region, s1, s2, s3, s4)
|
||||
insertrect(self.region, s1, s2, s3, s4)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- region:orRegion(region): Logical ''or''s another region to a region
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region:orRegion(s)
|
||||
for _, r in ipairs(s) do
|
||||
self:orRect(r[1], r[2], r[3], r[4])
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- region:andRect(r1, r2, r3, r4): Logical ''and''s a rectange to a region
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region:andRect(s1, s2, s3, s4)
|
||||
local r = { }
|
||||
for _, d in ipairs(self.region) do
|
||||
@ -207,10 +141,7 @@ function Region:andRect(s1, s2, s3, s4)
|
||||
self.region = r
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- region:xorRect(r1, r2, r3, r4): Logical ''xor''s a rectange to a region
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region:xorRect(s1, s2, s3, s4)
|
||||
local r1 = { }
|
||||
local r2 = { { s1, s2, s3, s4 } }
|
||||
@ -225,10 +156,7 @@ function Region:xorRect(s1, s2, s3, s4)
|
||||
self:orRegion(r2)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- self = region:subRect(r1, r2, r3, r4): Subtracts a rectangle from a region
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region:subRect(s1, s2, s3, s4)
|
||||
local r1 = { }
|
||||
for _, d in ipairs(self.region) do
|
||||
@ -241,10 +169,7 @@ function Region:subRect(s1, s2, s3, s4)
|
||||
return self
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- region:getRect - gets an iterator on the rectangles in a region [internal]
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region:getRects()
|
||||
local index = 0
|
||||
return function(object)
|
||||
@ -255,12 +180,9 @@ function Region:getRects()
|
||||
end, self.region
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- success = region:checkIntersect(x0, y0, x1, y1): Returns a boolean
|
||||
-- indicating whether a rectangle specified by its coordinates overlaps
|
||||
-- with a region.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region:checkIntersect(s1, s2, s3, s4)
|
||||
for _, d in ipairs(self.region) do
|
||||
if Region.intersect(d[1], d[2], d[3], d[4], s1, s2, s3, s4) then
|
||||
@ -270,10 +192,7 @@ function Region:checkIntersect(s1, s2, s3, s4)
|
||||
return false
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- region:subRegion(region2): Subtracts {{region2}} from {{region}}.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region:subRegion(region)
|
||||
if region then
|
||||
for r1, r2, r3, r4 in region:getRects() do
|
||||
@ -282,10 +201,7 @@ function Region:subRegion(region)
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- region:andRegion(r): Logically ''and''s a region to a region
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region:andRegion(s)
|
||||
local r = { }
|
||||
for _, s in ipairs(s.region) do
|
||||
@ -301,23 +217,17 @@ function Region:andRegion(s)
|
||||
self.region = r
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- region:forEach(func, obj, ...): For each rectangle in a region, calls the
|
||||
-- specified function according the following scheme:
|
||||
-- func(obj, x0, y0, x1, y1, ...)
|
||||
-- Extra arguments are passed through to the function.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region:forEach(func, obj, ...)
|
||||
for x0, y0, x1, y1 in self:getRects() do
|
||||
func(obj, x0, y0, x1, y1, ...)
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- region:shift(dx, dy): Shifts a region by delta x and y.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region:shift(dx, dy)
|
||||
for _, r in ipairs(self.region) do
|
||||
r[1] = r[1] + dx
|
||||
@ -327,18 +237,12 @@ function Region:shift(dx, dy)
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- region:isEmpty(): Returns '''true''' if a region is empty.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region:isEmpty()
|
||||
return #self.region == 0
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- minx, miny, maxx, maxy = region:get(): Get region's min/max extents
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function Region:get()
|
||||
if #self.region > 0 then
|
||||
local minx = 1000000 -- ui.HUGE
|
||||
|
@ -7,24 +7,7 @@ local tween = {
|
||||
|
||||
Copyright (c) 2014 Enrique García Cota, Yuichi Tateno, Emmanuel Oga
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Licence details: https://opensource.org/licenses/MIT
|
||||
]]
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
_G.requireInjector()
|
||||
_G.requireInjector(_ENV)
|
||||
|
||||
local UI = require('ui')
|
||||
local Util = require('util')
|
||||
|
456
sys/apps/Installer.lua
Normal file
456
sys/apps/Installer.lua
Normal file
@ -0,0 +1,456 @@
|
||||
local colors = _G.colors
|
||||
local fs = _G.fs
|
||||
local http = _G.http
|
||||
local install = _ENV.install
|
||||
local os = _G.os
|
||||
|
||||
local requireInjector
|
||||
if not install.testing then
|
||||
local url ='https://raw.githubusercontent.com/kepler155c/opus/master/sys/apis/injector.lua'
|
||||
requireInjector = load(http.get(url).readAll())()
|
||||
else
|
||||
requireInjector = _G.requireInjector
|
||||
end
|
||||
|
||||
requireInjector(_ENV)
|
||||
|
||||
if not install.testing then
|
||||
if package then
|
||||
for _ = 1, 4 do
|
||||
table.remove(package.loaders, 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local Git = require('git')
|
||||
local UI = require('ui')
|
||||
local Util = require('util')
|
||||
|
||||
local currentFile = ''
|
||||
local currentProgress = 0
|
||||
local cancelEvent
|
||||
|
||||
local args = { ... }
|
||||
local steps = install.steps[args[1] or 'install']
|
||||
|
||||
if not steps then
|
||||
error('Invalid install type')
|
||||
end
|
||||
|
||||
local mode = steps[#steps]
|
||||
|
||||
if UI.term.width < 32 then
|
||||
cancelEvent = 'quit'
|
||||
end
|
||||
|
||||
local page = UI.Page {
|
||||
backgroundColor = colors.cyan,
|
||||
titleBar = UI.TitleBar {
|
||||
event = cancelEvent,
|
||||
},
|
||||
wizard = UI.Wizard {
|
||||
y = 2, ey = -2,
|
||||
},
|
||||
notification = UI.Notification(),
|
||||
accelerators = {
|
||||
q = 'quit',
|
||||
},
|
||||
}
|
||||
|
||||
local pages = {
|
||||
splash = UI.Viewport { },
|
||||
review = UI.Viewport { },
|
||||
license = UI.Viewport {
|
||||
backgroundColor = colors.black,
|
||||
},
|
||||
branch = UI.Window {
|
||||
grid = UI.ScrollingGrid {
|
||||
ey = -3,
|
||||
columns = {
|
||||
{ heading = 'Branch', key = 'branch' },
|
||||
{ heading = 'Description', key = 'description' },
|
||||
},
|
||||
values = install.branches,
|
||||
autospace = true,
|
||||
},
|
||||
},
|
||||
files = UI.Window {
|
||||
grid = UI.ScrollingGrid {
|
||||
ey = -3,
|
||||
columns = {
|
||||
{ heading = 'Files', key = 'file' },
|
||||
},
|
||||
sortColumn = 'file',
|
||||
},
|
||||
},
|
||||
install = UI.Window {
|
||||
progressBar = UI.ProgressBar {
|
||||
y = -1,
|
||||
},
|
||||
},
|
||||
uninstall = UI.Window {
|
||||
progressBar = UI.ProgressBar {
|
||||
y = -1,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
local function getFileList()
|
||||
if install.gitRepo then
|
||||
local gitFiles = Git.list(string.format('%s/%s', install.gitRepo, install.gitBranch or 'master'))
|
||||
install.files = { }
|
||||
install.diskspace = 0
|
||||
for path, entry in pairs(gitFiles) do
|
||||
install.files[path] = entry.url
|
||||
install.diskspace = install.diskspace + entry.size
|
||||
end
|
||||
end
|
||||
|
||||
if not install.files or Util.empty(install.files) then
|
||||
error('File list is missing or empty')
|
||||
end
|
||||
end
|
||||
|
||||
--[[ Splash ]]--
|
||||
function pages.splash:enable()
|
||||
page.titleBar.title = 'Installer v1.0'
|
||||
UI.Viewport.enable(self)
|
||||
end
|
||||
|
||||
function pages.splash:draw()
|
||||
self:clear()
|
||||
self:setCursorPos(1, 1)
|
||||
self:print(
|
||||
string.format('%s v%s\n', install.title, install.version), nil, colors.yellow)
|
||||
self:print(
|
||||
string.format('By: %s\n\n%s\n', install.author, install.description))
|
||||
|
||||
self.ymax = self.cursorY
|
||||
end
|
||||
|
||||
--[[ License ]]--
|
||||
function pages.license:enable()
|
||||
page.titleBar.title = 'License Review'
|
||||
page.wizard.nextButton.text = 'Accept'
|
||||
UI.Viewport.enable(self)
|
||||
end
|
||||
|
||||
function pages.license:draw()
|
||||
self:clear()
|
||||
self:setCursorPos(1, 1)
|
||||
self:print(
|
||||
string.format('Copyright (c) %s %s\n\n', install.copyrightYear,
|
||||
install.copyrightHolders),
|
||||
nil, colors.yellow)
|
||||
self:print(install.license)
|
||||
|
||||
self.ymax = self.cursorY + 1
|
||||
end
|
||||
|
||||
--[[ Review ]]--
|
||||
function pages.review:enable()
|
||||
if mode == 'uninstall' then
|
||||
page.nextButton.text = 'Remove'
|
||||
page.titleBar.title = 'Remove Installed Files'
|
||||
else
|
||||
page.wizard.nextButton.text = 'Begin'
|
||||
page.titleBar.title = 'Download and Install'
|
||||
end
|
||||
UI.Viewport.enable(self)
|
||||
end
|
||||
|
||||
function pages.review:draw()
|
||||
self:clear()
|
||||
self:setCursorPos(1, 1)
|
||||
|
||||
local text = 'Ready to begin installation.\n\nProceeding will download and install the files to the hard drive.'
|
||||
if mode == 'uninstall' then
|
||||
text = 'Ready to begin.\n\nProceeding will remove the files previously installed.'
|
||||
end
|
||||
self:print(text)
|
||||
|
||||
self.ymax = self.cursorY + 1
|
||||
end
|
||||
|
||||
--[[ Files ]]--
|
||||
function pages.files:enable()
|
||||
page.titleBar.title = 'Review Files'
|
||||
self.grid.values = { }
|
||||
for k,v in pairs(install.files) do
|
||||
table.insert(self.grid.values, { file = k, code = v })
|
||||
end
|
||||
self.grid:update()
|
||||
UI.Window.enable(self)
|
||||
end
|
||||
|
||||
function pages.files:draw()
|
||||
self:clear()
|
||||
|
||||
local function formatSize(size)
|
||||
if size >= 1000000 then
|
||||
return string.format('%dM', math.floor(size/1000000, 2))
|
||||
elseif size >= 1000 then
|
||||
return string.format('%dK', math.floor(size/1000, 2))
|
||||
end
|
||||
return size
|
||||
end
|
||||
|
||||
if install.diskspace then
|
||||
|
||||
local bg = self.backgroundColor
|
||||
|
||||
local diskFree = fs.getFreeSpace('/')
|
||||
if install.diskspace > diskFree then
|
||||
bg = colors.red
|
||||
end
|
||||
|
||||
local text = string.format('Space Required: %s, Free: %s',
|
||||
formatSize(install.diskspace), formatSize(diskFree))
|
||||
|
||||
if #text > self.width then
|
||||
text = string.format('Space: %s Free: %s',
|
||||
formatSize(install.diskspace), formatSize(diskFree))
|
||||
end
|
||||
|
||||
self:write(1, self.height, Util.widthify(text, self.width), bg)
|
||||
end
|
||||
self.grid:draw()
|
||||
end
|
||||
|
||||
--[[
|
||||
function pages.files:view(url)
|
||||
local s, m = pcall(function()
|
||||
page.notification:info('Downloading')
|
||||
page:sync()
|
||||
Util.download(url, '/.source')
|
||||
end)
|
||||
page.notification:disable()
|
||||
if s then
|
||||
shell.run('edit /.source')
|
||||
fs.delete('/.source')
|
||||
page:draw()
|
||||
page.notification:cancel()
|
||||
else
|
||||
page.notification:error(m:gsub('.*: (.*)', '%1'))
|
||||
end
|
||||
end
|
||||
|
||||
function pages.files:eventHandler(event)
|
||||
if event.type == 'grid_select' then
|
||||
self:view(event.selected.code)
|
||||
return true
|
||||
end
|
||||
end
|
||||
--]]
|
||||
|
||||
local function drawCommon(self)
|
||||
if currentFile then
|
||||
self:write(1, 3, 'File:')
|
||||
self:write(1, 4, Util.widthify(currentFile, self.width))
|
||||
else
|
||||
self:write(1, 3, 'Finished')
|
||||
end
|
||||
if self.failed then
|
||||
self:write(1, 5, Util.widthify(self.failed, self.width), colors.red)
|
||||
end
|
||||
self:write(1, self.height - 1, 'Progress')
|
||||
|
||||
self.progressBar.value = currentProgress
|
||||
self.progressBar:draw()
|
||||
self:sync()
|
||||
end
|
||||
|
||||
--[[ Branch ]]--
|
||||
function pages.branch:enable()
|
||||
page.titleBar.title = 'Select Branch'
|
||||
UI.Window.enable(self)
|
||||
end
|
||||
|
||||
function pages.branch:eventHandler(event)
|
||||
-- user is navigating to next view (not previous)
|
||||
if event.type == 'enable_view' and event.next then
|
||||
install.gitBranch = self.grid:getSelected().branch
|
||||
getFileList()
|
||||
end
|
||||
end
|
||||
|
||||
--[[ Install ]]--
|
||||
function pages.install:enable()
|
||||
page.wizard.cancelButton:disable()
|
||||
page.wizard.previousButton:disable()
|
||||
page.wizard.nextButton:disable()
|
||||
|
||||
page.titleBar.title = 'Installing...'
|
||||
page.titleBar.event = nil
|
||||
|
||||
UI.Window.enable(self)
|
||||
|
||||
page:draw()
|
||||
page:sync()
|
||||
|
||||
local i = 0
|
||||
local numFiles = Util.size(install.files)
|
||||
for filename,url in pairs(install.files) do
|
||||
currentFile = filename
|
||||
currentProgress = i / numFiles * 100
|
||||
self:draw(self)
|
||||
self:sync()
|
||||
local s, m = pcall(function()
|
||||
Util.download(url, fs.combine(install.directory or '', filename))
|
||||
end)
|
||||
if not s then
|
||||
self.failed = m:gsub('.*: (.*)', '%1')
|
||||
break
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
if not self.failed then
|
||||
currentProgress = 100
|
||||
currentFile = nil
|
||||
|
||||
if install.postInstall then
|
||||
local s, m = pcall(function() install.postInstall(page, UI) end)
|
||||
if not s then
|
||||
self.failed = m:gsub('.*: (.*)', '%1')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
page.wizard.nextButton.text = 'Exit'
|
||||
page.wizard.nextButton.event = 'quit'
|
||||
if not self.failed and install.rebootAfter then
|
||||
page.wizard.nextButton.text = 'Reboot'
|
||||
page.wizard.nextButton.event = 'reboot'
|
||||
end
|
||||
|
||||
page.wizard.nextButton:enable()
|
||||
page:draw()
|
||||
page:sync()
|
||||
|
||||
if not self.failed and Util.key(args, 'automatic') then
|
||||
if install.rebootAfter then
|
||||
os.reboot()
|
||||
else
|
||||
UI:exitPullEvents()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function pages.install:draw()
|
||||
self:clear()
|
||||
local text = 'The files are being installed'
|
||||
if #text > self.width then
|
||||
text = 'Installing files'
|
||||
end
|
||||
self:write(1, 1, text, nil, colors.yellow)
|
||||
|
||||
drawCommon(self)
|
||||
end
|
||||
|
||||
--[[ Uninstall ]]--
|
||||
function pages.uninstall:enable()
|
||||
page.wizard.cancelButton:disable()
|
||||
page.wizard.previousButton:disable()
|
||||
page.wizard.nextButton:disable()
|
||||
|
||||
page.titleBar.title = 'Uninstalling...'
|
||||
page.titleBar.event = nil
|
||||
|
||||
page:draw()
|
||||
page:sync()
|
||||
|
||||
UI.Window.enable(self)
|
||||
|
||||
local function pruneDir(dir)
|
||||
if #dir > 0 then
|
||||
if fs.exists(dir) then
|
||||
local files = fs.list(dir)
|
||||
if #files == 0 then
|
||||
fs.delete(dir)
|
||||
pruneDir(fs.getDir(dir))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local i = 0
|
||||
local numFiles = Util.size(install.files)
|
||||
for k in pairs(install.files) do
|
||||
currentFile = k
|
||||
currentProgress = i / numFiles * 100
|
||||
self:draw()
|
||||
self:sync()
|
||||
fs.delete(k)
|
||||
pruneDir(fs.getDir(k))
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
currentProgress = 100
|
||||
currentFile = nil
|
||||
|
||||
page.wizard.nextButton.text = 'Exit'
|
||||
page.wizard.nextButton.event = 'quit'
|
||||
page.wizard.nextButton:enable()
|
||||
|
||||
page:draw()
|
||||
page:sync()
|
||||
end
|
||||
|
||||
function pages.uninstall:draw()
|
||||
self:clear()
|
||||
self:write(1, 1, 'Uninstalling files', nil, colors.yellow)
|
||||
drawCommon(self)
|
||||
end
|
||||
|
||||
function page:eventHandler(event)
|
||||
if event.type == 'cancel' then
|
||||
UI:exitPullEvents()
|
||||
|
||||
elseif event.type == 'reboot' then
|
||||
os.reboot()
|
||||
|
||||
elseif event.type == 'quit' then
|
||||
UI:exitPullEvents()
|
||||
|
||||
else
|
||||
return UI.Page.eventHandler(self, event)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function page:enable()
|
||||
UI.Page.enable(self)
|
||||
self:setFocus(page.wizard.nextButton)
|
||||
if UI.term.width < 32 then
|
||||
page.wizard.cancelButton:disable()
|
||||
page.wizard.previousButton.x = 2
|
||||
end
|
||||
end
|
||||
|
||||
getFileList()
|
||||
|
||||
local wizardPages = { }
|
||||
for k,v in ipairs(steps) do
|
||||
if not pages[v] then
|
||||
error('Invalid step: ' .. v)
|
||||
end
|
||||
wizardPages[k] = pages[v]
|
||||
wizardPages[k].index = k
|
||||
wizardPages[k].x = 2
|
||||
wizardPages[k].y = 2
|
||||
wizardPages[k].ey = -3
|
||||
wizardPages[k].ex = -2
|
||||
end
|
||||
page.wizard:add(wizardPages)
|
||||
|
||||
if Util.key(steps, 'install') and install.preInstall then
|
||||
install.preInstall(page, UI)
|
||||
end
|
||||
|
||||
UI:setPage(page)
|
||||
local s, m = pcall(function() UI:pullEvents() end)
|
||||
if not s then
|
||||
UI.term:reset()
|
||||
_G.printError(m)
|
||||
end
|
@ -1,6 +1,5 @@
|
||||
_G.requireInjector(_ENV)
|
||||
|
||||
local Event = require('event')
|
||||
local History = require('history')
|
||||
local UI = require('ui')
|
||||
local Util = require('util')
|
||||
@ -10,8 +9,10 @@ local os = _G.os
|
||||
local textutils = _G.textutils
|
||||
local term = _G.term
|
||||
|
||||
local _exit
|
||||
|
||||
local sandboxEnv = setmetatable(Util.shallowCopy(_ENV), { __index = _G })
|
||||
sandboxEnv.exit = function() Event.exitPullEvents() end
|
||||
sandboxEnv.exit = function() _exit = true end
|
||||
sandboxEnv._echo = function( ... ) return { ... } end
|
||||
_G.requireInjector(sandboxEnv)
|
||||
|
||||
@ -19,7 +20,6 @@ UI:configure('Lua', ...)
|
||||
|
||||
local command = ''
|
||||
local history = History.load('usr/.lua_history', 25)
|
||||
local extChars = Util.getVersion() > 1.76
|
||||
|
||||
local page = UI.Page {
|
||||
menuBar = UI.MenuBar {
|
||||
@ -41,10 +41,6 @@ local page = UI.Page {
|
||||
[ 'control-space' ] = 'autocomplete',
|
||||
},
|
||||
},
|
||||
indicator = UI.Text {
|
||||
backgroundColor = colors.black,
|
||||
y = 2, x = -1, width = 1,
|
||||
},
|
||||
grid = UI.ScrollingGrid {
|
||||
y = 3, ey = -2,
|
||||
columns = {
|
||||
@ -62,21 +58,10 @@ local page = UI.Page {
|
||||
},
|
||||
output = UI.Embedded {
|
||||
y = -6,
|
||||
backgroundColor = colors.gray,
|
||||
},
|
||||
--notification = UI.Notification(),
|
||||
}
|
||||
|
||||
function page.indicator:showResult(s)
|
||||
local values = {
|
||||
[ true ] = { c = colors.green, i = (extChars and '\003') or '+' },
|
||||
[ false ] = { c = colors.red, i = 'x' }
|
||||
}
|
||||
|
||||
self.textColor = values[s].c
|
||||
self.value = values[s].i
|
||||
self:draw()
|
||||
end
|
||||
|
||||
function page:setPrompt(value, focus)
|
||||
self.prompt:setValue(value)
|
||||
self.prompt.scroll = 0
|
||||
@ -133,12 +118,12 @@ end
|
||||
|
||||
function page:eventHandler(event)
|
||||
if event.type == 'global' then
|
||||
self:setPrompt('', true)
|
||||
self:setPrompt('_G', true)
|
||||
self:executeStatement('_G')
|
||||
command = nil
|
||||
|
||||
elseif event.type == 'local' then
|
||||
self:setPrompt('', true)
|
||||
self:setPrompt('_ENV', true)
|
||||
self:executeStatement('_ENV')
|
||||
command = nil
|
||||
|
||||
@ -341,8 +326,11 @@ end
|
||||
function page:executeStatement(statement)
|
||||
command = statement
|
||||
|
||||
local s, m
|
||||
local oterm = term.redirect(self.output.win)
|
||||
local s, m = self:rawExecute(command)
|
||||
pcall(function()
|
||||
s, m = self:rawExecute(command)
|
||||
end)
|
||||
if not s then
|
||||
_G.printError(m)
|
||||
end
|
||||
@ -353,14 +341,14 @@ function page:executeStatement(statement)
|
||||
else
|
||||
self.grid:setValues({ })
|
||||
self.grid:draw()
|
||||
if m then
|
||||
if not self.output.enabled then
|
||||
if m and not self.output.enabled then
|
||||
self:emit({ type = 'show_output' })
|
||||
end
|
||||
--self.notification:error(m, 5)
|
||||
end
|
||||
|
||||
if _exit then
|
||||
UI:exitPullEvents()
|
||||
end
|
||||
self.indicator:showResult(not not s)
|
||||
end
|
||||
|
||||
local args = { ... }
|
||||
@ -371,5 +359,4 @@ if args[1] then
|
||||
end
|
||||
|
||||
UI:setPage(page)
|
||||
Event.pullEvents()
|
||||
UI.term:reset()
|
||||
UI:pullEvents()
|
||||
|
@ -1,4 +1,4 @@
|
||||
_G.requireInjector()
|
||||
_G.requireInjector(_ENV)
|
||||
|
||||
local class = require('class')
|
||||
local Config = require('config')
|
||||
|
@ -1,4 +1,4 @@
|
||||
_G.requireInjector()
|
||||
_G.requireInjector(_ENV)
|
||||
|
||||
local Config = require('config')
|
||||
local Security = require('security')
|
||||
@ -201,9 +201,13 @@ end
|
||||
if settings then
|
||||
local values = { }
|
||||
for _,v in pairs(settings.getNames()) do
|
||||
local value = settings.get(v)
|
||||
if not value then
|
||||
value = false
|
||||
end
|
||||
table.insert(values, {
|
||||
name = v,
|
||||
value = not not settings.get(v),
|
||||
value = value,
|
||||
})
|
||||
end
|
||||
|
||||
@ -224,7 +228,9 @@ if settings then
|
||||
})
|
||||
function systemPage.tabs.settingsTab:eventHandler(event)
|
||||
if event.type == 'grid_select' then
|
||||
if not event.selected.value or type(event.selected.value) == 'boolean' then
|
||||
event.selected.value = not event.selected.value
|
||||
end
|
||||
settings.set(event.selected.name, event.selected.value)
|
||||
settings.save('.settings')
|
||||
self.grid:draw()
|
||||
|
@ -58,11 +58,7 @@ function page.grid:getDisplayValues(row)
|
||||
else
|
||||
row.timestamp = string.format("%sm", math.floor(elapsed/6)/10)
|
||||
end
|
||||
if row.isDead then
|
||||
row.status = 'error'
|
||||
else
|
||||
row.status = coroutine.status(row.co)
|
||||
end
|
||||
row.status = row.isDead and 'error' or coroutine.status(row.co)
|
||||
return row
|
||||
end
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
_G.requireInjector()
|
||||
_G.requireInjector(_ENV)
|
||||
|
||||
local Event = require('event')
|
||||
local Util = require('util')
|
||||
|
@ -1,4 +1,4 @@
|
||||
_G.requireInjector()
|
||||
_G.requireInjector(_ENV)
|
||||
|
||||
local Security = require('security')
|
||||
local SHA1 = require('sha1')
|
||||
|
170
sys/apps/shell
170
sys/apps/shell
@ -11,7 +11,7 @@ for k,v in pairs(_ENV) do
|
||||
end
|
||||
sandboxEnv.shell = shell
|
||||
|
||||
_G.requireInjector()
|
||||
_G.requireInjector(_ENV)
|
||||
|
||||
local Util = require('util')
|
||||
|
||||
@ -118,6 +118,10 @@ function shell.resolveProgram( _sCommand )
|
||||
_sCommand = tAliases[_sCommand]
|
||||
end
|
||||
|
||||
if _sCommand:match("^(https?:)") then
|
||||
return _sCommand
|
||||
end
|
||||
|
||||
local path = shell.resolve(_sCommand)
|
||||
if fs.exists(path) and not fs.isDir(path) then
|
||||
return path
|
||||
@ -325,10 +329,8 @@ function shell.openTab( ... )
|
||||
local sPath = shell.resolveProgram(sCommand)
|
||||
if sPath == "sys/apps/shell" then
|
||||
return _ENV.multishell.launch(Util.shallowCopy(sandboxEnv), sPath, table.unpack(tWords, 2))
|
||||
elseif sPath ~= nil then
|
||||
return _ENV.multishell.launch(Util.shallowCopy(sandboxEnv), "sys/apps/shell", sCommand, table.unpack(tWords, 2))
|
||||
else
|
||||
return false, "No such program"
|
||||
return _ENV.multishell.launch(Util.shallowCopy(sandboxEnv), "sys/apps/shell", sCommand, table.unpack(tWords, 2))
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -352,11 +354,12 @@ if #tArgs > 0 then
|
||||
end
|
||||
|
||||
local Config = require('config')
|
||||
local Entry = require('entry')
|
||||
local History = require('history')
|
||||
local Input = require('input')
|
||||
local Terminal = require('terminal')
|
||||
|
||||
local colors = _G.colors
|
||||
local keys = _G.keys
|
||||
local os = _G.os
|
||||
local term = _G.term
|
||||
local textutils = _G.textutils
|
||||
@ -538,128 +541,81 @@ local function autocomplete(line)
|
||||
end
|
||||
|
||||
local function shellRead(history)
|
||||
term.setCursorBlink( true )
|
||||
|
||||
local sLine = ""
|
||||
local nPos = 0
|
||||
|
||||
local w = term.getSize()
|
||||
local sx = term.getCursorPos()
|
||||
local lastLen = 0
|
||||
local entry = Entry({
|
||||
width = term.getSize() - 3
|
||||
})
|
||||
|
||||
history:reset()
|
||||
term.setCursorBlink(true)
|
||||
|
||||
local function redraw( sReplace )
|
||||
local nScroll = 0
|
||||
if sx + nPos >= w then
|
||||
nScroll = (sx + nPos) - w
|
||||
end
|
||||
|
||||
local function redraw()
|
||||
local _,cy = term.getCursorPos()
|
||||
term.setCursorPos( sx, cy )
|
||||
if sReplace then
|
||||
term.write( string.rep( sReplace, math.max( string.len(sLine) - nScroll, 0 ) ) )
|
||||
else
|
||||
term.write( string.sub( sLine, nScroll + 1 ) )
|
||||
end
|
||||
term.setCursorPos( sx + nPos - nScroll, cy )
|
||||
term.setCursorPos(3, cy)
|
||||
local filler = #entry.value < lastLen
|
||||
and string.rep(' ', lastLen - #entry.value)
|
||||
or ''
|
||||
local str = string.sub(entry.value, entry.scroll + 1)
|
||||
term.write(string.sub(str, 1, entry.width) .. filler)
|
||||
term.setCursorPos(3 + entry.pos - entry.scroll, cy)
|
||||
lastLen = #entry.value
|
||||
end
|
||||
|
||||
while true do
|
||||
local sEvent, param = os.pullEventRaw()
|
||||
local event, p1, p2, p3 = os.pullEventRaw()
|
||||
|
||||
if sEvent == "char" then
|
||||
sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 )
|
||||
nPos = nPos + 1
|
||||
redraw()
|
||||
elseif sEvent == "paste" then
|
||||
sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 )
|
||||
nPos = nPos + string.len( param )
|
||||
redraw()
|
||||
elseif sEvent == 'mouse_click' and param == 2 then
|
||||
redraw(string.rep(' ', #sLine))
|
||||
sLine = ''
|
||||
nPos = 0
|
||||
redraw()
|
||||
elseif sEvent == 'mouse_scroll' then
|
||||
if param == -1 then
|
||||
local ie = Input:translate(event, p1, p2, p3)
|
||||
if ie then
|
||||
if ie.code == 'scroll_up' then
|
||||
terminal.scrollUp()
|
||||
else
|
||||
|
||||
elseif ie.code == 'scroll_down' then
|
||||
terminal.scrollDown()
|
||||
end
|
||||
elseif sEvent == 'terminate' then
|
||||
|
||||
elseif ie.code == 'terminate' then
|
||||
bExit = true
|
||||
break
|
||||
elseif sEvent == "key" then
|
||||
if param == keys.enter then
|
||||
-- Enter
|
||||
|
||||
elseif ie.code == 'enter' then
|
||||
break
|
||||
elseif param == keys.tab then
|
||||
if nPos == #sLine then
|
||||
local cline = autocomplete(sLine)
|
||||
|
||||
elseif ie.code == 'up' or ie.code == 'down' then
|
||||
if ie.code == 'up' then
|
||||
entry.value = history:back() or ''
|
||||
else
|
||||
entry.value = history:forward() or ''
|
||||
end
|
||||
entry.pos = string.len(entry.value)
|
||||
entry.scroll = 0
|
||||
entry:updateScroll()
|
||||
redraw()
|
||||
|
||||
elseif ie.code == 'tab' then
|
||||
if entry.pos == #entry.value then
|
||||
local cline = autocomplete(entry.value)
|
||||
if cline then
|
||||
sLine = cline
|
||||
nPos = #sLine
|
||||
redraw()
|
||||
end
|
||||
end
|
||||
elseif param == keys.left then
|
||||
if nPos > 0 then
|
||||
nPos = nPos - 1
|
||||
redraw()
|
||||
end
|
||||
elseif param == keys.right then
|
||||
if nPos < string.len(sLine) then
|
||||
redraw(" ")
|
||||
nPos = nPos + 1
|
||||
redraw()
|
||||
end
|
||||
elseif param == keys.up or param == keys.down then
|
||||
redraw(" ")
|
||||
if param == keys.up then
|
||||
sLine = history:back()
|
||||
else
|
||||
sLine = history:forward()
|
||||
end
|
||||
if sLine then
|
||||
nPos = string.len(sLine)
|
||||
else
|
||||
sLine = ""
|
||||
nPos = 0
|
||||
end
|
||||
redraw()
|
||||
elseif param == keys.backspace then
|
||||
if nPos > 0 then
|
||||
redraw(" ")
|
||||
sLine = string.sub( sLine, 1, nPos - 1 ) .. string.sub( sLine, nPos + 1 )
|
||||
nPos = nPos - 1
|
||||
redraw()
|
||||
end
|
||||
elseif param == keys.home then
|
||||
redraw(" ")
|
||||
nPos = 0
|
||||
redraw()
|
||||
elseif param == keys.delete then
|
||||
if nPos < string.len(sLine) then
|
||||
redraw(" ")
|
||||
sLine = string.sub( sLine, 1, nPos ) .. string.sub( sLine, nPos + 2 )
|
||||
redraw()
|
||||
end
|
||||
elseif param == keys["end"] then
|
||||
redraw(" ")
|
||||
nPos = string.len(sLine)
|
||||
redraw()
|
||||
end
|
||||
elseif sEvent == "term_resize" then
|
||||
w = term.getSize()
|
||||
entry.value = cline
|
||||
entry.pos = #entry.value
|
||||
entry:updateScroll()
|
||||
redraw()
|
||||
end
|
||||
end
|
||||
|
||||
local _, cy = term.getCursorPos()
|
||||
term.setCursorPos( w + 1, cy )
|
||||
elseif entry:process(ie) then
|
||||
redraw()
|
||||
end
|
||||
|
||||
elseif event == "term_resize" then
|
||||
entry.width = term.getSize() - 3
|
||||
redraw()
|
||||
end
|
||||
end
|
||||
|
||||
--local _, cy = term.getCursorPos()
|
||||
--term.setCursorPos( w + 1, cy )
|
||||
print()
|
||||
term.setCursorBlink( false )
|
||||
return sLine
|
||||
return entry.value
|
||||
end
|
||||
|
||||
local history = History.load('usr/.shell_history', 25)
|
||||
|
@ -1,4 +1,4 @@
|
||||
_G.requireInjector()
|
||||
_G.requireInjector(_ENV)
|
||||
|
||||
local Event = require('event')
|
||||
local Socket = require('socket')
|
||||
|
@ -1,4 +1,4 @@
|
||||
_G.requireInjector()
|
||||
_G.requireInjector(_ENV)
|
||||
|
||||
local Crypto = require('crypto')
|
||||
local Security = require('security')
|
||||
|
@ -1,4 +1,4 @@
|
||||
_G.requireInjector()
|
||||
_G.requireInjector(_ENV)
|
||||
|
||||
local Event = require('event')
|
||||
local Socket = require('socket')
|
||||
|
@ -13,13 +13,13 @@ kernel.hook('clipboard_copy', function(_, args)
|
||||
data = args[1]
|
||||
end)
|
||||
|
||||
keyboard.addHotkey('control-shift-paste', function(_, args)
|
||||
keyboard.addHotkey('shift-paste', function()
|
||||
if type(data) == 'table' then
|
||||
local s, m = pcall(textutils.serialize, data)
|
||||
data = (s and m) or Util.tostring(data)
|
||||
end
|
||||
-- replace the event paste data with our internal data
|
||||
args[1] = Util.tostring(data or '')
|
||||
-- args[1] = Util.tostring(data or '')
|
||||
if data then
|
||||
os.queueEvent('paste', data)
|
||||
end
|
||||
|
@ -4,7 +4,7 @@ local turtle = _G.turtle
|
||||
if turtle and modem then
|
||||
local s, m = turtle.run(function()
|
||||
|
||||
_G.requireInjector()
|
||||
_G.requireInjector(_ENV)
|
||||
|
||||
local Config = require('config')
|
||||
local config = {
|
||||
|
@ -1,14 +1,19 @@
|
||||
if _G.device.wireless_modem then
|
||||
|
||||
_G.requireInjector()
|
||||
_G.requireInjector(_ENV)
|
||||
local Config = require('config')
|
||||
|
||||
local kernel = _G.kernel
|
||||
|
||||
local config = { }
|
||||
Config.load('gps', config)
|
||||
|
||||
if config.host and type(config.host) == 'table' then
|
||||
_ENV._APP_TITLE = 'GPS Daemon'
|
||||
os.run(_ENV, '/rom/programs/gps', 'host', config.host.x, config.host.y, config.host.z)
|
||||
print('GPS daemon stopped')
|
||||
kernel.run({
|
||||
title = 'GPS Daemon',
|
||||
hidden = true,
|
||||
path = '/rom/programs/gps',
|
||||
args = { 'host', config.host.x, config.host.y, config.host.z },
|
||||
})
|
||||
end
|
||||
end
|
||||
|
@ -1,4 +1,4 @@
|
||||
_G.requireInjector()
|
||||
_G.requireInjector(_ENV)
|
||||
|
||||
local Util = require('util')
|
||||
|
||||
@ -10,7 +10,7 @@ local multishell = _ENV.multishell
|
||||
keyboard.addHotkey('control-o', function()
|
||||
for _,tab in pairs(multishell.getTabs()) do
|
||||
if tab.isOverview then
|
||||
multishell.setFocus(tab.tabId)
|
||||
multishell.setFocus(tab.uid)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
@ -10,20 +10,17 @@ local multishell = _ENV.multishell
|
||||
local os = _G.os
|
||||
local term = _G.term
|
||||
|
||||
local routine = kernel.getCurrent()
|
||||
if multishell then
|
||||
multishell.setTitle(multishell.getCurrent(), 'System Log')
|
||||
multishell.hideTab(routine.uid)
|
||||
end
|
||||
local function systemLog()
|
||||
local routine = kernel.getCurrent()
|
||||
|
||||
local w, h = kernel.window.getSize()
|
||||
kernel.window.reposition(1, 2, w, h - 1)
|
||||
local w, h = kernel.window.getSize()
|
||||
kernel.window.reposition(1, 2, w, h - 1)
|
||||
|
||||
routine.terminal = kernel.window
|
||||
routine.window = kernel.window
|
||||
term.redirect(kernel.window)
|
||||
routine.terminal = kernel.window
|
||||
routine.window = kernel.window
|
||||
term.redirect(kernel.window)
|
||||
|
||||
kernel.hook('mouse_scroll', function(_, eventData)
|
||||
kernel.hook('mouse_scroll', function(_, eventData)
|
||||
local dir, y = eventData[1], eventData[3]
|
||||
|
||||
if y > 1 then
|
||||
@ -36,16 +33,23 @@ kernel.hook('mouse_scroll', function(_, eventData)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
keyboard.addHotkey('control-d', function()
|
||||
keyboard.addHotkey('control-d', function()
|
||||
local current = kernel.getFocused()
|
||||
if current.uid ~= routine.uid then
|
||||
kernel.raise(routine.uid)
|
||||
elseif kernel.routines[2] then
|
||||
kernel.raise(kernel.routines[2].uid)
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
os.pullEventRaw('terminate')
|
||||
keyboard.removeHotkey('control-d')
|
||||
os.pullEventRaw('terminate')
|
||||
keyboard.removeHotkey('control-d')
|
||||
end
|
||||
|
||||
multishell.openTab({
|
||||
title = 'System Log',
|
||||
fn = systemLog,
|
||||
hidden = true,
|
||||
})
|
||||
|
@ -1,3 +0,0 @@
|
||||
term.clear()
|
||||
term.setCursorPos(1, 1)
|
||||
print(os.version())
|
@ -70,8 +70,8 @@ kernel.hook({ 'key', 'key_up', 'char', 'paste' }, function(event, eventData)
|
||||
-- and fire hotkeys
|
||||
local hotkey = Input:translate(event, eventData[1], eventData[2])
|
||||
|
||||
if hotkey and keyboard.hotkeys[hotkey] then
|
||||
keyboard.hotkeys[hotkey](event, eventData)
|
||||
if hotkey and keyboard.hotkeys[hotkey.code] then
|
||||
keyboard.hotkeys[hotkey.code](event, eventData)
|
||||
end
|
||||
end)
|
||||
|
||||
|
@ -2,7 +2,7 @@ if fs.native then
|
||||
return
|
||||
end
|
||||
|
||||
_G.requireInjector()
|
||||
_G.requireInjector(_ENV)
|
||||
local Util = require('util')
|
||||
|
||||
local fs = _G.fs
|
||||
|
@ -1,4 +1,4 @@
|
||||
_G.requireInjector()
|
||||
_G.requireInjector(_ENV)
|
||||
|
||||
local Util = require('util')
|
||||
|
||||
|
@ -2,7 +2,7 @@ if not _G.turtle then
|
||||
return
|
||||
end
|
||||
|
||||
_G.requireInjector()
|
||||
_G.requireInjector(_ENV)
|
||||
|
||||
local Pathing = require('turtle.pathfind')
|
||||
local GPS = require('gps')
|
||||
|
@ -1,4 +1,4 @@
|
||||
_G.requireInjector()
|
||||
_G.requireInjector(_ENV)
|
||||
|
||||
local Config = require('config')
|
||||
local Util = require('util')
|
||||
@ -199,6 +199,10 @@ kernel.hook('multishell_terminate', function(_, eventData)
|
||||
return true
|
||||
end)
|
||||
|
||||
kernel.hook('terminate', function()
|
||||
return kernel.getFocused().isOverview
|
||||
end)
|
||||
|
||||
kernel.hook('multishell_redraw', function()
|
||||
tabsDirty = false
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user