opus/sys/apis/entry.lua

254 lines
5.6 KiB
Lua

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
local function prevWord(line, cx)
local nOffset = 1
while nOffset <= #line do
local nNext = line:find("%W%w", nOffset)
if nNext and nNext < cx then
nOffset = nNext + 1
else
break
end
end
return nOffset - 1 < cx and nOffset - 1
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
local function moveLeft(entry)
if entry.pos > 0 then
entry.pos = math.max(entry.pos - 1, 0)
return true
end
end
local function moveRight(entry)
local input = tostring(entry.value)
if entry.pos < #input then
entry.pos = math.min(entry.pos + 1, #input)
return true
end
end
local function moveStart(entry)
if entry.pos ~= 0 then
entry.pos = 0
return true
end
end
local function moveEnd(entry)
if entry.pos ~= #tostring(entry.value) then
entry.pos = #tostring(entry.value)
return true
end
end
local function backspace(entry)
if entry.pos > 0 then
local input = tostring(entry.value)
entry.value = input:sub(1, entry.pos - 1) .. input:sub(entry.pos + 1)
entry.pos = entry.pos - 1
return true
end
end
local function moveWordRight(entry)
local nx = nextWord(entry.value, entry.pos + 1)
if nx then
entry.pos = math.min(nx - 1, #entry.value)
elseif entry.pos < #entry.value then
entry.pos = #entry.value
end
return true
end
local function moveWordLeft(entry)
if entry.pos ~= 0 then
local lx = 1
while true do
local nx = nextWord(entry.value, lx)
if not nx or nx >= entry.pos then
break
end
lx = nx
end
if not lx then
entry.pos = 0
else
entry.pos = lx - 1
end
return true
end
end
local function delete(entry)
local input = tostring(entry.value)
if entry.pos < #input then
entry.value = input:sub(1, entry.pos) .. input:sub(entry.pos + 2)
entry.update = true
return true
end
end
-- credit for cut functions to: https://github.com/SquidDev-CC/mbs/blob/master/lib/readline.lua
local function cutFromStart(entry)
if entry.pos > 0 then
local input = tostring(entry.value)
os.queueEvent('clipboard_copy', input:sub(1, entry.pos))
entry.value = input:sub(entry.pos + 1)
entry.pos = 0
return true
end
end
local function cutToEnd(entry)
local input = tostring(entry.value)
if entry.pos < #input then
os.queueEvent('clipboard_copy', input:sub(entry.pos + 1))
entry.value = input:sub(1, entry.pos)
return true
end
end
local function cutNextWord(entry)
local input = tostring(entry.value)
if entry.pos < #input then
local ex = nextWord(entry.value, entry.pos)
if ex then
os.queueEvent('clipboard_copy', input:sub(entry.pos + 1, ex))
entry.value = input:sub(1, entry.pos) .. input:sub(ex + 1)
return true
end
end
end
local function cutPrevWord(entry)
if entry.pos > 0 then
local sx = prevWord(entry.value, entry.pos)
if sx then
local input = tostring(entry.value)
os.queueEvent('clipboard_copy', input:sub(sx + 1, entry.pos))
entry.value = input:sub(1, sx) .. input:sub(entry.pos + 1)
entry.pos = sx
return true
end
end
end
local function insertChar(entry, ie)
local input = tostring(entry.value)
if #input < entry.limit then
entry.value = input:sub(1, entry.pos) .. ie.ch .. input:sub(entry.pos + 1)
entry.pos = entry.pos + 1
entry.update = true
return true
end
end
local function copy(entry)
os.queueEvent('clipboard_copy', entry.value)
end
local function paste(entry, ie)
local input = tostring(entry.value)
if #input + #ie.text > entry.limit then
ie.text = ie.text:sub(1, entry.limit-#input)
end
entry.value = input:sub(1, entry.pos) .. ie.text .. input:sub(entry.pos + 1)
entry.pos = entry.pos + #ie.text
return true
end
local function moveCursor(entry, ie)
-- need starting x passed in instead of hardcoding 3
entry.pos = math.max(0, math.min(ie.x - 3 + entry.scroll, #entry.value))
return true
end
local function clearLine(entry)
local input = tostring(entry.value)
if #input > 0 then
entry:reset()
return true
end
end
local mappings = {
[ 'left' ] = moveLeft,
[ 'control-b' ] = moveLeft,
[ 'right' ] = moveRight,
[ 'control-f' ] = moveRight,
[ 'home' ] = moveStart,
[ 'control-a' ] = moveStart,
[ 'end' ] = moveEnd,
[ 'control-e' ] = moveEnd,
[ 'backspace' ] = backspace,
[ 'control-right' ] = moveWordRight,
[ 'alt-f' ] = moveWordRight,
[ 'control-left' ] = moveWordLeft,
[ 'alt-b' ] = moveWordLeft,
[ 'delete' ] = delete,
[ 'control-u' ] = cutFromStart,
[ 'control-k' ] = cutToEnd,
[ 'control-d' ] = cutNextWord,
[ 'control-w' ] = cutPrevWord,
[ 'char' ] = insertChar,
[ 'copy' ] = copy,
[ 'paste' ] = paste,
[ 'control-y' ] = paste,
[ 'mouse_click' ] = moveCursor,
[ 'mouse_rightclick' ] = clearLine,
}
function Entry:process(ie)
local action = mappings[ie.code]
local updated
if action then
updated = action(self, ie)
end
self:updateScroll()
return updated
end
return Entry