Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- vos.loadApi('core.api')
- vos.loadApi('ui.api')
- Logger.disable()
- local assert = vos.assert
- local commandBuffer = ''
- local commandCount
- local x, y = 1, 1
- local scrollx, scrolly = 0, 0
- local lines = {}
- local clipboard = nil
- local autoClearStatus = false
- local fileInfo = {
- modified = false,
- }
- -- forward declarations
- local keyMappings = { }
- local keyMapping
- local keyFunctions
- local function isAdvanced() return term.isColor and term.isColor() end
- local colorTheme = {
- editorBackground = "black",
- normal = {
- lineNumbersText = "gray",
- },
- highlight = {
- lineNumbersText = 'white',
- },
- textColor = "white",
- conditional = "yellow",
- constant = "red",
- ["function"] = "magenta",
- language = 'cyan',
- ["table"] = 'lime',
- string = "red",
- comment = "lime"
- }
- local standardTheme = {
- editorBackground = "black",
- editorLineHighlight = "black",
- editorLineNumbers = "black",
- editorLineNumbersHighlight = "white",
- editorError = "black",
- editorErrorHighlight = "black",
- textColor = "white",
- conditional = "white",
- constant = "white",
- ["function"] = "white",
- string = "white",
- comment = "white"
- }
- -- Load Theme
- local theme = standardTheme
- if isAdvanced() then
- theme = colorTheme
- end
- keywords = {
- ["and"] = "conditional",
- ["break"] = "conditional",
- ["do"] = "conditional",
- ["else"] = "conditional",
- ["elseif"] = "conditional",
- ["for"] = "conditional",
- ["if"] = "conditional",
- ["in"] = "conditional",
- ["local"] = "conditional",
- ["not"] = "conditional",
- ["or"] = "conditional",
- ["repeat"] = "conditional",
- ["return"] = "conditional",
- ["then"] = "conditional",
- ["until"] = "conditional",
- ["while"] = "conditional",
- --[[
- ['{'] = 'table',
- ['}'] = 'table',
- --]]
- ["function"] = "language",
- ["end"] = "language",
- ["pairs"] = "language",
- ["ipairs"] = "language",
- ["rawset"] = "language",
- ["rawget"] = "language",
- ["print"] = "language",
- ["true"] = "constant",
- ["false"] = "constant",
- ["nil"] = "constant",
- ["write"] = "function",
- ["sleep"] = "function",
- ["loadstring"] = "function",
- ["loadfile"] = "function",
- ["dofile"] = "function",
- ["setfenv"] = "function",
- ["getfenv"] = "function",
- }
- local standardsCompletions = {
- "if%s+.+%s+then%s*$",
- "for%s+.+%s+do%s*$",
- "while%s+.+%s+do%s*$",
- "repeat%s*$",
- "function%s+[a-zA-Z_0-9]?\(.*\)%s*$",
- "=%s*function%s*\(.*\)%s*$",
- "else%s*$",
- "elseif%s+.+%s+then%s*$"
- }
- local liveCompletions = {
- ["("] = ")",
- ["{"] = "}",
- ["["] = "]",
- ["\""] = "\"",
- ["'"] = "'",
- }
- local function hackyRead()
- -- stops read from scrolling screen
- local oldPrint = _G.print
- _G.print = function() end
- local result = read()
- _G.print = oldPrint
- result = Util.trim(result)
- if #result > 0 then
- return result
- end
- end
- local editor = UI.Page({
- settings = {
- tabWidth = 2,
- },
- gutter = UI.Window({
- width = 3,
- height = UI.term.height - 1,
- }),
- editArea = UI.Window({
- x = 4,
- y = 1,
- width = UI.term.width - 3,
- height = UI.term.height - 1,
- dirty = { },
- focus = function() end,
- }),
- statusBar = UI.StatusBar({
- backgroundColor = colors.black,
- columns = {
- { '', 'status', UI.term.width - 10 },
- { '', 'cursor', 8 }
- },
- }),
- })
- local gutter = editor.gutter
- local editArea = editor.editArea
- local statusBar = editor.statusBar
- function editor:draw()
- term.setCursorBlink(false)
- term.setBackgroundColor(colors.black)
- editArea:draw()
- statusBar:draw()
- term.setTextColor(colors[theme.textColor])
- term.setCursorPos(x - scrollx + editArea.x - 1, y - scrolly)
- term.setCursorBlink(true)
- end
- function editor:flashScreen()
- term.setBackgroundColor(colors.lightGray)
- term.clear()
- os.sleep(0)
- editArea:markScreenDirty()
- end
- --[[ STATUSBAR AREA ]]--
- function statusBar:showMessage(str, ...)
- assert('statusBar:showMessage', {
- { 'string', str },
- })
- self:setValue('status', str:format(...))
- self:draw()
- end
- function statusBar:clearMessage()
- self:showMessage('')
- end
- function statusBar:showError(status)
- term.setCursorPos(1, statusBar.y)
- term.setBackgroundColor(colors.red)
- term.setTextColor(colors.white)
- term.write(status)
- term.setBackgroundColor(colors[theme.editorBackground])
- end
- function statusBar:draw()
- if commandBuffer or commandCount then
- self:setValue('cursor', tostring(commandCount or 1) .. tostring(commandBuffer or ''))
- else
- self:setValue('cursor', string.format('%d,%d', y, x))
- end
- UI.StatusBar.draw(self)
- end
- --[[ EDIT AREA ]]--
- function editArea:attemptToHighlight(line, regex, col)
- local match = string.match(line, regex)
- if match then
- if type(col) == "number" then
- term.setTextColor(col)
- elseif type(col) == "function" then
- term.setTextColor(col(match))
- end
- term.write(match)
- term.setTextColor(colors[theme.textColor])
- return line:sub(match:len() + 1, -1)
- end
- return nil
- end
- function editArea:writeHighlighted(line)
- while line:len() > 0 do
- line = self:attemptToHighlight(line, "^%-%-%[%[.-%]%]", colors[theme.comment]) or
- self:attemptToHighlight(line, "^%-%-.*", colors[theme.comment]) or
- self:attemptToHighlight(line, "^\".*[^\\]\"", colors[theme.string]) or
- self:attemptToHighlight(line, "^\'.*[^\\]\'", colors[theme.string]) or
- self:attemptToHighlight(line, "^%[%[.-%]%]", colors[theme.string]) or
- self:attemptToHighlight(line, "^[%w_]+", function(match)
- if keywords[match] then
- return colors[theme[keywords[match]]]
- end
- return colors[theme.textColor]
- end) or
- self:attemptToHighlight(line, "^[^%w_]", colors[theme.textColor])
- end
- end
- function editArea:drawLine(ly)
- if (ly - scrolly < 1) or (ly - scrolly > editArea.height) then
- return
- end
- term.setCursorPos(1, ly - scrolly)
- if ly <= #lines then
- local _colors = theme.normal
- if ly == y then
- _colors = theme.highlight
- end
- term.setTextColor(colors[_colors.lineNumbersText])
- local ln = string.rep(" ", gutter.width - 1 - tostring(ly):len()) .. tostring(ly)
- term.write(ln .. ' ')
- local a = lines[ly]
- local totalWidth = self.width
- if scrollx > 0 then
- totalWidth = self.width + scrollx
- term.setCursorPos(1 - scrollx + self.x, ly - scrolly)
- end
- self:writeHighlighted(a)
- if #a < totalWidth then
- term.write(string.rep(' ', totalWidth - #a))
- end
- else
- term.clearLine()
- end
- end
- function editArea:drawDirty()
- local keys = Util.keys(self.dirty)
- for _,lineNo in pairs(keys) do
- self:drawLine(lineNo)
- self.dirty[lineNo] = nil
- end
- end
- function editArea:markDirty(ls)
- assert('editor:markDirty', {
- { 'table', ls },
- })
- for _, ly in pairs(ls) do
- self.dirty[ly] = true
- end
- end
- function editArea:markSubsequentDirty(lineNo)
- for i = lineNo - scrolly, self.height do
- self.dirty[i + scrolly] = true
- end
- end
- function editArea:markScreenDirty()
- for i = 1, self.height do
- self.dirty[scrolly + i] = true
- end
- if autoClearStatus then
- statusBar:setValue('status', '')
- end
- end
- function editArea:draw()
- local gutterWidth = math.max(tostring(#lines):len() + 1, 3)
- if gutterWidth ~= gutter.width then
- gutter.width = gutterWidth
- editArea.width = editor.width - gutter.width
- editArea.x = gutter.width + 1
- self:markScreenDirty()
- end
- if not Util.empty(self.dirty) then
- --local ds = 'ds: ' .. table.concat(Util.keys(self.dirty), ',')
- --editor.statusBar:setValue('status', ds)
- self:drawDirty()
- end
- end
- function editArea:cursorLoc(newX, newY)
- if newY > #lines then
- newY = #lines
- elseif newY < 1 then
- newY = 1
- end
- if y ~= newY then
- self:markDirty({ y, newY })
- end
- y = newY
- if newX < 1 then
- newX = 1
- elseif newX > #lines[y] + 1 then
- newX = #lines[y] + 1
- end
- x = newX
- if y > #lines then
- y = #lines
- end
- local force = false
- local sx, sy = x - scrollx, y - scrolly
- local oscrollx, oscrolly = scrollx, scrolly
- if sx < 1 then
- scrollx = x - 1
- force = true
- elseif sx > self.width then
- scrollx = x - self.width
- force = true
- end
- if sy < 1 then
- scrolly = y - 1
- elseif sy > self.height then
- scrolly = y - self.height
- end
- local scrolledy = scrolly - oscrolly
- if (math.abs(scrolledy) >= self.height) then
- force = true
- end
- if force or scrolledy ~= 0 then
- if autoClearStatus then
- editor.statusBar:setValue('status', '')
- end
- end
- if force then
- self:markScreenDirty()
- elseif scrolledy ~= 0 then
- term.scroll(scrolledy)
- if scrolledy > 0 then
- statusBar:clear()
- -- term.setCursorPos(1, statusBar.y)
- -- term.clearLine()
- self:markSubsequentDirty(scrolly + self.height - scrolledy + 1)
- else
- for i = -1, scrolledy, -1 do
- self:markDirty({ scrolly - i })
- end
- end
- end
- end
- function getFileInfo(path)
- local abspath = "/" .. shell.resolve(path)
- local fi = {
- abspath = abspath,
- path = path,
- name = fs.getName(path),
- dir = fs.getDir(abspath),
- isNew = not fs.exists(abspath),
- isDir = fs.isDir(path),
- dirExists = fs.exists(fs.getDir(abspath)),
- modified = false,
- }
- if fi.isDir then
- fi.isReadOnly = true
- else
- fi.isReadOnly = fs.isReadOnly(fi.abspath)
- end
- return fi
- end
- function resetCommandBuffer()
- commandBuffer = nil
- commandCount = nil
- end
- function newFile()
- local fi = {
- isNew = true,
- isDir = false,
- dirExists = false,
- modified = false,
- isReadOnly = false,
- }
- end
- function load(path)
- fileInfo = getFileInfo(path)
- if fileInfo.isNew then
- lines = { '' }
- else
- if fileInfo.isDir then
- lines = fs.list(fileInfo.abspath)
- else
- lines = Util.readLines(fileInfo.abspath) or { '' }
- end
- end
- multishell.setTitle(TAB_ID, fileInfo.name)
- editArea:markScreenDirty()
- local status = fileInfo.path
- if fileInfo.isNew then
- if not fileInfo.dirExists then
- statusBar:showMessage('"%s" [New DIRECTORY]', path)
- else
- statusBar:showMessage('"%s" [New File]', path)
- end
- elseif fileInfo.isDir then
- statusBar:showMessage('"%s" is a directory')
- elseif fileInfo.isReadOnly then
- statusBar:showMessage('"%s" [readonly] %dL, %dC',
- path, #lines, fs.getSize(fileInfo.abspath))
- else
- statusBar:showMessage('"%s" %dL, %dC',
- path, #lines, fs.getSize(fileInfo.abspath))
- end
- end
- local function saveFile(path)
- local dir = path:sub(1, path:len() - fs.getName(path):len())
- if not fs.exists(dir) then
- fs.makeDir(dir)
- end
- if fs.isDir(path) then
- return false, string.format('"%s" is a directory', path)
- end
- if fs.isReadOnly(path) then
- return false, string.format('"%s" is read only', path)
- end
- if not Util.writeLines(path, lines) then
- return false, string.format('Error saving "%s"', path)
- end
- return true
- end
- keyFunctions = {
- commandMode = function()
- statusBar:clearMessage()
- autoClearStatus = true
- keyMapping = keyMappings['vi-command']
- end,
- insertMode = function(event)
- statusBar:showMessage('-- INSERT --')
- autoClearStatus = false
- keyMapping = keyMappings['vi-insert']
- if event.key == 'a' then
- keyFunctions.right()
- elseif event.key == 'A' then
- keyFunctions.lineEnd()
- elseif event.key == 'o' then
- keyFunctions.appendLine()
- elseif event.key == 'O' then
- keyFunctions.insertLine()
- end
- end,
- up = function(event)
- if y > 1 then
- editArea:cursorLoc(x, y - (event.count or 1))
- return true
- end
- end,
- down = function(event)
- if y < #lines then
- editArea:cursorLoc(x, y + (event.count or 1))
- return true
- end
- end,
- left = function(event)
- if x > 1 then
- editArea:cursorLoc(x - (event.count or 1), y)
- return true
- end
- end,
- right = function(event)
- if x < lines[y]:len() + 1 then
- editArea:cursorLoc(x + (event.count or 1), y)
- return true
- end
- end,
- leftWrap = function()
- if x > 1 then
- editArea:cursorLoc(x - 1, y)
- return true
- end
- if y > 1 then
- editArea:cursorLoc(#lines[y - 1] + 1, y - 1)
- return true
- end
- end,
- rightWrap = function()
- if x < lines[y]:len() + 1 then
- editArea:cursorLoc(x + 1, y)
- return true
- end
- if y < #lines then
- editArea:cursorLoc(1, y + 1)
- return true
- end
- end,
- home = function()
- editArea:cursorLoc(1, y)
- return true
- end,
- lineEnd = function()
- editArea:cursorLoc(lines[y]:len() + 1, y)
- return true
- end,
- gotoLine = function(event)
- if not event.count then
- editArea:cursorLoc(1, #lines)
- return true
- end
- if event.count > #lines then
- return false
- end
- editArea:cursorLoc(1, event.count)
- return true
- end,
- pageUp = function()
- if scrolly > 0 then
- editArea:cursorLoc(x, math.min(math.max(y - editArea.height, 1), #lines))
- return true
- end
- end,
- pageDown = function()
- editArea:cursorLoc(x, math.min(math.max(y + editArea.height, 1), #lines))
- end,
- quit = function(event)
- if fileInfo.modified and event.key ~= ':q!' then
- return false, 'No write since last change (add ! to override)'
- end
- Event.exitPullEvents()
- return #event.key
- end,
- abort = function()
- Event.exitPullEvents()
- end,
- status = function()
- local path = fileInfo.path or '[No Name]'
- if #lines == 0 then
- statusBar:showMessage('"%s" -- No lines in buffer --', path)
- else
- statusBar:showMessage('"%s" %d lines --%d%%--',
- fileInfo.path, #lines, math.floor(y/#lines*100))
- end
- return true
- end,
- save = function()
- saveFile(fileInfo.abspath)
- statusBar:showMessage('"%s" %dL, %dC written',
- fileInfo.path, #lines, fs.getSize(fileInfo.abspath))
- end,
- cutLine = function()
- clipboard = lines[y]
- table.remove(lines, y)
- editArea:markSubsequentDirty(y)
- editArea:cursorLoc(1, y)
- fileInfo.modified = true
- end,
- copyLines = function(event)
- clipboard = { }
- local count = math.min(event.count or 1, #lines - y)
- for i = 1, event.count do
- table.insert(clipboard, lines[y + i - 1])
- end
- statusBar:showMessage('%d lines yanked', count)
- end,
- appendLine = function()
- table.insert(lines, y + 1, '')
- editArea:markSubsequentDirty(y + 1)
- editArea:cursorLoc(1, y + 1)
- fileInfo.modified = true
- end,
- insertLine = function()
- table.insert(lines, y, '')
- editArea:markSubsequentDirty(y)
- editArea:cursorLoc(1, y)
- fileInfo.modified = true
- end,
- enter = function()
- local f = nil
- local oldy = y
- for _, v in pairs(standardsCompletions) do
- if lines[y]:find(v) then f = v end
- end
- local _, spaces = lines[y]:find("^[ ]+")
- if not spaces then spaces = 0 end
- if f then
- table.insert(lines, y + 1, string.rep(" ", spaces + 2))
- if not f:find("else", 1, true) and not f:find("elseif", 1, true) then
- table.insert(lines, y + 2, string.rep(" ", spaces) ..
- (f:find("repeat", 1, true) and "until " or f:find("{", 1, true) and "}" or "end"))
- end
- editArea:cursorLoc(spaces + 3, y + 1)
- else
- local oldLine = lines[y]
- lines[y] = lines[y]:sub(1, x - 1)
- table.insert(lines, y + 1, string.rep(" ", spaces) .. oldLine:sub(x, -1))
- editArea:cursorLoc(spaces + 1, y + 1)
- end
- editArea:markSubsequentDirty(oldy)
- fileInfo.modified = true
- end,
- backspace = function()
- if x > 1 then
- local f = false
- for k, v in pairs(liveCompletions) do
- if lines[y]:sub(x - 1, x - 1) == k then f = true end
- end
- lines[y] = lines[y]:sub(1, x - 2) .. lines[y]:sub(x + (f and 1 or 0), -1)
- editArea:markDirty({ y })
- editArea:cursorLoc(x - 1, y)
- fileInfo.modified = true
- elseif y > 1 then
- local prevLen = lines[y - 1]:len() + 1
- lines[y - 1] = lines[y - 1] .. lines[y]
- table.remove(lines, y)
- editArea:markSubsequentDirty(y - 1)
- editArea:cursorLoc(prevLen, y - 1)
- fileInfo.modified = true
- end
- end,
- delete = function()
- if x < lines[y]:len() + 1 then
- lines[y] = lines[y]:sub(1, x - 1) .. lines[y]:sub(x + 1)
- editArea:markDirty({ y })
- -- editArea:cursorLoc(x, y)
- fileInfo.modified = true
- elseif y < #lines then
- lines[y] = lines[y] .. lines[y + 1]
- table.remove(lines, y + 1)
- editArea:markSubsequentDirty(y)
- -- editArea:cursorLoc(x, y)
- fileInfo.modified = true
- end
- end,
- deleteToEnd = function()
- lines[y] = lines[y]:sub(1, x - 1)
- editArea:markDirty({ y })
- editArea:cursorLoc(#lines[y], y)
- fileInfo.modified = true
- end,
- tab = function()
- lines[y] = string.rep(" ", editor.settings.tabWidth) .. lines[y]
- editArea:markDirty({ y })
- editArea:cursorLoc(x + 2, y)
- fileInfo.modified = true
- end,
- insertCharacter = function(event)
- local key = event.key
- local shouldIgnore = false
- for k, v in pairs(liveCompletions) do
- if key == v and lines[y]:find(k, 1, true) and lines[y]:sub(x, x) == v then
- shouldIgnore = true
- end
- end
- local addOne = false
- if not shouldIgnore then
- for k, v in pairs(liveCompletions) do
- if key == k and lines[y]:sub(x, x) ~= k then
- key = key .. v
- addOne = true
- end
- end
- lines[y] = lines[y]:sub(1, x - 1) .. key .. lines[y]:sub(x, -1)
- end
- editArea:markDirty({ y })
- editArea:cursorLoc(x + (addOne and 1 or key:len()), y)
- fileInfo.modified = true
- end,
- pasteLine = function()
- if clipboard then
- table.insert(lines, y, clipboard)
- editArea:markSubsequentDirty(y)
- statusBar:showMessage('1 more line')
- fileInfo.modified = true
- end
- end,
- nextWord = function()
- local str = lines[y]
- local result = { str:find("(%w+)", x) }
- if #result > 0 and result[1] == x then
- result = { str:find("(%w+)", result[2] + 1) }
- end
- if #result > 0 then
- if #result > 0 then
- editArea:cursorLoc(result[1], y)
- end
- elseif #result == 0 and y < #lines then
- local nx
- result = { lines[y + 1]:find("(%w+)", 1) }
- if #result == 0 then
- nx = 1
- else
- nx = result[1]
- end
- editArea:cursorLoc(nx, y + 1)
- end
- end,
- deleteLines = function(event)
- clipboard = { }
- for i = 1, (event.count or 1) do
- table.insert(clipboard, lines[y])
- table.remove(lines, y)
- end
- if #lines == 0 then
- table.insert(lines, '')
- end
- editArea:cursorLoc(1, y)
- editArea:markSubsequentDirty(y)
- fileInfo.modified = true
- end,
- pasteLinesBefore = function()
- if clipboard and type(clipboard) == 'table' then
- for i = 1, #clipboard do
- table.insert(lines, y + i - 1, clipboard[i])
- end
- editArea:cursorLoc(1, y)
- editArea:markSubsequentDirty(y)
- fileInfo.modified = true
- end
- end,
- searchPrompt = function()
- term.setCursorPos(1, statusBar.y)
- term.write('/')
- hackyRead()
- end,
- nextLine = function()
- if y < #lines then
- editArea:cursorLoc(1, y + 1)
- end
- end,
- write = function(event)
- local fi = fileInfo
- if event.args then
- fi = getFileInfo(event.args)
- end
- if fi.isReadOnly then
- return false, "'readonly' option is set"
- end
- if event.args and fs.exists(fi.path) and not event.key:find(1, '!', true) then
- return false, 'File exists (add ! to override)'
- end
- local success, msg = saveFile(fi.path)
- if not success then
- return false, msg
- end
- fi.modified = false
- statusBar:showMessage('"%s" %dL, %dC written',
- filename, #lines, fs.getSize(filename))
- if event.key:sub(2, 1) == '!' then
- return 2
- end
- return 1
- end,
- colonPrompt = function(event)
- term.setCursorPos(1, statusBar.y)
- term.clearLine()
- term.write(':')
- local cmd = hackyRead()
- statusBar:clearMessage()
- if cmd then
- local words = Util.toWords(cmd)
- local cmd = words[1]
- local index = 1
- repeat
- local subcmd = ':' .. cmd:sub(index, 1)
- if not keyMapping[subcmd] then
- statusBar:showError('Invalid command')
- break
- end
- event.key = ':' .. cmd:sub(index)
- event.args = words[2]
- local inc, msg = keyMapping[subcmd](event)
- if not inc then
- statusBar:showError(msg)
- break
- end
- index = index + inc
- until index > #cmd
- end
- end,
- refresh = function()
- editArea:markScreenDirty()
- end,
- insertTranslate = function(event)
- if #event.key == 1 then
- return keyFunctions.insertCharacter
- end
- return keyMapping[event.key]
- end,
- commandTranslate = function(event)
- local filterKeys = {
- [ 'leftCtrl' ] = true,
- [ 'leftAlt' ] = true,
- [ 'leftShift' ] = true,
- [ ' ' ] = true,
- }
- if filterKeys[event.key] then
- return function() return true end
- end
- if commandBuffer and #event.key > 1 then
- return resetCommandBuffer
- end
- if #event.key == 1 then
- local ch = tonumber(event.key)
- if ch then
- if commandCount then
- commandCount = commandCount * 10 + ch
- else
- commandCount = ch
- end
- commandBuffer = nil
- return
- end
- if not commandBuffer then
- commandBuffer = event.key
- else
- commandBuffer = commandBuffer .. event.key
- end
- event.key = commandBuffer
- end
- local fn = keyMapping[event.key]
- if fn then
- event.count = commandCount
- commandBuffer = nil
- commandCount = nil
- return fn
- end
- for k,_ in pairs(keyMapping) do
- if k:find('^' .. event.key) then
- return
- end
- end
- --statusBar:showMessage(tostring(event.key))
- --autoClearStatus = false
- return resetCommandBuffer
- end,
- }
- local commonKeyMapping = {
- [ 'up' ] = keyFunctions.up,
- [ 'down' ] = keyFunctions.down,
- [ 'left' ] = keyFunctions.left,
- [ 'right' ] = keyFunctions.right,
- [ 'home' ] = keyFunctions.home,
- [ 'end' ] = keyFunctions.lineEnd,
- [ 'pageUp' ] = keyFunctions.pageUp,
- [ 'pageDown' ] = keyFunctions.pageDown,
- [ 'control-t' ] = keyFunctions.abort,
- }
- local colonCommands = {
- [ 'w' ] = keyFunctions.write,
- [ 'r' ] = keyFunctions.notImplemented,
- [ 'e' ] = keyFunctions.notImplemented,
- [ 'vi' ] = keyFunctions.notImplemented,
- [ '!!' ] = keyFunctions.notImplemented,
- [ '^!(%S)' ] = keyFunctions.run,
- [ 'sh' ] = keyFunctions.notImplemented,
- [ 'set' ] = keyFunctions.notImplemented,
- [ 'q' ] = keyFunctions.quit,
- }
- local keyMappingsSource = {
- [ 'vi-command' ] = {
- [ 'translate' ] = keyFunctions.commandTranslate,
- -- insert
- [ 'i' ] = keyFunctions.insertMode,
- [ 'I' ] = keyFunctions.notImplemented,
- [ 'a' ] = keyFunctions.insertMode,
- [ 'A' ] = keyFunctions.insertMode,
- [ 'o' ] = keyFunctions.insertMode,
- [ 'O' ] = keyFunctions.insertMode,
- [ 'r' ] = keyFunctions.notImplemented,
- [ 'R' ] = keyFunctions.notImplemented,
- -- motion
- [ 'h' ] = keyFunctions.left,
- [ 'j' ] = keyFunctions.down,
- [ 'k' ] = keyFunctions.up,
- [ 'l' ] = keyFunctions.right,
- [ 'w' ] = keyFunctions.nextWord,
- [ 'b' ] = keyFunctions.notImplemented,
- [ '^' ] = keyFunctions.notImplemented,
- [ 'space' ] = keyFunctions.rightWrap,
- [ '0' ] = keyFunctions.home,
- [ '$' ] = keyFunctions.lineEnd,
- [ 'G' ] = keyFunctions.gotoLine,
- [ 'control-f' ] = keyFunctions.pageDown,
- [ 'control-b' ] = keyFunctions.pageUp,
- [ 'backspace' ] = keyFunctions.leftWrap,
- -- deleting
- [ 'x' ] = keyFunctions.delete,
- [ 'X' ] = keyFunctions.notImplemented,
- [ 'D' ] = keyFunctions.deleteToEnd,
- [ 'dd' ] = keyFunctions.deleteLines,
- [ 'dw' ] = keyFunctions.notImplemented,
- -- status
- [ 'control-g' ] = keyFunctions.status,
- -- paste
- [ 'p' ] = keyFunctions.pasteLinesAfter,
- [ 'P' ] = keyFunctions.pasteLinesBefore,
- [ 'yy' ] = keyFunctions.copyLines,
- -- changing text
- [ 'C' ] = keyFunctions.notImplemented,
- [ 'cc' ] = keyFunctions.notImplemented,
- [ 'cw' ] = keyFunctions.notImplemented,
- -- searching
- [ 'n' ] = keyFunctions.notImplemented,
- [ 'N' ] = keyFunctions.notImplemented,
- [ '/' ] = keyFunctions.searchPrompt,
- [ 'enter' ] = keyFunctions.nextLine,
- [ ':' ] = keyFunctions.colonPrompt,
- [ 'ZZ' ] = keyFunctions.notImplemented,
- [ 'control-l' ] = keyFunctions.refresh,
- },
- [ 'vi-insert' ] = {
- [ 'leftAlt' ] = keyFunctions.commandMode,
- [ 'enter' ] = keyFunctions.enter,
- [ 'backspace' ] = keyFunctions.backspace,
- [ 'delete' ] = keyFunctions.delete,
- [ 'tab' ] = keyFunctions.tab,
- [ 'default' ] = keyFunctions.default,
- [ 'translate' ] = keyFunctions.insertTranslate,
- },
- [ 'fullscreen' ] = {
- [ 'control-g' ] = keyFunctions.status,
- [ 'control-s' ] = keyFunctions.save,
- [ 'control-x' ] = keyFunctions.cutLine,
- [ 'control-c' ] = keyFunctions.copyLines,
- [ 'contol-v' ] = keyFunctions.pasteLine,
- [ 'right' ] = keyFunctions.rightWrap,
- [ 'left' ] = keyFunctions.leftWrap,
- [ 'enter' ] = keyFunctions.enter,
- [ 'backspace' ] = keyFunctions.backspace,
- [ 'delete' ] = keyFunctions.delete,
- [ 'tab' ] = keyFunctions.tab,
- [ 'default' ] = keyFunctions.default,
- },
- }
- for k,v in pairs(keyMappingsSource) do
- keyMappings[k] = Util.shallowCopy(commonKeyMapping)
- Util.merge(keyMappings[k], v)
- end
- keyMapping = keyMappings['vi-command']
- function editArea:eventHandler(event)
- if event.type == 'paste' then
- event.type = 'key'
- event.key = 'contol-v'
- end
- if event.type == 'key' then
- local fn = keyMapping.translate(event)
- if fn then
- if not fn(event) then
- editor:flashScreen()
- end
- end
- elseif event.type == "mouse_click" then
- editArea:cursorLoc(scrollx + event.x, scrolly + event.y)
- else
- return false
- end
- editor:draw()
- return true
- end
- local function main(arguments)
- if #arguments > 0 then
- load(arguments[1])
- else
- newFile()
- end
- term.setBackgroundColor(colors[theme.editorBackground])
- UI.pager:setPage(editor)
- -- autoClearStatus = true
- Event.pullEvents()
- end
- local args = {...}
- local _, err = pcall(function()
- main(args)
- end)
- term.setTextColor(colors.white)
- if not err then
- term.clear()
- term.setCursorPos(1, 1)
- end
- -- Catch errors
- if err and not err:find("Terminated") then
- print(err)
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement