Advertisement
Lanzr

hedit.lua

Jul 4th, 2024 (edited)
687
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 24.58 KB | None | 0 0
  1. --[[
  2.     Lets use hedit to edit hex code !
  3. ]]
  4. require("hexMap")
  5.  
  6. local completion = require "cc.shell.completion"
  7. local complete = completion.build(
  8.     completion.file
  9. )
  10. shell.setCompletionFunction("hedit.lua", complete)
  11.  
  12. local tArgs = { ... }
  13.     if #tArgs == 0 then
  14.         local programName = arg[0] or fs.getName(shell.getRunningProgram())
  15.         print("Usage: " .. programName .. " <path>")
  16.     return
  17. end
  18.  
  19. -- Error checking
  20. local sPath = shell.resolve(tArgs[1])
  21. local bReadOnly = fs.isReadOnly(sPath)
  22. if fs.exists(sPath) and fs.isDir(sPath) then
  23.     print("Cannot edit a directory.")
  24.     return
  25. end
  26.  
  27. -- Create .hex files by default
  28. if not fs.exists(sPath) and not string.find(sPath, "%.") then
  29.     local sExtension = "hex"
  30.     if sExtension ~= "" and type(sExtension) == "string" then
  31.         sPath = sPath .. "." .. sExtension
  32.     end
  33. end
  34.  
  35. local x, y = 1, 1
  36. local w, h = term.getSize()
  37. local scrollX, scrollY = 0, 0
  38.  
  39. local tLines = {}
  40. local bRunning = true
  41.  
  42. -- Colours
  43. local highlightColour, keywordColour, preExpWordColour, commentColour, textColour, bgColour, stringColour, errorColour, funcColour
  44. if term.isColour() then
  45.     bgColour = colours.black
  46.     textColour = colours.white
  47.     highlightColour = colours.yellow
  48.     keywordColour = colours.yellow
  49.     preExpWordColour = colours.orange
  50.     funcColour = colours.lightBlue
  51.     commentColour = colours.green
  52.     stringColour = colours.red
  53.     errorColour = colours.red
  54. else
  55.     bgColour = colours.black
  56.     textColour = colours.white
  57.     highlightColour = colours.white
  58.     keywordColour = colours.white
  59.     preExpWordColour = colours.white
  60.     funcColour = colours.white
  61.     commentColour = colours.white
  62.     stringColour = colours.white
  63.     errorColour = colours.white
  64. end
  65.  
  66. -- Menus
  67. local bMenu = false
  68. local nMenuItem = 1
  69. local tMenuItems = {}
  70. if not bReadOnly then
  71.     table.insert(tMenuItems, "Save")
  72. end
  73. if peripheral.find("focal_port") then
  74.     table.insert(tMenuItems, "Compile")
  75. end
  76. if peripheral.find("printer") then
  77.     table.insert(tMenuItems, "Print")
  78. end
  79. table.insert(tMenuItems, "Exit")
  80.  
  81. local status_ok, status_text
  82. local function set_status(text, ok)
  83.     status_ok = ok ~= false
  84.     status_text = text
  85. end
  86.  
  87. if bReadOnly then
  88.     set_status("File is read only", false)
  89. elseif fs.getFreeSpace(sPath) < 1024 then
  90.     set_status("Disk is low on space", false)
  91. else
  92.     local message
  93.     if term.isColour() then
  94.         message = "Press Ctrl or click here to access menu"
  95.     else
  96.         message = "Press Ctrl to access menu"
  97.     end
  98.  
  99.     if #message > w - 5 then
  100.         message = "Press Ctrl for menu"
  101.     end
  102.  
  103.     set_status(message)
  104. end
  105.  
  106. local function load(_sPath)
  107.     tLines = {}
  108.     if fs.exists(_sPath) then
  109.         local file = io.open(_sPath, "r")
  110.         local sLine = file:read()
  111.         while sLine do
  112.             table.insert(tLines, sLine)
  113.             sLine = file:read()
  114.         end
  115.         file:close()
  116.     end
  117.  
  118.     if #tLines == 0 then
  119.         table.insert(tLines, "")
  120.     end
  121. end
  122.  
  123. local function save(_sPath, fWrite)
  124.     -- Create intervening folder
  125.     local sDir = _sPath:sub(1, _sPath:len() - fs.getName(_sPath):len())
  126.     if not fs.exists(sDir) then
  127.         fs.makeDir(sDir)
  128.     end
  129.  
  130.     -- Save
  131.     local file, fileerr
  132.     local function innerSave()
  133.         file, fileerr = fs.open(_sPath, "w")
  134.         if file then
  135.             if file then
  136.                 fWrite(file)
  137.             end
  138.         else
  139.             error("Failed to open " .. _sPath)
  140.         end
  141.     end
  142.  
  143.     local ok, err = pcall(innerSave)
  144.     if file then
  145.         file.close()
  146.     end
  147.     return ok, err, fileerr
  148. end
  149.  
  150. local tKeywords = {}
  151. for name, iota in pairs(hexMap) do
  152.     tKeywords[name] = true
  153. end
  154. local tPreMapWords = {}
  155. for name,regex in pairs(preMap) do
  156.     tPreMapWords["@"..name] = true
  157. end
  158. local function tryWrite(sLine, regex, colour)
  159.     local match = string.match(sLine, regex)
  160.     if match then
  161.         if type(colour) == "number" then
  162.             term.setTextColour(colour)
  163.         else
  164.             term.setTextColour(colour(match))
  165.         end
  166.         term.write(match)
  167.         term.setTextColour(textColour)
  168.         return string.sub(sLine, #match + 1)
  169.     end
  170.     return nil
  171. end
  172.  
  173. local function writeHighlighted(sLine)
  174.     while #sLine > 0 do
  175.         sLine =
  176.             tryWrite(sLine, "^#.*", commentColour) or
  177.             tryWrite(sLine, "^\"\"", stringColour) or
  178.             tryWrite(sLine, "^\".-[^\\]\"", stringColour) or
  179.             tryWrite(sLine, "^\'\'", stringColour) or
  180.             tryWrite(sLine, "^\'.-[^\\]\'", stringColour) or
  181.             tryWrite(sLine, "^%[%[.-%]%]", stringColour) or
  182.             tryWrite(sLine, "^[%w_]+%(%)", funcColour) or
  183.             tryWrite(sLine, "^[%w_]+",
  184.                 function(match)
  185.                     if tKeywords[match] then
  186.                         return keywordColour
  187.                     end
  188.                     return textColour
  189.                 end) or
  190.             tryWrite(sLine, "^(@[%w_]+)",
  191.                 function(match)
  192.                     if tPreMapWords[match] then
  193.                         return preExpWordColour
  194.                     end
  195.                     return textColour
  196.                 end) or
  197.             tryWrite(sLine, "^[^%w_]", textColour)
  198.     end
  199. end
  200.  
  201. local tCompletions
  202. local nCompletion
  203.  
  204. _hexENV = {}
  205. for cmd, iota in pairs(hexMap) do
  206.     local result = string.match(cmd,"[{}>%*%+-=</]")
  207.     if result == nil then
  208.        _hexENV[cmd] = true
  209.     end
  210. end
  211.  
  212. local tCompleteEnv = _hexENV
  213. local function complete(sLine)
  214.     if settings.get("edit.autocomplete") then
  215.         local nStartPos = string.find(sLine, "[a-zA-Z0-9_%.:]+$")
  216.         if nStartPos then
  217.             sLine = string.sub(sLine, nStartPos)
  218.         end
  219.         term.setCursorPos(1,5)
  220.         if #sLine > 0 then
  221.             return textutils.complete(sLine, tCompleteEnv)
  222.         end
  223.     end
  224.     return nil
  225. end
  226.  
  227. local function recomplete()
  228.     local sLine = tLines[y]
  229.     if not bMenu and not bReadOnly and x == #sLine + 1 then
  230.         tCompletions = complete(sLine)
  231.         if tCompletions and #tCompletions > 0 then
  232.             nCompletion = 1
  233.         else
  234.             nCompletion = nil
  235.         end
  236.     else
  237.         tCompletions = nil
  238.         nCompletion = nil
  239.     end
  240. end
  241.  
  242. local function writeCompletion(sLine)
  243.     if nCompletion then
  244.         local sCompletion = tCompletions[nCompletion]
  245.         term.setTextColor(colours.white)
  246.         term.setBackgroundColor(colours.grey)
  247.         term.write(sCompletion)
  248.         term.setTextColor(textColour)
  249.         term.setBackgroundColor(bgColour)
  250.     end
  251. end
  252.  
  253. local function redrawText()
  254.     local cursorX, cursorY = x, y
  255.     for y = 1, h - 1 do
  256.         term.setCursorPos(1 - scrollX, y)
  257.         term.clearLine()
  258.  
  259.         local sLine = tLines[y + scrollY]
  260.         if sLine ~= nil then
  261.             writeHighlighted(sLine)
  262.             if cursorY == y and cursorX == #sLine + 1 then
  263.                 writeCompletion()
  264.             end
  265.         end
  266.     end
  267.     term.setCursorPos(x - scrollX, y - scrollY)
  268. end
  269.  
  270. local function redrawLine(_nY)
  271.     local sLine = tLines[_nY]
  272.     if sLine then
  273.         term.setCursorPos(1 - scrollX, _nY - scrollY)
  274.         term.clearLine()
  275.         writeHighlighted(sLine)
  276.         if _nY == y and x == #sLine + 1 then
  277.             writeCompletion()
  278.         end
  279.         term.setCursorPos(x - scrollX, _nY - scrollY)
  280.     end
  281. end
  282.  
  283. local function redrawMenu()
  284.     -- Clear line
  285.     term.setCursorPos(1, h)
  286.     term.clearLine()
  287.  
  288.     -- Draw line numbers
  289.     term.setCursorPos(w - #("Ln " .. y) + 1, h)
  290.     term.setTextColour(highlightColour)
  291.     term.write("Ln ")
  292.     term.setTextColour(textColour)
  293.     term.write(y)
  294.  
  295.     term.setCursorPos(1, h)
  296.     if bMenu then
  297.         -- Draw menu
  298.         term.setTextColour(textColour)
  299.         for nItem, sItem in pairs(tMenuItems) do
  300.             if nItem == nMenuItem then
  301.                 term.setTextColour(highlightColour)
  302.                 term.write("[")
  303.                 term.setTextColour(textColour)
  304.                 term.write(sItem)
  305.                 term.setTextColour(highlightColour)
  306.                 term.write("]")
  307.                 term.setTextColour(textColour)
  308.             else
  309.                 term.write(" " .. sItem .. " ")
  310.             end
  311.         end
  312.     else
  313.         -- Draw status
  314.         term.setTextColour(status_ok and highlightColour or errorColour)
  315.         term.write(status_text)
  316.         term.setTextColour(textColour)
  317.     end
  318.  
  319.     -- Reset cursor
  320.     term.setCursorPos(x - scrollX, y - scrollY)
  321. end
  322.  
  323. local tMenuFuncs = {
  324.     Save = function()
  325.         if bReadOnly then
  326.             set_status("Access denied", false)
  327.         else
  328.             local ok, _, fileerr  = save(sPath, function(file)
  329.                 for _, sLine in ipairs(tLines) do
  330.                     file.write(sLine .. "\n")
  331.                 end
  332.             end)
  333.             if ok then
  334.                 set_status("Saved to " .. sPath)
  335.             else
  336.                 if fileerr then
  337.                     set_status("Error saving: " .. fileerr, false)
  338.                 else
  339.                     set_status("Error saving to " .. sPath, false)
  340.                 end
  341.             end
  342.         end
  343.         redrawMenu()
  344.     end,
  345.     Print = function()
  346.         local printer = peripheral.find("printer")
  347.         if not printer then
  348.             set_status("No printer attached", false)
  349.             return
  350.         end
  351.  
  352.         local nPage = 0
  353.         local sName = fs.getName(sPath)
  354.         if printer.getInkLevel() < 1 then
  355.             set_status("Printer out of ink", false)
  356.             return
  357.         elseif printer.getPaperLevel() < 1 then
  358.             set_status("Printer out of paper", false)
  359.             return
  360.         end
  361.  
  362.         local screenTerminal = term.current()
  363.         local printerTerminal = {
  364.             getCursorPos = printer.getCursorPos,
  365.             setCursorPos = printer.setCursorPos,
  366.             getSize = printer.getPageSize,
  367.             write = printer.write,
  368.         }
  369.         printerTerminal.scroll = function()
  370.             if nPage == 1 then
  371.                 printer.setPageTitle(sName .. " (page " .. nPage .. ")")
  372.             end
  373.  
  374.             while not printer.newPage() do
  375.                 if printer.getInkLevel() < 1 then
  376.                     set_status("Printer out of ink, please refill", false)
  377.                 elseif printer.getPaperLevel() < 1 then
  378.                     set_status("Printer out of paper, please refill", false)
  379.                 else
  380.                     set_status("Printer output tray full, please empty", false)
  381.                 end
  382.  
  383.                 term.redirect(screenTerminal)
  384.                 redrawMenu()
  385.                 term.redirect(printerTerminal)
  386.  
  387.                 sleep(0.5)
  388.             end
  389.  
  390.             nPage = nPage + 1
  391.             if nPage == 1 then
  392.                 printer.setPageTitle(sName)
  393.             else
  394.                 printer.setPageTitle(sName .. " (page " .. nPage .. ")")
  395.             end
  396.         end
  397.  
  398.         bMenu = false
  399.         term.redirect(printerTerminal)
  400.         local ok, error = pcall(function()
  401.             term.scroll()
  402.             for _, sLine in ipairs(tLines) do
  403.                 print(sLine)
  404.             end
  405.         end)
  406.         term.redirect(screenTerminal)
  407.         if not ok then
  408.             print(error)
  409.         end
  410.  
  411.         while not printer.endPage() do
  412.             set_status("Printer output tray full, please empty")
  413.             redrawMenu()
  414.             sleep(0.5)
  415.         end
  416.         bMenu = true
  417.  
  418.         if nPage > 1 then
  419.             set_status("Printed " .. nPage .. " Pages")
  420.         else
  421.             set_status("Printed 1 Page")
  422.         end
  423.         redrawMenu()
  424.     end,
  425.     Exit = function()
  426.         bRunning = false
  427.     end,
  428.     Compile = function()
  429.         local sTitle = fs.getName(sPath)
  430.         if sTitle:sub(-4) == ".hex" then
  431.             sTitle = sTitle:sub(1, -5)
  432.         end
  433.         local sTempPath = bReadOnly and ".temp." .. sTitle or fs.combine(fs.getDir(sPath), ".temp." .. sTitle)
  434.         if fs.exists(sTempPath) then
  435.             set_status("Error saving to " .. sTempPath, false)
  436.             return
  437.         end
  438.         local ok = save(sTempPath, function(file)
  439.             file.write(table.concat(tLines, "\n"))
  440.         end)
  441.         if ok then
  442.             shell.run("hex "..sTempPath)
  443.             fs.delete(sTempPath)
  444.         else
  445.             set_status("Error saving to " .. sTempPath, false)
  446.         end
  447.         redrawMenu()
  448.     end,
  449. }
  450.  
  451. local function doMenuItem(_n)
  452.     tMenuFuncs[tMenuItems[_n]]()
  453.     if bMenu then
  454.         bMenu = false
  455.         term.setCursorBlink(true)
  456.     end
  457.     redrawMenu()
  458. end
  459.  
  460. local function setCursor(newX, newY)
  461.     local _, oldY = x, y
  462.     x, y = newX, newY
  463.     local screenX = x - scrollX
  464.     local screenY = y - scrollY
  465.  
  466.     local bRedraw = false
  467.     if screenX < 1 then
  468.         scrollX = x - 1
  469.         screenX = 1
  470.         bRedraw = true
  471.     elseif screenX > w then
  472.         scrollX = x - w
  473.         screenX = w
  474.         bRedraw = true
  475.     end
  476.  
  477.     if screenY < 1 then
  478.         scrollY = y - 1
  479.         screenY = 1
  480.         bRedraw = true
  481.     elseif screenY > h - 1 then
  482.         scrollY = y - (h - 1)
  483.         screenY = h - 1
  484.         bRedraw = true
  485.     end
  486.  
  487.     recomplete()
  488.     if bRedraw then
  489.         redrawText()
  490.     elseif y ~= oldY then
  491.         redrawLine(oldY)
  492.         redrawLine(y)
  493.     else
  494.         redrawLine(y)
  495.     end
  496.     term.setCursorPos(screenX, screenY)
  497.  
  498.     redrawMenu()
  499. end
  500.  
  501. -- Actual program functionality begins
  502. load(sPath)
  503.  
  504. term.setBackgroundColour(bgColour)
  505. term.clear()
  506. term.setCursorPos(x, y)
  507. term.setCursorBlink(true)
  508.  
  509. recomplete()
  510. redrawText()
  511. redrawMenu()
  512.  
  513. local function acceptCompletion()
  514.     if nCompletion then
  515.         -- Append the completion
  516.         local sCompletion = tCompletions[nCompletion]
  517.         tLines[y] = tLines[y] .. sCompletion
  518.         setCursor(x + #sCompletion , y)
  519.     end
  520. end
  521.  
  522. -- Handle input
  523. while bRunning do
  524.     local sEvent, param, param2, param3 = os.pullEvent()
  525.     if sEvent == "key" then
  526.         if param == keys.up then
  527.             -- Up
  528.             if not bMenu then
  529.                 if nCompletion then
  530.                     -- Cycle completions
  531.                     nCompletion = nCompletion - 1
  532.                     if nCompletion < 1 then
  533.                         nCompletion = #tCompletions
  534.                     end
  535.                     redrawLine(y)
  536.  
  537.                 elseif y > 1 then
  538.                     -- Move cursor up
  539.                     setCursor(
  540.                         math.min(x, #tLines[y - 1] + 1),
  541.                         y - 1
  542.                     )
  543.                 end
  544.             end
  545.  
  546.         elseif param == keys.down then
  547.             -- Down
  548.             if not bMenu then
  549.                 -- Move cursor down
  550.                 if nCompletion then
  551.                     -- Cycle completions
  552.                     nCompletion = nCompletion + 1
  553.                     if nCompletion > #tCompletions then
  554.                         nCompletion = 1
  555.                     end
  556.                     redrawLine(y)
  557.  
  558.                 elseif y < #tLines then
  559.                     -- Move cursor down
  560.                     setCursor(
  561.                         math.min(x, #tLines[y + 1] + 1),
  562.                         y + 1
  563.                     )
  564.                 end
  565.             end
  566.  
  567.         elseif param == keys.tab then
  568.             -- Tab
  569.             if not bMenu and not bReadOnly then
  570.                 if nCompletion and x == #tLines[y] + 1 then
  571.                     -- Accept autocomplete
  572.                     acceptCompletion()
  573.                 else
  574.                     -- Indent line
  575.                     local sLine = tLines[y]
  576.                     tLines[y] = string.sub(sLine, 1, x - 1) .. "    " .. string.sub(sLine, x)
  577.                     setCursor(x + 4, y)
  578.                 end
  579.             end
  580.  
  581.         elseif param == keys.pageUp then
  582.             -- Page Up
  583.             if not bMenu then
  584.                 -- Move up a page
  585.                 local newY
  586.                 if y - (h - 1) >= 1 then
  587.                     newY = y - (h - 1)
  588.                 else
  589.                     newY = 1
  590.                 end
  591.                 setCursor(
  592.                     math.min(x, #tLines[newY] + 1),
  593.                     newY
  594.                 )
  595.             end
  596.  
  597.         elseif param == keys.pageDown then
  598.             -- Page Down
  599.             if not bMenu then
  600.                 -- Move down a page
  601.                 local newY
  602.                 if y + (h - 1) <= #tLines then
  603.                     newY = y + (h - 1)
  604.                 else
  605.                     newY = #tLines
  606.                 end
  607.                 local newX = math.min(x, #tLines[newY] + 1)
  608.                 setCursor(newX, newY)
  609.             end
  610.  
  611.         elseif param == keys.home then
  612.             -- Home
  613.             if not bMenu then
  614.                 -- Move cursor to the beginning
  615.                 if x > 1 then
  616.                     setCursor(1, y)
  617.                 end
  618.             end
  619.  
  620.         elseif param == keys["end"] then
  621.             -- End
  622.             if not bMenu then
  623.                 -- Move cursor to the end
  624.                 local nLimit = #tLines[y] + 1
  625.                 if x < nLimit then
  626.                     setCursor(nLimit, y)
  627.                 end
  628.             end
  629.  
  630.         elseif param == keys.left then
  631.             -- Left
  632.             if not bMenu then
  633.                 if x > 1 then
  634.                     -- Move cursor left
  635.                     setCursor(x - 1, y)
  636.                 elseif x == 1 and y > 1 then
  637.                     setCursor(#tLines[y - 1] + 1, y - 1)
  638.                 end
  639.             else
  640.                 -- Move menu left
  641.                 nMenuItem = nMenuItem - 1
  642.                 if nMenuItem < 1 then
  643.                     nMenuItem = #tMenuItems
  644.                 end
  645.                 redrawMenu()
  646.             end
  647.  
  648.         elseif param == keys.right then
  649.             -- Right
  650.             if not bMenu then
  651.                 local nLimit = #tLines[y] + 1
  652.                 if x < nLimit then
  653.                     -- Move cursor right
  654.                     setCursor(x + 1, y)
  655.                 elseif nCompletion and x == #tLines[y] + 1 then
  656.                     -- Accept autocomplete
  657.                     acceptCompletion()
  658.                 elseif x == nLimit and y < #tLines then
  659.                     -- Go to next line
  660.                     setCursor(1, y + 1)
  661.                 end
  662.             else
  663.                 -- Move menu right
  664.                 nMenuItem = nMenuItem + 1
  665.                 if nMenuItem > #tMenuItems then
  666.                     nMenuItem = 1
  667.                 end
  668.                 redrawMenu()
  669.             end
  670.  
  671.         elseif param == keys.delete then
  672.             -- Delete
  673.             if not bMenu and not bReadOnly then
  674.                 local nLimit = #tLines[y] + 1
  675.                 if x < nLimit then
  676.                     local sLine = tLines[y]
  677.                     tLines[y] = string.sub(sLine, 1, x - 1) .. string.sub(sLine, x + 1)
  678.                     recomplete()
  679.                     redrawLine(y)
  680.                 elseif y < #tLines then
  681.                     tLines[y] = tLines[y] .. tLines[y + 1]
  682.                     table.remove(tLines, y + 1)
  683.                     recomplete()
  684.                     redrawText()
  685.                 end
  686.             end
  687.  
  688.         elseif param == keys.backspace then
  689.             -- Backspace
  690.             if not bMenu and not bReadOnly then
  691.                 if x > 1 then
  692.                     -- Remove character
  693.                     local sLine = tLines[y]
  694.                     if x > 4 and string.sub(sLine, x - 4, x - 1) == "    " and not string.sub(sLine, 1, x - 1):find("%S") then
  695.                         tLines[y] = string.sub(sLine, 1, x - 5) .. string.sub(sLine, x)
  696.                         setCursor(x - 4, y)
  697.                     else
  698.                         tLines[y] = string.sub(sLine, 1, x - 2) .. string.sub(sLine, x)
  699.                         setCursor(x - 1, y)
  700.                     end
  701.                 elseif y > 1 then
  702.                     -- Remove newline
  703.                     local sPrevLen = #tLines[y - 1]
  704.                     tLines[y - 1] = tLines[y - 1] .. tLines[y]
  705.                     table.remove(tLines, y)
  706.                     setCursor(sPrevLen + 1, y - 1)
  707.                     redrawText()
  708.                 end
  709.             end
  710.  
  711.         elseif param == keys.enter or param == keys.numPadEnter then
  712.             -- Enter/Numpad Enter
  713.             if not bMenu and not bReadOnly then
  714.                 -- Newline
  715.                 local sLine = tLines[y]
  716.                 local _, spaces = string.find(sLine, "^[ ]+")
  717.                 if not spaces then
  718.                     spaces = 0
  719.                 end
  720.                 tLines[y] = string.sub(sLine, 1, x - 1)
  721.                 table.insert(tLines, y + 1, string.rep(' ', spaces) .. string.sub(sLine, x))
  722.                 setCursor(spaces + 1, y + 1)
  723.                 redrawText()
  724.  
  725.             elseif bMenu then
  726.                 -- Menu selection
  727.                 doMenuItem(nMenuItem)
  728.  
  729.             end
  730.  
  731.         elseif param == keys.leftCtrl or param == keys.rightCtrl then
  732.             -- Menu toggle
  733.             bMenu = not bMenu
  734.             if bMenu then
  735.                 term.setCursorBlink(false)
  736.             else
  737.                 term.setCursorBlink(true)
  738.             end
  739.             redrawMenu()
  740.         elseif param == keys.rightAlt then
  741.             if bMenu then
  742.                 bMenu = false
  743.                 term.setCursorBlink(true)
  744.                 redrawMenu()
  745.             end
  746.         end
  747.  
  748.     elseif sEvent == "char" then
  749.         if not bMenu and not bReadOnly then
  750.             -- Input text
  751.             local sLine = tLines[y]
  752.             tLines[y] = string.sub(sLine, 1, x - 1) .. param .. string.sub(sLine, x)
  753.             setCursor(x + 1, y)
  754.  
  755.         elseif bMenu then
  756.             -- Select menu items
  757.             for n, sMenuItem in ipairs(tMenuItems) do
  758.                 if string.lower(string.sub(sMenuItem, 1, 1)) == string.lower(param) then
  759.                     doMenuItem(n)
  760.                     break
  761.                 end
  762.             end
  763.         end
  764.  
  765.     elseif sEvent == "paste" then
  766.         if not bReadOnly then
  767.             -- Close menu if open
  768.             if bMenu then
  769.                 bMenu = false
  770.                 term.setCursorBlink(true)
  771.                 redrawMenu()
  772.             end
  773.             -- Input text
  774.             local sLine = tLines[y]
  775.             tLines[y] = string.sub(sLine, 1, x - 1) .. param .. string.sub(sLine, x)
  776.             setCursor(x + #param , y)
  777.         end
  778.  
  779.     elseif sEvent == "mouse_click" then
  780.         local cx, cy = param2, param3
  781.         if not bMenu then
  782.             if param == 1 then
  783.                 -- Left click
  784.                 if cy < h then
  785.                     local newY = math.min(math.max(scrollY + cy, 1), #tLines)
  786.                     local newX = math.min(math.max(scrollX + cx, 1), #tLines[newY] + 1)
  787.                     setCursor(newX, newY)
  788.                 else
  789.                     bMenu = true
  790.                     redrawMenu()
  791.                 end
  792.             end
  793.         else
  794.             if cy == h then
  795.                 local nMenuPosEnd = 1
  796.                 local nMenuPosStart = 1
  797.                 for n, sMenuItem in ipairs(tMenuItems) do
  798.                     nMenuPosEnd = nMenuPosEnd + #sMenuItem + 1
  799.                     if cx > nMenuPosStart and cx < nMenuPosEnd then
  800.                         doMenuItem(n)
  801.                     end
  802.                     nMenuPosEnd = nMenuPosEnd + 1
  803.                     nMenuPosStart = nMenuPosEnd
  804.                 end
  805.             else
  806.                 bMenu = false
  807.                 term.setCursorBlink(true)
  808.                 redrawMenu()
  809.             end
  810.         end
  811.  
  812.     elseif sEvent == "mouse_scroll" then
  813.         if not bMenu then
  814.             if param == -1 then
  815.                 -- Scroll up
  816.                 if scrollY > 0 then
  817.                     -- Move cursor up
  818.                     scrollY = scrollY - 1
  819.                     redrawText()
  820.                 end
  821.  
  822.             elseif param == 1 then
  823.                 -- Scroll down
  824.                 local nMaxScroll = #tLines - (h - 1)
  825.                 if scrollY < nMaxScroll then
  826.                     -- Move cursor down
  827.                     scrollY = scrollY + 1
  828.                     redrawText()
  829.                 end
  830.  
  831.             end
  832.         end
  833.  
  834.     elseif sEvent == "term_resize" then
  835.         w, h = term.getSize()
  836.         setCursor(x, y)
  837.         redrawMenu()
  838.         redrawText()
  839.  
  840.     end
  841. end
  842.  
  843. -- Cleanup
  844. term.clear()
  845. term.setCursorBlink(false)
  846. term.setCursorPos(1, 1)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement