daily pastebin goal
60%
SHARE
TWEET

buggy synedit

ecoMeco Nov 15th, 2016 288 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. local event = require("event")
  2. local fs = require("filesystem")
  3. local keyboard = require("keyboard")
  4. local shell = require("shell")
  5. local term = require("term")
  6. local text = require("text")
  7. local unicode = require("unicode")
  8.  
  9. -- SYNEDIT MODIFICATIONS start
  10.  
  11. --Monokai color scheme
  12. local bgColor = 0x272822
  13. local textColor = 0xF8F8F2
  14. local highlightColor = 0xF92672
  15. local keywordColor = 0xF92672
  16. local commentColor = 0x75715E
  17. local stringColor = 0xE6DB74
  18. local numberColor = 0xAE81FF
  19.  
  20. local tKeywords = {
  21.     ["and"] = true,
  22.     ["break"] = true,
  23.     ["do"] = true,
  24.     ["else"] = true,
  25.     ["elseif"] = true,
  26.     ["end"] = true,
  27.     ["false"] = true,
  28.     ["for"] = true,
  29.     ["function"] = true,
  30.     ["if"] = true,
  31.     ["in"] = true,
  32.     ["local"] = true,
  33.     ["nil"] = true,
  34.     ["not"] = true,
  35.     ["or"] = true,
  36.     ["repeat"] = true,
  37.     ["return"] = true,
  38.     ["then"] = true,
  39.     ["true"] = true,
  40.     ["until"] = true,
  41.     ["while"] = true,
  42.  
  43.     --Doesn't work for some reason...
  44.     ["+"] = true,
  45.     ["-"] = true,
  46.     ["*"] = true,
  47.     ["/"] = true,
  48.     ["="] = true,
  49. }
  50. --SYNEDIT MODIFICATIONS end
  51.  
  52. if not term.isAvailable() then
  53.   return
  54. end
  55. local gpu = term.gpu()
  56. local args, options = shell.parse(...)
  57. if #args == 0 then
  58.   io.write("Usage: edit <filename>")
  59.   return
  60. end
  61.  
  62. local filename = shell.resolve(args[1])
  63.  
  64. local readonly = options.r or fs.get(filename) == nil or fs.get(filename).isReadOnly()
  65.  
  66. if not fs.exists(filename) then
  67.   if fs.isDirectory(filename) then
  68.     io.stderr:write("file is a directory\n")
  69.     return 1
  70.   elseif readonly then
  71.     io.stderr:write("file system is read only\n")
  72.     return 1
  73.   end
  74. end
  75.  
  76. local function loadConfig()
  77.   -- Try to load user settings.
  78.   local env = {}
  79.   local config = loadfile("/etc/edit.cfg", nil, env)
  80.   if config then
  81.     pcall(config)
  82.   end
  83.   -- Fill in defaults.
  84.   env.keybinds = env.keybinds or {
  85.     left = {{"left"}},
  86.     right = {{"right"}},
  87.     up = {{"up"}},
  88.     down = {{"down"}},
  89.     home = {{"home"}},
  90.     eol = {{"end"}},
  91.     pageUp = {{"pageUp"}},
  92.     pageDown = {{"pageDown"}},
  93.  
  94.     backspace = {{"back"}},
  95.     delete = {{"delete"}},
  96.     deleteLine = {{"control", "delete"}, {"shift", "delete"}},
  97.     newline = {{"enter"}},
  98.  
  99.     save = {{"control", "s"}},
  100.     close = {{"control", "w"}},
  101.     find = {{"control", "f"}},
  102.     findnext = {{"control", "g"}, {"control", "n"}, {"f3"}}
  103.   }
  104.   -- Generate config file if it didn't exist.
  105.   if not config then
  106.     local root = fs.get("/")
  107.     if root and not root.isReadOnly() then
  108.       fs.makeDirectory("/etc")
  109.       local f = io.open("/etc/edit.cfg", "w")
  110.       if f then
  111.         local serialization = require("serialization")
  112.         for k, v in pairs(env) do
  113.           f:write(k.."="..tostring(serialization.serialize(v, math.huge)).."\n")
  114.         end
  115.         f:close()
  116.       end
  117.     end
  118.   end
  119.   return env
  120. end
  121.  
  122. term.clear()
  123. term.setCursorBlink(true)
  124.  
  125. local running = true
  126. local buffer = {}
  127. local scrollX, scrollY = 0, 0
  128. local config = loadConfig()
  129.  
  130. local getKeyBindHandler -- forward declaration for refind()
  131.  
  132. local function helpStatusText()
  133.   local function prettifyKeybind(label, command)
  134.     local keybind = type(config.keybinds) == "table" and config.keybinds[command]
  135.     if type(keybind) ~= "table" or type(keybind[1]) ~= "table" then return "" end
  136.     local alt, control, shift, key
  137.     for _, value in ipairs(keybind[1]) do
  138.       if value == "alt" then alt = true
  139.       elseif value == "control" then control = true
  140.       elseif value == "shift" then shift = true
  141.       else key = value end
  142.     end
  143.     if not key then return "" end
  144.     return label .. ": [" ..
  145.            (control and "Ctrl+" or "") ..
  146.            (alt and "Alt+" or "") ..
  147.            (shift and "Shift+" or "") ..
  148.            unicode.upper(key) ..
  149.            "] "
  150.   end
  151.   return prettifyKeybind("Save", "save") ..
  152.          prettifyKeybind("Close", "close") ..
  153.          prettifyKeybind("Find", "find")
  154. end
  155.  
  156. -------------------------------------------------------------------------------
  157.  
  158. local function setStatus(value)
  159.   local x, y, w, h = term.getGlobalArea()
  160.   value = unicode.wlen(value) > w - 10 and unicode.wtrunc(value, w - 9) or value
  161.   value = text.padRight(value, w - 10)
  162.   gpu.set(x, y + h - 1, value)
  163. end
  164.  
  165. local function getArea()
  166.   local x, y, w, h = term.getGlobalArea()
  167.   return x, y, w, h - 1
  168. end
  169.  
  170. local function removePrefix(line, length)
  171.   if length >= unicode.wlen(line) then
  172.     return ""
  173.   else
  174.     local prefix = unicode.wtrunc(line, length + 1)
  175.     local suffix = unicode.sub(line, unicode.len(prefix) + 1)
  176.     length = length - unicode.wlen(prefix)
  177.     if length > 0 then
  178.       suffix = (" "):rep(unicode.charWidth(suffix) - length) .. unicode.sub(suffix, 2)
  179.     end
  180.     return suffix
  181.   end
  182. end
  183.  
  184. local function lengthToChars(line, length)
  185.   if length > unicode.wlen(line) then
  186.     return unicode.len(line) + 1
  187.   else
  188.     local prefix = unicode.wtrunc(line, length)
  189.     return unicode.len(prefix) + 1
  190.   end
  191. end
  192.  
  193.  
  194. local function isWideAtPosition(line, x)
  195.   local index = lengthToChars(line, x)
  196.   if index > unicode.len(line) then
  197.     return false, false
  198.   end
  199.   local prefix = unicode.sub(line, 1, index)
  200.   local char = unicode.sub(line, index, index)
  201.   --isWide, isRight
  202.   return unicode.isWide(char), unicode.wlen(prefix) == x
  203. end
  204.  
  205.  
  206. --SYNEDIT MODIFICATIONS start
  207. local function tryWrite(sLine, regex, color, x, y, lineNr)
  208.     local match = string.match(sLine, regex)
  209.     if match then
  210.         if type(color) == "number" then
  211.             gpu.setForeground(color)
  212.         else
  213.             gpu.setForeground(color(match))
  214.         end
  215.         --gpu.set(x, y - 1 + lineNr - scrollY, sLine)
  216.         term.write(match)
  217.         gpu.setForeground(textColor)
  218.         return string.sub(sLine, string.len(match) + 1)
  219.     end
  220.     return nil
  221. end
  222.  
  223. local function writeHighlighted(sLine, x, y, lineNr)
  224.     while string.len(sLine) > 0 do
  225.         sLine =
  226.             tryWrite(sLine, "^%-%-%[%[.-%]%]", commentColor, x, y, lineNr) or
  227.             tryWrite(sLine, "^%-%-.*", commentColor, x, y, lineNr)         or
  228.             tryWrite(sLine, "^\"\"", stringColor, x, y, lineNr)            or
  229.             tryWrite(sLine, "^\".-[^\\]\"", stringColor, x, y, lineNr)     or
  230.             tryWrite(sLine, "^\'\'", stringColor, x, y, lineNr)            or
  231.             tryWrite(sLine, "^\'.-[^\\]\'", stringColor, x, y, lineNr)     or
  232.             tryWrite(sLine, "^%[%[.-%]%]", stringColor, x, y, lineNr)      or
  233.             tryWrite(sLine, "^[%w_]+", function(match)
  234.                 if tonumber(match) ~= nil then
  235.                     return numberColor
  236.                 elseif tKeywords[match] then
  237.                     return keywordColor
  238.                 end
  239.                 return textColor
  240.             end, x, y, lineNr)                                             or
  241.             tryWrite(sLine, "^[^%w_]", textColor, x, y, lineNr)
  242.     end
  243. end
  244. -- SYNEDIT MODIFICATIONS end
  245.  
  246. local function drawLine(x, y, w, h, lineNr)
  247.   local yLocal = lineNr - scrollY
  248.   if yLocal > 0 and yLocal <= h then
  249.     local str = removePrefix(buffer[lineNr] or "", scrollX)
  250.     str = unicode.wlen(str) > w and unicode.wtrunc(str, w + 1) or str
  251.     str = text.padRight(str, w)
  252.     writeHighlighted(str, x, y, lineNr)
  253.     --gpu.set(x, y - 1 + lineNr - scrollY, str)
  254.   end
  255. end
  256.  
  257. local function getCursor()
  258.   local cx, cy = term.getCursor()
  259.   return cx + scrollX, cy + scrollY
  260. end
  261.  
  262. local function line()
  263.   local cbx, cby = getCursor()
  264.   return buffer[cby]
  265. end
  266.  
  267. local function getNormalizedCursor()
  268.   local cbx, cby = getCursor()
  269.   local wide, right = isWideAtPosition(buffer[cby], cbx)
  270.   if wide and right then
  271.     cbx = cbx - 1
  272.   end
  273.   return cbx, cby
  274. end
  275.  
  276. local function setCursor(nbx, nby)
  277.   local x, y, w, h = getArea()
  278.   nby = math.max(1, math.min(#buffer, nby))
  279.  
  280.   local ncy = nby - scrollY
  281.   if ncy > h then
  282.     term.setCursorBlink(false)
  283.     local sy = nby - h
  284.     local dy = math.abs(scrollY - sy)
  285.     scrollY = sy
  286.     if h > dy then
  287.       gpu.copy(x, y + dy, w, h - dy, 0, -dy)
  288.     end
  289.     for lineNr = nby - (math.min(dy, h) - 1), nby do
  290.       drawLine(x, y, w, h, lineNr)
  291.     end
  292.   elseif ncy < 1 then
  293.     term.setCursorBlink(false)
  294.     local sy = nby - 1
  295.     local dy = math.abs(scrollY - sy)
  296.     scrollY = sy
  297.     if h > dy then
  298.       gpu.copy(x, y, w, h - dy, 0, dy)
  299.     end
  300.     for lineNr = nby, nby + (math.min(dy, h) - 1) do
  301.       drawLine(x, y, w, h, lineNr)
  302.     end
  303.   end
  304.   term.setCursor(term.getCursor(), nby - scrollY)
  305.  
  306.   nbx = math.max(1, math.min(unicode.wlen(line()) + 1, nbx))
  307.   local wide, right = isWideAtPosition(line(), nbx)
  308.   local ncx = nbx - scrollX
  309.   if ncx > w or (ncx + 1 > w and wide and not right) then
  310.     term.setCursorBlink(false)
  311.     scrollX = nbx - w + ((wide and not right) and 1 or 0)
  312.     for lineNr = 1 + scrollY, math.min(h + scrollY, #buffer) do
  313.       drawLine(x, y, w, h, lineNr)
  314.     end
  315.   elseif ncx < 1 or (ncx - 1 < 1 and wide and right) then
  316.     term.setCursorBlink(false)
  317.     scrollX = nbx - 1 - ((wide and right) and 1 or 0)
  318.     for lineNr = 1 + scrollY, math.min(h + scrollY, #buffer) do
  319.       drawLine(x, y, w, h, lineNr)
  320.     end
  321.   end
  322.   term.setCursor(nbx - scrollX, nby - scrollY)
  323.   --update with term lib
  324.   nbx, nby = getCursor()
  325.   gpu.set(x + w - 10, y + h, text.padLeft(string.format("%d,%d", nby, nbx), 10))
  326. end
  327.  
  328. local function highlight(bx, by, length, enabled)
  329.   local x, y, w, h = getArea()
  330.   local cx, cy = bx - scrollX, by - scrollY
  331.   cx = math.max(1, math.min(w, cx))
  332.   cy = math.max(1, math.min(h, cy))
  333.   length = math.max(1, math.min(w - cx, length))
  334.  
  335.   local fg, fgp = gpu.getForeground()
  336.   local bg, bgp = gpu.getBackground()
  337.   if enabled then
  338.     gpu.setForeground(bg, bgp)
  339.     gpu.setBackground(fg, fgp)
  340.   end
  341.   local indexFrom = lengthToChars(buffer[by], bx)
  342.   local value = unicode.sub(buffer[by], indexFrom)
  343.   if unicode.wlen(value) > length then
  344.     value = unicode.wtrunc(value, length + 1)
  345.   end
  346.   gpu.set(x - 1 + cx, y - 1 + cy, value)
  347.   if enabled then
  348.     gpu.setForeground(fg, fgp)
  349.     gpu.setBackground(bg, bgp)
  350.   end
  351. end
  352.  
  353. local function home()
  354.   local cbx, cby = getCursor()
  355.   setCursor(1, cby)
  356. end
  357.  
  358. local function ende()
  359.   local cbx, cby = getCursor()
  360.   setCursor(unicode.wlen(line()) + 1, cby)
  361. end
  362.  
  363. local function left()
  364.   local cbx, cby = getNormalizedCursor()
  365.   if cbx > 1 then
  366.     local wideTarget, rightTarget = isWideAtPosition(line(), cbx - 1)
  367.     if wideTarget and rightTarget then
  368.       setCursor(cbx - 2, cby)
  369.     else
  370.       setCursor(cbx - 1, cby)
  371.     end
  372.     return true -- for backspace
  373.   elseif cby > 1 then
  374.     setCursor(cbx, cby - 1)
  375.     ende()
  376.     return true -- again, for backspace
  377.   end
  378. end
  379.  
  380. local function right(n)
  381.   n = n or 1
  382.   local cbx, cby = getNormalizedCursor()
  383.   local be = unicode.wlen(line()) + 1
  384.   local wide, right = isWideAtPosition(line(), cbx + n)
  385.   if wide and right then
  386.     n = n + 1
  387.   end
  388.   if cbx + n <= be then
  389.     setCursor(cbx + n, cby)
  390.   elseif cby < #buffer then
  391.     setCursor(1, cby + 1)
  392.   end
  393. end
  394.  
  395. local function up(n)
  396.   n = n or 1
  397.   local cbx, cby = getCursor()
  398.   if cby > 1 then
  399.     setCursor(cbx, cby - n)
  400.   end
  401. end
  402.  
  403. local function down(n)
  404.   n = n or 1
  405.   local cbx, cby = getCursor()
  406.   if cby < #buffer then
  407.     setCursor(cbx, cby + n)
  408.   end
  409. end
  410.  
  411. local function delete(fullRow)
  412.   local cx, cy = term.getCursor()
  413.   local cbx, cby = getCursor()
  414.   local x, y, w, h = getArea()
  415.   local function deleteRow(row)
  416.     local content = table.remove(buffer, row)
  417.     local rcy = cy + (row - cby)
  418.     if rcy <= h then
  419.       gpu.copy(x, y + rcy, w, h - rcy, 0, -1)
  420.       drawLine(x, y, w, h, row + (h - rcy))
  421.     end
  422.     return content
  423.   end
  424.   if fullRow then
  425.     term.setCursorBlink(false)
  426.     if #buffer > 1 then
  427.       deleteRow(cby)
  428.     else
  429.       buffer[cby] = ""
  430.       gpu.fill(x, y - 1 + cy, w, 1, " ")
  431.     end
  432.     setCursor(1, cby)
  433.   elseif cbx <= unicode.wlen(line()) then
  434.     term.setCursorBlink(false)
  435.     local index = lengthToChars(line(), cbx)
  436.     buffer[cby] = unicode.sub(line(), 1, index - 1) ..
  437.                   unicode.sub(line(), index + 1)
  438.     drawLine(x, y, w, h, cby)
  439.   elseif cby < #buffer then
  440.     term.setCursorBlink(false)
  441.     local append = deleteRow(cby + 1)
  442.     buffer[cby] = buffer[cby] .. append
  443.     drawLine(x, y, w, h, cby)
  444.   else
  445.     return
  446.   end
  447.   setStatus(helpStatusText())
  448. end
  449.  
  450. local function insert(value)
  451.   if not value or unicode.len(value) < 1 then
  452.     return
  453.   end
  454.   term.setCursorBlink(false)
  455.   local cx, cy = term.getCursor()
  456.   local cbx, cby = getCursor()
  457.   local x, y, w, h = getArea()
  458.   local index = lengthToChars(line(), cbx)
  459.   buffer[cby] = unicode.sub(line(), 1, index - 1) ..
  460.                 value ..
  461.                 unicode.sub(line(), index)
  462.   drawLine(x, y, w, h, cby)
  463.   right(unicode.wlen(value))
  464.   setStatus(helpStatusText())
  465. end
  466.  
  467. local function enter()
  468.   term.setCursorBlink(false)
  469.   local cx, cy = term.getCursor()
  470.   local cbx, cby = getCursor()
  471.   local x, y, w, h = getArea()
  472.   local index = lengthToChars(line(), cbx)
  473.   table.insert(buffer, cby + 1, unicode.sub(buffer[cby], index))
  474.   buffer[cby] = unicode.sub(buffer[cby], 1, index - 1)
  475.   drawLine(x, y, w, h, cby)
  476.   if cy < h then
  477.     if cy < h - 1 then
  478.       gpu.copy(x, y + cy, w, h - (cy + 1), 0, 1)
  479.     end
  480.     drawLine(x, y, w, h, cby + 1)
  481.   end
  482.   setCursor(1, cby + 1)
  483.   setStatus(helpStatusText())
  484. end
  485.  
  486. local findText = ""
  487.  
  488. local function find()
  489.   local x, y, w, h = getArea()
  490.   local cx, cy = term.getCursor()
  491.   local cbx, cby = getCursor()
  492.   local ibx, iby = cbx, cby
  493.   while running do
  494.     if unicode.len(findText) > 0 then
  495.       local sx, sy
  496.       for syo = 1, #buffer do -- iterate lines with wraparound
  497.         sy = (iby + syo - 1 + #buffer - 1) % #buffer + 1
  498.         sx = string.find(buffer[sy], findText, syo == 1 and ibx or 1, true)
  499.         if sx and (sx >= ibx or syo > 1) then
  500.           break
  501.         end
  502.       end
  503.       if not sx then -- special case for single matches
  504.         sy = iby
  505.         sx = string.find(buffer[sy], findText, nil, true)
  506.       end
  507.       if sx then
  508.         sx = unicode.wlen(string.sub(buffer[sy], 1, sx - 1)) + 1
  509.         cbx, cby = sx, sy
  510.         setCursor(cbx, cby)
  511.         highlight(cbx, cby, unicode.wlen(findText), true)
  512.       end
  513.     end
  514.     term.setCursor(7 + unicode.wlen(findText), h + 1)
  515.     setStatus("Find: " .. findText)
  516.  
  517.     local _, address, char, code = term.pull("key_down")
  518.     if address == term.keyboard() then
  519.       local handler, name = getKeyBindHandler(code)
  520.       highlight(cbx, cby, unicode.wlen(findText), false)
  521.       if name == "newline" then
  522.         break
  523.       elseif name == "close" then
  524.         handler()
  525.       elseif name == "backspace" then
  526.         findText = unicode.sub(findText, 1, -2)
  527.       elseif name == "find" or name == "findnext" then
  528.         ibx = cbx + 1
  529.         iby = cby
  530.       elseif not keyboard.isControl(char) then
  531.         findText = findText .. unicode.char(char)
  532.       end
  533.     end
  534.   end
  535.   setCursor(cbx, cby)
  536.   setStatus(helpStatusText())
  537. end
  538.  
  539. -------------------------------------------------------------------------------
  540.  
  541. local keyBindHandlers = {
  542.   left = left,
  543.   right = right,
  544.   up = up,
  545.   down = down,
  546.   home = home,
  547.   eol = ende,
  548.   pageUp = function()
  549.     local x, y, w, h = getArea()
  550.     up(h - 1)
  551.   end,
  552.   pageDown = function()
  553.     local x, y, w, h = getArea()
  554.     down(h - 1)
  555.   end,
  556.  
  557.   backspace = function()
  558.     if not readonly and left() then
  559.       delete()
  560.     end
  561.   end,
  562.   delete = function()
  563.     if not readonly then
  564.       delete()
  565.     end
  566.   end,
  567.   deleteLine = function()
  568.     if not readonly then
  569.       delete(true)
  570.     end
  571.   end,
  572.   newline = function()
  573.     if not readonly then
  574.       enter()
  575.     end
  576.   end,
  577.  
  578.   save = function()
  579.     if readonly then return end
  580.     local new = not fs.exists(filename)
  581.     local backup
  582.     if not new then
  583.       backup = filename .. "~"
  584.       for i = 1, math.huge do
  585.         if not fs.exists(backup) then
  586.           break
  587.         end
  588.         backup = filename .. "~" .. i
  589.       end
  590.       fs.copy(filename, backup)
  591.     end
  592.     local f, reason = io.open(filename, "w")
  593.     if f then
  594.       local chars, firstLine = 0, true
  595.       for _, line in ipairs(buffer) do
  596.         if not firstLine then
  597.           line = "\n" .. line
  598.         end
  599.         firstLine = false
  600.         f:write(line)
  601.         chars = chars + unicode.len(line)
  602.       end
  603.       f:close()
  604.       local format
  605.       if new then
  606.         format = [["%s" [New] %dL,%dC written]]
  607.       else
  608.         format = [["%s" %dL,%dC written]]
  609.       end
  610.       setStatus(string.format(format, fs.name(filename), #buffer, chars))
  611.     else
  612.       setStatus(reason)
  613.     end
  614.     if not new then
  615.       fs.remove(backup)
  616.     end
  617.   end,
  618.   close = function()
  619.     -- TODO ask to save if changed
  620.     running = false
  621.   end,
  622.   find = function()
  623.     findText = ""
  624.     find()
  625.   end,
  626.   findnext = find
  627. }
  628.  
  629. getKeyBindHandler = function(code)
  630.   if type(config.keybinds) ~= "table" then return end
  631.   -- Look for matches, prefer more 'precise' keybinds, e.g. prefer
  632.   -- ctrl+del over del.
  633.   local result, resultName, resultWeight = nil, nil, 0
  634.   for command, keybinds in pairs(config.keybinds) do
  635.     if type(keybinds) == "table" and keyBindHandlers[command] then
  636.       for _, keybind in ipairs(keybinds) do
  637.         if type(keybind) == "table" then
  638.           local alt, control, shift, key
  639.           for _, value in ipairs(keybind) do
  640.             if value == "alt" then alt = true
  641.             elseif value == "control" then control = true
  642.             elseif value == "shift" then shift = true
  643.             else key = value end
  644.           end
  645.           local keyboardAddress = term.keyboard()
  646.           if (not alt or keyboard.isAltDown(keyboardAddress)) and
  647.              (not control or keyboard.isControlDown(keyboardAddress)) and
  648.              (not shift or keyboard.isShiftDown(keyboardAddress)) and
  649.              code == keyboard.keys[key] and
  650.              #keybind > resultWeight
  651.           then
  652.             resultWeight = #keybind
  653.             resultName = command
  654.             result = keyBindHandlers[command]
  655.           end
  656.         end
  657.       end
  658.     end
  659.   end
  660.   return result, resultName
  661. end
  662.  
  663. -------------------------------------------------------------------------------
  664.  
  665. local function onKeyDown(char, code)
  666.   local handler = getKeyBindHandler(code)
  667.   if handler then
  668.     handler()
  669.   elseif readonly and code == keyboard.keys.q then
  670.     running = false
  671.   elseif not readonly then
  672.     if not keyboard.isControl(char) then
  673.       insert(unicode.char(char))
  674.     elseif unicode.char(char) == "\t" then
  675.       insert("  ")
  676.     end
  677.   end
  678. end
  679.  
  680. local function onClipboard(value)
  681.   value = value:gsub("\r\n", "\n")
  682.   local cbx, cby = getCursor()
  683.   local start = 1
  684.   local l = value:find("\n", 1, true)
  685.   if l then
  686.     repeat
  687.       local line = string.sub(value, start, l - 1)
  688.       line = text.detab(line, 2)
  689.       insert(line)
  690.       enter()
  691.       start = l + 1
  692.       l = value:find("\n", start, true)
  693.     until not l
  694.   end
  695.   insert(string.sub(value, start))
  696. end
  697.  
  698. local function onClick(x, y)
  699.   setCursor(x + scrollX, y + scrollY)
  700. end
  701.  
  702. local function onScroll(direction)
  703.   local cbx, cby = getCursor()
  704.   setCursor(cbx, cby - direction * 12)
  705. end
  706.  
  707. -------------------------------------------------------------------------------
  708.  
  709. do
  710.   local f = io.open(filename)
  711.   if f then
  712.     local x, y, w, h = getArea()
  713.     local chars = 0
  714.     for line in f:lines() do
  715.       if line:sub(-1) == "\r" then
  716.         line = line:sub(1, -2)
  717.       end
  718.       table.insert(buffer, line)
  719.       chars = chars + unicode.len(line)
  720.       if #buffer <= h then
  721.         drawLine(x, y, w, h, #buffer)
  722.       end
  723.     end
  724.     f:close()
  725.     if #buffer == 0 then
  726.       table.insert(buffer, "")
  727.     end
  728.     local format
  729.     if readonly then
  730.       format = [["%s" [readonly] %dL,%dC]]
  731.     else
  732.       format = [["%s" %dL,%dC]]
  733.     end
  734.     setStatus(string.format(format, fs.name(filename), #buffer, chars))
  735.   else
  736.     table.insert(buffer, "")
  737.     setStatus(string.format([["%s" [New File] ]], fs.name(filename)))
  738.   end
  739.   setCursor(1, 1)
  740. end
  741.  
  742. while running do
  743.   local event, address, arg1, arg2, arg3 = term.pull()
  744.   if address == term.keyboard() or address == term.screen() then
  745.     local blink = true
  746.     if event == "key_down" then
  747.       onKeyDown(arg1, arg2)
  748.     elseif event == "clipboard" and not readonly then
  749.       onClipboard(arg1)
  750.     elseif event == "touch" or event == "drag" then
  751.       local x, y, w, h = getArea()
  752.       arg1 = arg1 - x + 1
  753.       arg2 = arg2 - y + 1
  754.       if arg1 >= 1 and arg2 >= 1 and arg1 <= w and arg2 <= h then
  755.         onClick(arg1, arg2)
  756.       end
  757.     elseif event == "scroll" then
  758.       onScroll(arg3)
  759.     else
  760.       blink = false
  761.     end
  762.     if blink then
  763.       term.setCursorBlink(true)
  764.     end
  765.   end
  766. end
  767.  
  768. term.clear()
  769. term.setCursorBlink(false)
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top