Advertisement
rungholt

shedit AltGr Patch

Feb 12th, 2021
623
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. if not fs.exists('lex') then
  2.     shell.run('pastebin get edyuQ5xY lex')
  3. end
  4.  
  5. local lexSuccess = os.loadAPI('lex')
  6.  
  7. if not lexSuccess or not lex or not lex.lex then
  8.     print('A valid lexer is required (file `lex` seems to be broken or not a lexer)')
  9.     return
  10. end
  11.  
  12. -- Get file to edit
  13. local tArgs = { ... }
  14. if #tArgs == 0 then
  15.     print( "Usage: shedit <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. local x,y = 1,1
  28. local markX, markY = 1, 1
  29. local w,h = term.getSize()
  30. local scrollX, scrollY = 0,0
  31.  
  32. local tLines = {}
  33. local bRunning = true
  34.  
  35. -- Colors
  36. local highlightColor, keywordColor, commentColor, textColor, bgColor, stringColor
  37. if term.isColor() then
  38.     bgColor = colors.black
  39.     textColor = colors.white
  40.     highlightColor = colors.yellow
  41.     keywordColor = colors.yellow
  42.     commentColor = colors.green
  43.     stringColor = colors.red
  44. else
  45.     bgColor = colors.black
  46.     textColor = colors.white
  47.     highlightColor = colors.white
  48.     keywordColor = colors.white
  49.     commentColor = colors.white
  50.     stringColor = colors.white
  51. end
  52.  
  53. -- Menus
  54. local bMenu = false
  55. local nMenuItem = 1
  56. local tMenuItems = {}
  57. if not bReadOnly then
  58.     table.insert( tMenuItems, "Save" )
  59. end
  60. if shell.openTab then
  61.     table.insert( tMenuItems, "Run" )
  62. end
  63. if peripheral.find( "printer" ) then
  64.     table.insert( tMenuItems, "Print" )
  65. end
  66. table.insert( tMenuItems, "Exit" )
  67. table.insert(tMenuItems, 'Tools')
  68. table.insert(tMenuItems, 'Find')
  69. table.insert(tMenuItems, 'Jump')
  70. table.insert(tMenuItems, 'Copy')
  71. table.insert(tMenuItems, 'VPaste')
  72.  
  73. local sStatus = "Press Ctrl to access menu"
  74. if string.len( sStatus ) > w - 5 then
  75.     sStatus = "Press Ctrl for menu"
  76. end
  77.  
  78. local function load( _sPath )
  79.     tLines = {}
  80.     if fs.exists( _sPath ) then
  81.         local file = io.open( _sPath, "r" )
  82.         local sLine = file:read()
  83.         while sLine do
  84.             table.insert( tLines, sLine )
  85.             sLine = file:read()
  86.         end
  87.         file:close()
  88.     end
  89.  
  90.     if #tLines == 0 then
  91.         table.insert( tLines, "" )
  92.     end
  93. end
  94.  
  95. local function save( _sPath )
  96.     -- Create intervening folder
  97.     local sDir = _sPath:sub(1, _sPath:len() - fs.getName(_sPath):len() )
  98.     if not fs.exists( sDir ) then
  99.         fs.makeDir( sDir )
  100.     end
  101.  
  102.     -- Save
  103.     local file = nil
  104.     local function innerSave()
  105.         file = fs.open( _sPath, "w" )
  106.         if file then
  107.             for n, sLine in ipairs( tLines ) do
  108.                 file.write( sLine .. "\n" )
  109.             end
  110.         else
  111.             error( "Failed to open ".._sPath )
  112.         end
  113.     end
  114.  
  115.     local ok, err = pcall( innerSave )
  116.     if file then
  117.         file.close()
  118.     end
  119.     return ok, err
  120. end
  121.  
  122. local tKeywords = {
  123.     ["and"] = true,
  124.     ["break"] = true,
  125.     ["do"] = true,
  126.     ["else"] = true,
  127.     ["elseif"] = true,
  128.     ["end"] = true,
  129.     ["false"] = true,
  130.     ["for"] = true,
  131.     ["function"] = true,
  132.     ["if"] = true,
  133.     ["in"] = true,
  134.     ["local"] = true,
  135.     ["nil"] = true,
  136.     ["not"] = true,
  137.     ["or"] = true,
  138.     ["repeat"] = true,
  139.     ["return"] = true,
  140.     ["then"] = true,
  141.     ["true"] = true,
  142.     ["until"]= true,
  143.     ["while"] = true,
  144. }
  145.  
  146. local function tryWrite( sLine, regex, color )
  147.     local match = string.match( sLine, regex )
  148.     if match then
  149.         if type(color) == "number" then
  150.             term.setTextColor( color )
  151.         else
  152.             term.setTextColor( color(match) )
  153.         end
  154.         term.write( match )
  155.         term.setTextColor( textColor )
  156.         return string.sub( sLine, string.len(match) + 1 )
  157.     end
  158.     return nil
  159. end
  160.  
  161. --[[local function writeHighlighted( sLine )
  162.     while string.len(sLine) > 0 do
  163.         sLine =
  164.             tryWrite( sLine, "^%-%-%[%[.-%]%]", commentColor ) or
  165.             tryWrite( sLine, "^%-%-.*", commentColor ) or
  166.             tryWrite( sLine, "^\"\"", stringColor ) or
  167.             tryWrite( sLine, "^\".-[^\\]\"", stringColor ) or
  168.             tryWrite( sLine, "^\'\'", stringColor ) or
  169.             tryWrite( sLine, "^\'.-[^\\]\'", stringColor ) or
  170.             tryWrite( sLine, "^%[%[.-%]%]", stringColor ) or
  171.             tryWrite( sLine, "^[%w_]+", function( match )
  172.                 if tKeywords[ match ] then
  173.                     return keywordColor
  174.                 end
  175.                 return textColor
  176.             end ) or
  177.             tryWrite( sLine, "^[^%w_]", textColor )
  178.     end
  179. end]]
  180.  
  181. local apis = {
  182.     -- tables
  183.     bit = true,
  184.     bit32 = true,
  185.     bitop = true,
  186.     colors = true,
  187.     colours = true,
  188.     coroutine = true,
  189.     disk = true,
  190.     fs = true,
  191.     gps = true,
  192.     help = true,
  193.     http = true,
  194.     io = true,
  195.     keys = true,
  196.     math = true,
  197.     os = true,
  198.     paintutils = true,
  199.     parallel = true,
  200.     peripheral = true,
  201.     rednet = true,
  202.     redstone = true,
  203.     rs = true,
  204.     settings = true,
  205.     shell = true,
  206.     socket = true,
  207.     string = true,
  208.     table = true,
  209.     term = true,
  210.     textutils = true,
  211.     vector = true,
  212.     window = true,
  213.  
  214.     -- functions
  215.     assert = true,
  216.     collectgarbage = true,
  217.     dofile = true,
  218.     error = true,
  219.     getfenv = true,
  220.     getmetatable = true,
  221.     ipairs = true,
  222.     loadfile = true,
  223.     loadstring = true,
  224.     module = true,
  225.     next = true,
  226.     pairs = true,
  227.     pcall = true,
  228.     print = true,
  229.     rawequal = true,
  230.     rawget = true,
  231.     rawset = true,
  232.     require = true,
  233.     select = true,
  234.     setfenv = true,
  235.     setmetatable = true,
  236.     tonumber = true,
  237.     tostring = true,
  238.     type = true,
  239.     unpack = true,
  240.     xpcall =  true,
  241.     printError = true,
  242.     write = true
  243. }
  244.  
  245. local function onUpdate()
  246.     tokenized = lex.lex(table.concat(tLines, '\n'))
  247. end
  248.  
  249. local function markExists()
  250.     if markX ~= x or markY ~= y then
  251.         return true
  252.     else
  253.         return false
  254.     end
  255. end
  256.  
  257. local function isMarked(newX, newY)
  258.     if (newY > markY and newY < y) or (newY > y and newY < markY) then
  259.         return true
  260.     end
  261.  
  262.     if newY == markY and newY == y then
  263.         if markX > x and newX >= x and newX < markX then
  264.             return true
  265.         elseif markX < x and newX >= markX and newX < x then
  266.             return true
  267.         end
  268.     elseif newY == markY then
  269.         if newX < markX and y < markY then
  270.             return true
  271.         elseif newX >= markX and y > markY then
  272.             return true
  273.         end
  274.     elseif newY == y then
  275.         if newX < x and y > markY then
  276.             return true
  277.         elseif newX >= x and y < markY then
  278.             return true
  279.         end
  280.     end
  281.  
  282.     return false
  283. end
  284.  
  285. local function getMarks()
  286.     local msx, msy
  287.     local mex, mey
  288.  
  289.     if markY == y then
  290.         if markX > x then
  291.             msx = x
  292.             msy = y
  293.             mex = markX
  294.             mey = markY
  295.         else
  296.             msx = markX
  297.             msy = markY
  298.             mex = x
  299.             mey = y
  300.         end
  301.     else
  302.         if markY > y then
  303.             msx = x
  304.             msy = y
  305.             mex = markX
  306.             mey = markY
  307.         else
  308.             msx = markX
  309.             msy = markY
  310.             mex = x
  311.             mey = y
  312.         end
  313.     end
  314.  
  315.     return msx, msy, mex, mey
  316. end
  317.  
  318. local function getCharDisplay(char)
  319.     if char == '\t' then
  320.         return '    '
  321.     else
  322.         return char
  323.     end
  324. end
  325.  
  326. local function getCharWidth(char)
  327.     return getCharDisplay(char):len()
  328. end
  329.  
  330. local function writeHighlighted(lineNr)
  331.     local tokens = tokenized[lineNr] or {}
  332.     local textColor = term.getTextColor()
  333.     local bgColor = term.getBackgroundColor()
  334.     local setX, setY = term.getCursorPos()
  335.     local msx, msy, mex, mey = getMarks()
  336.  
  337.     if lineNr < mey and lineNr >= msy then
  338.         term.setBackgroundColor(colors.white)
  339.     end
  340.  
  341.     term.clearLine()
  342.     term.setCursorPos(setX, setY)
  343.  
  344.     for t = 1, #tokens do
  345.         local token = tokens[t]
  346.         local color = colors.white
  347.  
  348.         if token.type == 'keyword' or token.type == 'operator' then
  349.             color = colors.yellow
  350.         elseif token.type == 'number' or token.type == 'value' then
  351.             color = colors.purple
  352.         elseif token.type == 'comment' then
  353.             color = colors.green
  354.         elseif token.type == 'ident' and apis[token.data] then
  355.             color = colors.lightGray
  356.         elseif token.type == 'string' then
  357.             color = colors.cyan
  358.         elseif token.type == 'escape' then
  359.             color = colors.purple
  360.         elseif token.type == 'unidentified' then
  361.             color = colors.red
  362.         end
  363.  
  364.         for p = 1, #token.data do
  365.             local sub = getCharDisplay(token.data:sub(p, p))
  366.  
  367.             local cX, cY = p + token.posFirst - 1, lineNr
  368.  
  369.             if (cY == msy and cY == mey and cX >= msx and cX < mex) or (cY == msy and cY ~= mey and cX >= msx) or (cY == mey and cY ~= msy and cX < mex) or (cY > msy and cY < mey) then
  370.                 term.setTextColor(colors.black)
  371.                 term.setBackgroundColor(color)
  372.             else
  373.                 term.setBackgroundColor(colors.black)
  374.                 term.setTextColor(color)
  375.             end
  376.  
  377.             term.write(sub)
  378.         end
  379.     end
  380.  
  381.     term.setTextColor(textColor)
  382.     term.setBackgroundColor(bgColor)
  383. end
  384.  
  385. local tCompletions
  386. local nCompletion
  387.  
  388. local tCompleteEnv = _ENV
  389. local function complete( sLine )
  390.     if settings.get( "edit.autocomplete" ) then
  391.         local nStartPos = string.find( sLine, "[a-zA-Z0-9_%.]+$" )
  392.         if nStartPos then
  393.             sLine = string.sub( sLine, nStartPos )
  394.         end
  395.         if #sLine > 0 then
  396.             return textutils.complete( sLine, tCompleteEnv )
  397.         end
  398.     end
  399.     return nil
  400. end
  401.  
  402. local function recomplete()
  403.     local sLine = tLines[y]
  404.     if not bMenu and not bReadOnly and x == string.len(sLine) + 1 then
  405.         tCompletions = complete( sLine )
  406.         if tCompletions and #tCompletions > 0 then
  407.             nCompletion = 1
  408.         else
  409.             nCompletion = nil
  410.         end
  411.     else
  412.         tCompletions = nil
  413.         nCompletion = nil
  414.     end
  415. end
  416.  
  417. local function writeCompletion( sLine )
  418.     if nCompletion then
  419.         local sCompletion = tCompletions[ nCompletion ]
  420.         term.setTextColor( colors.white )
  421.         term.setBackgroundColor( colors.gray )
  422.         term.write( sCompletion )
  423.         term.setTextColor( textColor )
  424.         term.setBackgroundColor( bgColor )
  425.     end
  426. end
  427.  
  428. local function getCursorX(lineNr)
  429.     local line = tLines[lineNr]
  430.     local cx = 1
  431.  
  432.     for i = 1, x - 1 do
  433.         cx = cx + getCharWidth(line:sub(i, i))
  434.     end
  435.  
  436.     return cx
  437. end
  438.  
  439. local function cxToPos(lineNr, cx)
  440.     local line = tLines[lineNr]
  441.     local num = 1
  442.     local pos = 1
  443.  
  444.     for i = 1, #line do
  445.         amt = getCharWidth(line:sub(i, i))
  446.  
  447.         if num + amt > cx then
  448.             return pos
  449.         else
  450.             num = num + amt
  451.             pos = pos + 1
  452.         end
  453.     end
  454.  
  455.     return pos
  456. end
  457.  
  458. local function redrawText()
  459.     local cursorX, cursorY = x, y
  460.     for y=1,h-1 do
  461.         term.setCursorPos( 1 - scrollX, y )
  462.         term.clearLine()
  463.  
  464.         local sLine = tLines[ y + scrollY ]
  465.         if sLine ~= nil then
  466.             --writeHighlighted( sLine )
  467.             writeHighlighted(y + scrollY)
  468.             if cursorY == y and cursorX == #sLine + 1 then
  469.                 writeCompletion()
  470.             end
  471.         end
  472.     end
  473.  
  474.     local cx = getCursorX(y)
  475.  
  476.     term.setCursorPos( cx - scrollX, y - scrollY )
  477. end
  478.  
  479. --[[local function redrawLine(_nY)
  480.     local sLine = tLines[_nY]
  481.     if sLine then
  482.         term.setCursorPos( 1 - scrollX, _nY - scrollY )
  483.         term.clearLine()
  484.         --writeHighlighted( sLine )
  485.         writeHighlighted(_nY)
  486.         if _nY == y and x == #sLine + 1 then
  487.             writeCompletion()
  488.         end
  489.         term.setCursorPos( x - scrollX, _nY - scrollY )
  490.     end
  491. end]]
  492.  
  493. local redrawLine = redrawText
  494.  
  495. local function redrawMenu()
  496.     -- Clear line
  497.     term.setCursorPos( 1, h )
  498.     term.clearLine()
  499.  
  500.     -- Draw line numbers
  501.     --[[term.setCursorPos( w - string.len( "Ln "..y ) + 1, h )
  502.     term.setTextColor( highlightColor )
  503.     term.write( "Ln " )
  504.     term.setTextColor( textColor )
  505.     term.write( y )]]
  506.  
  507.     if not bMenu then
  508.         -- Draw status
  509.         term.setTextColor( highlightColor )
  510.         term.write( sStatus )
  511.         term.setTextColor( textColor )
  512.  
  513.         term.setCursorPos(w - ('[' .. x .. ':' .. y .. ']:[' .. markX .. ':' .. markY .. ']'):len() + 1, h)
  514.         term.setTextColor(highlightColor)
  515.         term.write('[')
  516.         term.setTextColor(textColor)
  517.         term.write(x)
  518.         term.setTextColor(highlightColor)
  519.         term.write(':')
  520.         term.setTextColor(textColor)
  521.         term.write(y)
  522.         term.setTextColor(highlightColor)
  523.         term.write(']:[')
  524.         term.setTextColor(textColor)
  525.         term.write(markX)
  526.         term.setTextColor(highlightColor)
  527.         term.write(':')
  528.         term.setTextColor(textColor)
  529.         term.write(markY)
  530.         term.setTextColor(highlightColor)
  531.         term.write(']')
  532.         term.setTextColor(textColor)
  533.     else
  534.         -- Draw menu
  535.         term.setTextColor( textColor )
  536.         for nItem,sItem in pairs( tMenuItems ) do
  537.             if nItem == nMenuItem then
  538.                 term.setTextColor( highlightColor )
  539.                 term.write( "[" )
  540.                 term.setTextColor( textColor )
  541.                 term.write( sItem )
  542.                 term.setTextColor( highlightColor )
  543.                 term.write( "]" )
  544.                 term.setTextColor( textColor )
  545.             else
  546.                 term.write( " "..sItem.." " )
  547.             end
  548.         end
  549.     end
  550.  
  551.     -- Reset cursor
  552.     term.setCursorPos( getCursorX(y) - scrollX, y - scrollY )
  553. end
  554.  
  555. local function setCursor( newX, newY )
  556.     local oldX, oldY = x, y
  557.     x, y = newX, newY
  558.     local screenX = getCursorX(y) - scrollX
  559.     local screenY = y - scrollY
  560.  
  561.     local bRedraw = false
  562.     if screenX < 1 then
  563.         scrollX = getCursorX(y) - 1
  564.         screenX = 1
  565.         bRedraw = true
  566.     elseif screenX > w then
  567.         scrollX = scrollX + (screenX - w)
  568.         screenX = w
  569.         bRedraw = true
  570.     end
  571.  
  572.     if screenY < 1 then
  573.         scrollY = y - 1
  574.         screenY = 1
  575.         bRedraw = true
  576.     elseif screenY > h-1 then
  577.         scrollY = y - (h-1)
  578.         screenY = h-1
  579.         bRedraw = true
  580.     end
  581.  
  582.     recomplete()
  583.     if bRedraw then
  584.         redrawText()
  585.     elseif y ~= oldY then
  586.         redrawLine( oldY )
  587.         redrawLine( y )
  588.     else
  589.         redrawLine( y )
  590.     end
  591.     term.setCursorPos( screenX, screenY )
  592.  
  593.     redrawMenu()
  594. end
  595.  
  596. local function setCursorMark(newX, newY)
  597.     markX, markY = newX, newY
  598.     setCursor(newX, newY)
  599. end
  600.  
  601. local function deleteMarked()
  602.     if markExists() then
  603.         local msx, msy, mex, mey = getMarks()
  604.  
  605.         if msy == mey then
  606.             local line = tLines[mey]
  607.  
  608.             tLines[mey] = line:sub(1, msx - 1) .. line:sub(mex)
  609.         else
  610.             if mey - msy > 1 then
  611.                 for i = 1, mey - msy - 1 do
  612.                     table.remove(tLines, msy + 1)
  613.                 end
  614.             end
  615.  
  616.             local line = tLines[msy]
  617.             local line2 = tLines[msy + 1]
  618.  
  619.             tLines[msy] = line:sub(1, msx - 1) .. line2:sub(mex)
  620.             table.remove(tLines, msy + 1)
  621.         end
  622.  
  623.         setCursorMark(msx, msy)
  624.     end
  625. end
  626.  
  627. local function getMarked()
  628.     if markExists() then
  629.         local msx, msy, mex, mey = getMarks()
  630.  
  631.         if msy == mey then
  632.             return tLines[msy]:sub(msx, mex - 1)
  633.         else
  634.             local marked = tLines[msy]:sub(msx)
  635.  
  636.             if mey - msy > 1 then
  637.                 for i = msy + 1, mey - 1 do
  638.                     marked = marked .. '\n' .. tLines[i]
  639.                 end
  640.             end
  641.  
  642.             marked = marked .. '\n' .. tLines[mey]:sub(1, mex - 1)
  643.  
  644.             return marked
  645.         end
  646.     end
  647. end
  648.  
  649. local toolsFuncs = {
  650.     {
  651.         'Convert 2 spaces to tabs',
  652.         function()
  653.             for i = 1, #tLines do
  654.                 local line = tLines[i]
  655.                 local count = 0
  656.  
  657.                 while true do
  658.                     if line:sub(count * 2 + 1, count * 2 + 2) == '  ' then
  659.                         count = count + 1
  660.                     else
  661.                         break
  662.                     end
  663.                 end
  664.  
  665.                 tLines[i] = ('\t'):rep(count) .. line:sub(count * 2 + 1)
  666.             end
  667.         end
  668.     }, {
  669.         'Convert tabs to 2 spaces',
  670.         function()
  671.             for i = 1, #tLines do
  672.                 local line = tLines[i]
  673.                 local count = 0
  674.  
  675.                 while true do
  676.                     if line:sub(count + 1, count + 1) == '\t' then
  677.                         count = count + 1
  678.                     else
  679.                         break
  680.                     end
  681.                 end
  682.  
  683.                 tLines[i] = ('  '):rep(count) .. line:sub(count + 1)
  684.             end
  685.         end
  686.     }
  687. }
  688.  
  689. -- for testing scrolling, etc in the tools menu
  690. --[[for i = 1, 50 do
  691.     table.insert(toolsFuncs, {'Do nothing ' .. tostring(i), function() end})
  692. end]]
  693.  
  694.  
  695. local findHistory = {}
  696. local jumpHistory = {}
  697. local vClipboard = ''
  698.  
  699. local tMenuFuncs = {
  700.     Save = function()
  701.         if bReadOnly then
  702.             sStatus = "Access denied"
  703.         else
  704.             local ok, err = save( sPath )
  705.             if ok then
  706.                 sStatus="Saved to "..sPath
  707.             else
  708.                 sStatus="Error saving to "..sPath
  709.             end
  710.         end
  711.         redrawMenu()
  712.     end,
  713.     Print = function()
  714.         local printer = peripheral.find( "printer" )
  715.         if not printer then
  716.             sStatus = "No printer attached"
  717.             return
  718.         end
  719.  
  720.         local nPage = 0
  721.         local sName = fs.getName( sPath )
  722.         if printer.getInkLevel() < 1 then
  723.             sStatus = "Printer out of ink"
  724.             return
  725.         elseif printer.getPaperLevel() < 1 then
  726.             sStatus = "Printer out of paper"
  727.             return
  728.         end
  729.  
  730.         local screenTerminal = term.current()
  731.         local printerTerminal = {
  732.             getCursorPos = printer.getCursorPos,
  733.             setCursorPos = printer.setCursorPos,
  734.             getSize = printer.getPageSize,
  735.             write = printer.write,
  736.         }
  737.         printerTerminal.scroll = function()
  738.             if nPage == 1 then
  739.                 printer.setPageTitle( sName.." (page "..nPage..")" )
  740.             end
  741.  
  742.             while not printer.newPage() do
  743.                 if printer.getInkLevel() < 1 then
  744.                     sStatus = "Printer out of ink, please refill"
  745.                 elseif printer.getPaperLevel() < 1 then
  746.                     sStatus = "Printer out of paper, please refill"
  747.                 else
  748.                     sStatus = "Printer output tray full, please empty"
  749.                 end
  750.  
  751.                 term.redirect( screenTerminal )
  752.                 redrawMenu()
  753.                 term.redirect( printerTerminal )
  754.  
  755.                 local timer = os.startTimer(0.5)
  756.                 sleep(0.5)
  757.             end
  758.  
  759.             nPage = nPage + 1
  760.             if nPage == 1 then
  761.                 printer.setPageTitle( sName )
  762.             else
  763.                 printer.setPageTitle( sName.." (page "..nPage..")" )
  764.             end
  765.         end
  766.  
  767.         bMenu = false
  768.         term.redirect( printerTerminal )
  769.         local ok, error = pcall( function()
  770.             term.scroll()
  771.             for n, sLine in ipairs( tLines ) do
  772.                 print( sLine )
  773.             end
  774.         end )
  775.         term.redirect( screenTerminal )
  776.         if not ok then
  777.             print( error )
  778.         end
  779.  
  780.         while not printer.endPage() do
  781.             sStatus = "Printer output tray full, please empty"
  782.             redrawMenu()
  783.             sleep( 0.5 )
  784.         end
  785.         bMenu = true
  786.  
  787.         if nPage > 1 then
  788.             sStatus = "Printed "..nPage.." Pages"
  789.         else
  790.             sStatus = "Printed 1 Page"
  791.         end
  792.         redrawMenu()
  793.     end,
  794.     Exit = function()
  795.         bRunning = false
  796.     end,
  797.     Run = function()
  798.         local sTempPath = "/.temp"
  799.         local ok, err = save( sTempPath )
  800.         if ok then
  801.             local nTask = shell.openTab( sTempPath )
  802.             if nTask then
  803.                 shell.switchTab( nTask )
  804.             else
  805.                 sStatus="Error starting Task"
  806.             end
  807.             fs.delete( sTempPath )
  808.         else
  809.             sStatus="Error saving to "..sTempPath
  810.         end
  811.         redrawMenu()
  812.     end,
  813.     Tools = function()
  814.         bMenu = false
  815.         redrawText()
  816.         redrawMenu()
  817.  
  818.         local bgColor = term.getBackgroundColor()
  819.         paintutils.drawFilledBox(2, 2, w - 1, h - 1, colors.gray)
  820.         term.setCursorPos(3, 3)
  821.         term.write('ShEdit Tools')
  822.  
  823.         local scrollY = 0
  824.         local height = h - 8
  825.         local offset = 5
  826.         local selected = 1
  827.         local run = false
  828.  
  829.         term.setTextColor(colors.lightGray)
  830.         term.setCursorPos(3, offset + height + 1)
  831.         term.write('Arrows to select. Enter to run. Ctrl to cancel.')
  832.  
  833.         while true do
  834.             term.setBackgroundColor(colors.gray)
  835.             term.setTextColor(colors.lightGray)
  836.             local toWrite = '(' .. tostring(selected) .. '/' .. tostring(#toolsFuncs) .. ')'
  837.             term.setCursorPos(w - toWrite:len() - 1, 3)
  838.             term.write(toWrite)
  839.             term.setTextColor(colors.white)
  840.  
  841.             for i = 1, height do
  842.                 local index = i + scrollY
  843.                 term.setTextColor(colors.white)
  844.  
  845.                 if selected == index then
  846.                     term.setTextColor(keywordColor)
  847.                 end
  848.  
  849.                 if index <= #toolsFuncs then
  850.                     paintutils.drawLine(2, offset + i - 1, w - 1, offset + i - 1, color)
  851.                     term.setCursorPos(3, offset + index - scrollY - 1)
  852.  
  853.                     if selected == index then
  854.                         term.write('> ')
  855.                     else
  856.                         term.write('  ')
  857.                     end
  858.  
  859.                     term.write(toolsFuncs[index][1])
  860.                 end
  861.             end
  862.  
  863.             local evt, arg1, arg2, arg3 = os.pullEvent()
  864.             local clampScroll = false
  865.  
  866.             if evt == 'key' then
  867.                 clampScroll = true
  868.  
  869.                 if arg1 == keys.up then
  870.                     if selected == 1 then
  871.                         selected = #toolsFuncs
  872.                     else
  873.                         selected = selected - 1
  874.                     end
  875.                 elseif arg1 == keys.down then
  876.                     if selected == #toolsFuncs then
  877.                         selected = 1
  878.                     else
  879.                         selected = selected + 1
  880.                     end
  881.                 elseif arg1 == keys.pageUp then
  882.                     selected = math.max(1, math.min(#toolsFuncs, selected - height))
  883.                 elseif arg1 == keys.pageDown then
  884.                     selected = math.max(1, math.min(#toolsFuncs, selected + height))
  885.                 elseif arg1 == keys.enter then
  886.                     run = true
  887.  
  888.                     break
  889.                 elseif arg1 == keys.leftCtrl then
  890.                     break
  891.                 else
  892.                     clampScroll = false
  893.                 end
  894.             elseif evt == 'mouse_click' then
  895.                 if arg1 == 1 then
  896.                     if arg2 > 1 and arg2 < w then
  897.                         if arg3 >= offset and arg3 < offset + height then
  898.                             local index = arg3 - offset + scrollY + 1
  899.  
  900.                             if index <= #toolsFuncs then
  901.                                 selected = index
  902.                                 run = true
  903.  
  904.                                 break
  905.                             end
  906.                         end
  907.                     end
  908.                 end
  909.             elseif evt == 'mouse_scroll' then
  910.                 if arg2 > 1 and arg2 < w then
  911.                     if arg3 >= offset and arg3 < offset + height then
  912.                         scrollY = math.max(0, math.min(#toolsFuncs - height, scrollY + arg1))
  913.                     end
  914.                 end
  915.             end
  916.  
  917.             if clampScroll == true then
  918.                 if selected > height + scrollY then
  919.                     scrollY = selected - height
  920.                 elseif selected <= scrollY then
  921.                     scrollY = selected - 1
  922.                 end
  923.             end
  924.         end
  925.  
  926.         term.setBackgroundColor(bgColor)
  927.         redrawText()
  928.         bMenu = true
  929.  
  930.         if run then
  931.             if not bReadOnly then
  932.                 bMenu = false
  933.                 redrawMenu()
  934.                 toolsFuncs[selected][2]()
  935.                 onUpdate()
  936.                 redrawText()
  937.                 bMenu = true
  938.             else
  939.                 sStatus = 'File is read-only'
  940.             end
  941.         end
  942.     end,
  943.     Find = function()
  944.         term.setCursorPos(1, h)
  945.         term.clearLine()
  946.  
  947.         term.setTextColor(highlightColor)
  948.         term.write('Find: ')
  949.         term.setTextColor(textColor)
  950.  
  951.         local text = read(nil, findHistory)
  952.         table.insert(findHistory, text)
  953.  
  954.         local fLine, fPos
  955.         local found = false
  956.  
  957.         for i = y, #tLines do
  958.             local searchText = tLines[i]
  959.  
  960.             if i == y then
  961.                 searchText = searchText:sub(x + 1)
  962.             end
  963.  
  964.             local searchPat = ''
  965.  
  966.             local escapedChars = {
  967.                 ['%'] = true, ['.'] = true, ['('] = true, [')'] = true,
  968.                 ['%'] = true, ['+'] = true, ['-'] = true, ['*'] = true,
  969.                 ['?'] = true, ['['] = true, ['^'] = true, ['$'] = true
  970.             }
  971.  
  972.             for i = 1, #text do
  973.                 local char = text:sub(i, i)
  974.  
  975.                 if escapedChars[char] == true then
  976.                     searchPat = searchPat .. '%'
  977.                 end
  978.  
  979.                 searchPat = searchPat .. char
  980.             end
  981.  
  982.             local pos = searchText:find(searchPat)
  983.  
  984.             if pos then
  985.                 fLine = i
  986.                 fPos = pos
  987.  
  988.                 if i == y then
  989.                     fPos = fPos + x
  990.                 end
  991.  
  992.                 found = true
  993.  
  994.                 break
  995.             end
  996.         end
  997.  
  998.         if not found then
  999.             sStatus = 'Found no matches'
  1000.         else
  1001.             setCursorMark(fPos, fLine)
  1002.             setCursor(fPos + text:len(), fLine)
  1003.             sStatus = 'Found a match on line ' .. tostring(fLine)
  1004.         end
  1005.  
  1006.         redrawText()
  1007.     end,
  1008.     Jump = function()
  1009.         term.setCursorPos(1, h)
  1010.         term.clearLine()
  1011.  
  1012.         term.setTextColor(highlightColor)
  1013.         term.write('Jump: ')
  1014.         term.setTextColor(textColor)
  1015.  
  1016.         local toJump = read(nil, jumpHistory)
  1017.         table.insert(jumpHistory, toJump)
  1018.  
  1019.         local num = tonumber(toJump)
  1020.  
  1021.         if not num then
  1022.             sStatus = 'Invalid line'
  1023.         else
  1024.             if num % 1 == 0 then
  1025.                 if num >= 1 and num <= #tLines then
  1026.                     setCursorMark(1, num)
  1027.                     sStatus = 'Successfully jumped to line ' .. toJump
  1028.                 else
  1029.                     sStatus = 'Line is not in the range 1 - ' .. tostring(#tLines)
  1030.                 end
  1031.             else
  1032.                 sStatus = 'Line must be an integer'
  1033.             end
  1034.         end
  1035.  
  1036.         redrawText()
  1037.     end,
  1038.     Copy = function()
  1039.         vClipboard = getMarked()
  1040.  
  1041.         local lines = 1
  1042.  
  1043.         for i = 1, #vClipboard do
  1044.             if vClipboard:sub(i, i) == '\n' then
  1045.                 lines = lines + 1
  1046.             end
  1047.         end
  1048.  
  1049.         sStatus = 'Copied ' .. tostring(lines) .. ' lines'
  1050.     end,
  1051.     VPaste = function()
  1052.         if not bReadOnly then
  1053.             deleteMarked()
  1054.             local lines = 1
  1055.  
  1056.             for i = 1, #vClipboard do
  1057.                 local char = vClipboard:sub(i, i)
  1058.  
  1059.                 if char == '\n' then
  1060.                     lines = lines + 1
  1061.                     local sLine = tLines[y]
  1062.                     tLines[y] = string.sub(sLine,1,x-1)
  1063.                     table.insert( tLines, y+1, string.sub(sLine,x) )
  1064.                     x = 1
  1065.                     y = y + 1
  1066.                 else
  1067.                     tLines[y] = tLines[y]:sub(1, x - 1) .. char .. tLines[y]:sub(x)
  1068.                     x = x + 1
  1069.                 end
  1070.             end
  1071.  
  1072.             setCursorMark(x, y)
  1073.             onUpdate()
  1074.             redrawText()
  1075.  
  1076.             sStatus = 'Pasted ' .. tostring(lines) .. ' lines'
  1077.         else
  1078.             sStatus = 'File is read-only'
  1079.         end
  1080.     end
  1081. }
  1082.  
  1083. local function doMenuItem( _n )
  1084.     tMenuFuncs[tMenuItems[_n]]()
  1085.     if bMenu then
  1086.         bMenu = false
  1087.         term.setCursorBlink( true )
  1088.     end
  1089.     redrawMenu()
  1090. end
  1091.  
  1092. -- Actual program functionality begins
  1093. load(sPath)
  1094.  
  1095. term.setBackgroundColor( bgColor )
  1096. term.clear()
  1097. term.setCursorPos(getCursorX(y), y)
  1098. term.setCursorBlink( true )
  1099.  
  1100. recomplete()
  1101. onUpdate()
  1102. redrawText()
  1103. redrawMenu()
  1104.  
  1105. local function acceptCompletion()
  1106.     if nCompletion then
  1107.         -- Append the completion
  1108.         local sCompletion = tCompletions[ nCompletion ]
  1109.         tLines[y] = tLines[y] .. sCompletion
  1110.         onUpdate()
  1111.         setCursorMark( x + string.len( sCompletion ), y )
  1112.     end
  1113. end
  1114.  
  1115. local holdingShift = false
  1116.  
  1117. -- Handle input
  1118. while bRunning do
  1119.     local sEvent, param, param2, param3 = os.pullEvent()
  1120.     if sEvent == "key" then
  1121.         local oldX, oldY = x, y
  1122.         if param == keys.up then
  1123.             local cursorSet = setCursorMark
  1124.  
  1125.             if holdingShift then
  1126.                 cursorSet = setCursor
  1127.             end
  1128.  
  1129.             -- Up
  1130.             if not bMenu then
  1131.                 if nCompletion then
  1132.                     -- Cycle completions
  1133.                     nCompletion = nCompletion - 1
  1134.                     if nCompletion < 1 then
  1135.                         nCompletion = #tCompletions
  1136.                     end
  1137.                     redrawLine(y)
  1138.  
  1139.                 elseif y > 1 then
  1140.                     -- Move cursor up
  1141.                     --[[cursorSet(
  1142.                         math.min( x, string.len( tLines[y - 1] ) + 1 ),
  1143.                         y - 1
  1144.                     )]]
  1145.  
  1146.                     local cx = getCursorX(y)
  1147.                     local pos = cxToPos(y - 1, cx)
  1148.  
  1149.                     cursorSet(pos, y - 1)
  1150.                 else
  1151.                     cursorSet(1, y)
  1152.                 end
  1153.             end
  1154.  
  1155.         elseif param == keys.down then
  1156.             local cursorSet = setCursorMark
  1157.  
  1158.             if holdingShift then
  1159.                 cursorSet = setCursor
  1160.             end
  1161.  
  1162.             -- Down
  1163.             if not bMenu then
  1164.                 -- Move cursor down
  1165.                 if nCompletion then
  1166.                     -- Cycle completions
  1167.                     nCompletion = nCompletion + 1
  1168.                     if nCompletion > #tCompletions then
  1169.                         nCompletion = 1
  1170.                     end
  1171.                     redrawLine(y)
  1172.  
  1173.                 elseif y < #tLines then
  1174.                     -- Move cursor down
  1175.                     --[[cursorSet(
  1176.                         math.min( x, string.len( tLines[y + 1] ) + 1 ),
  1177.                         y + 1
  1178.                     )]]
  1179.  
  1180.                     local cx = getCursorX(y)
  1181.                     local pos = cxToPos(y + 1, cx)
  1182.  
  1183.                     cursorSet(pos, y + 1)
  1184.                 else
  1185.                     cursorSet(#tLines[y] + 1, y)
  1186.                 end
  1187.             end
  1188.  
  1189.         elseif param == keys.tab then
  1190.             -- Tab
  1191.             if not bMenu and not bReadOnly then
  1192.                 if nCompletion and x == string.len(tLines[y]) + 1 then
  1193.                     -- Accept autocomplete
  1194.                     acceptCompletion()
  1195.                 else
  1196.                     local msx, msy, mex, mey = getMarks()
  1197.  
  1198.                     for i = msy, mey do
  1199.                         local line = tLines[i]
  1200.  
  1201.                         if holdingShift then
  1202.                             -- Unindent line
  1203.                             if line:sub(1, 1) == '\t' then
  1204.                                 line = line:sub(2)
  1205.                             end
  1206.                         else
  1207.                             -- Indent line
  1208.                             if markExists() then
  1209.                                 line = '\t' .. line
  1210.                             else
  1211.                                 line = line:sub(1, x - 1) .. '\t' .. line:sub(x)
  1212.                             end
  1213.                         end
  1214.  
  1215.                         tLines[i] = line
  1216.                     end
  1217.  
  1218.                     if holdingShift then
  1219.                         markX = math.max(1, markX - 1)
  1220.                         setCursor(math.max(1, x - 1), y)
  1221.                     else
  1222.                         markX = markX + 1
  1223.                         setCursor(x + 1, y)
  1224.                     end
  1225.  
  1226.                     onUpdate()
  1227.                     redrawText()
  1228.                 end
  1229.             end
  1230.  
  1231.         elseif param == keys.pageUp then
  1232.             local cursorSet = setCursorMark
  1233.  
  1234.             if holdingShift then
  1235.                 cursorSet = setCursor
  1236.             end
  1237.  
  1238.             -- Page Up
  1239.             if not bMenu then
  1240.                 -- Move up a page
  1241.                 local newY
  1242.                 if y - (h - 1) >= 1 then
  1243.                     newY = y - (h - 1)
  1244.                 else
  1245.                     newY = 1
  1246.                 end
  1247.                 cursorSet(
  1248.                     math.min( x, string.len( tLines[newY] ) + 1 ),
  1249.                     newY
  1250.                 )
  1251.             end
  1252.  
  1253.         elseif param == keys.pageDown then
  1254.             local cursorSet = setCursorMark
  1255.  
  1256.             if holdingShift then
  1257.                 cursorSet = setCursor
  1258.             end
  1259.  
  1260.             -- Page Down
  1261.             if not bMenu then
  1262.                 -- Move down a page
  1263.                 local newY
  1264.                 if y + (h - 1) <= #tLines then
  1265.                     newY = y + (h - 1)
  1266.                 else
  1267.                     newY = #tLines
  1268.                 end
  1269.                 local newX = math.min( x, string.len( tLines[newY] ) + 1 )
  1270.                 cursorSet( newX, newY )
  1271.             end
  1272.  
  1273.         elseif param == keys.home then
  1274.             local cursorSet = setCursorMark
  1275.  
  1276.             if holdingShift then
  1277.                 cursorSet = setCursor
  1278.             end
  1279.  
  1280.             -- Home
  1281.             if not bMenu then
  1282.                 -- Move cursor to the beginning
  1283.                 if x > 1 then
  1284.                     cursorSet(1,y)
  1285.                 end
  1286.             end
  1287.  
  1288.         elseif param == keys["end"] then
  1289.             local cursorSet = setCursorMark
  1290.  
  1291.             if holdingShift then
  1292.                 cursorSet = setCursor
  1293.             end
  1294.  
  1295.             -- End
  1296.             if not bMenu then
  1297.                 -- Move cursor to the end
  1298.                 local nLimit = string.len( tLines[y] ) + 1
  1299.                 if x < nLimit then
  1300.                     cursorSet( nLimit, y )
  1301.                 end
  1302.             end
  1303.  
  1304.         elseif param == keys.left then
  1305.             local cursorSet = setCursorMark
  1306.  
  1307.             if holdingShift then
  1308.                 cursorSet = setCursor
  1309.             end
  1310.  
  1311.             -- Left
  1312.             if not bMenu then
  1313.                 if x > 1 then
  1314.                     -- Move cursor left
  1315.                     cursorSet( x - 1, y )
  1316.                 elseif x==1 and y>1 then
  1317.                     cursorSet( string.len( tLines[y-1] ) + 1, y - 1 )
  1318.                 end
  1319.             else
  1320.                 -- Move menu left
  1321.                 nMenuItem = nMenuItem - 1
  1322.                 if nMenuItem < 1 then
  1323.                     nMenuItem = #tMenuItems
  1324.                 end
  1325.                 redrawMenu()
  1326.             end
  1327.  
  1328.         elseif param == keys.right then
  1329.             local cursorSet = setCursorMark
  1330.  
  1331.             if holdingShift then
  1332.                 cursorSet = setCursor
  1333.             end
  1334.  
  1335.             -- Right
  1336.             if not bMenu then
  1337.                 local nLimit = string.len( tLines[y] ) + 1
  1338.                 if x < nLimit then
  1339.                     -- Move cursor right
  1340.                     cursorSet( x + 1, y )
  1341.                 elseif nCompletion and x == string.len(tLines[y]) + 1 then
  1342.                     -- Accept autocomplete
  1343.                     acceptCompletion()
  1344.                 elseif x==nLimit and y<#tLines then
  1345.                     -- Go to next line
  1346.                     cursorSet( 1, y + 1 )
  1347.                 end
  1348.             else
  1349.                 -- Move menu right
  1350.                 nMenuItem = nMenuItem + 1
  1351.                 if nMenuItem > #tMenuItems then
  1352.                     nMenuItem = 1
  1353.                 end
  1354.                 redrawMenu()
  1355.             end
  1356.  
  1357.         elseif param == keys.delete then
  1358.             -- Delete
  1359.             if not bMenu and not bReadOnly then
  1360.                 if markExists() then
  1361.                     deleteMarked()
  1362.                 else
  1363.                     local nLimit = string.len( tLines[y] ) + 1
  1364.                     if x < nLimit then
  1365.                         local sLine = tLines[y]
  1366.                         tLines[y] = string.sub(sLine,1,x-1) .. string.sub(sLine,x+1)
  1367.                     elseif y<#tLines then
  1368.                         tLines[y] = tLines[y] .. tLines[y+1]
  1369.                         table.remove( tLines, y+1 )
  1370.                     end
  1371.                 end
  1372.  
  1373.                 onUpdate()
  1374.                 recomplete()
  1375.                 redrawText()
  1376.             end
  1377.  
  1378.         elseif param == keys.backspace then
  1379.             -- Backspace
  1380.             if not bMenu and not bReadOnly then
  1381.                 if markExists() then
  1382.                     deleteMarked()
  1383.                 else
  1384.                     if x > 1 then
  1385.                         -- Remove character
  1386.                         local sLine = tLines[y]
  1387.                         tLines[y] = string.sub(sLine,1,x-2) .. string.sub(sLine,x)
  1388.                         setCursorMark( x - 1, y )
  1389.                     elseif y > 1 then
  1390.                         -- Remove newline
  1391.                         local sPrevLen = string.len( tLines[y-1] )
  1392.                         tLines[y-1] = tLines[y-1] .. tLines[y]
  1393.                         table.remove( tLines, y )
  1394.                         setCursorMark( sPrevLen + 1, y - 1 )
  1395.                     end
  1396.                 end
  1397.  
  1398.                 onUpdate()
  1399.                 recomplete()
  1400.                 redrawText()
  1401.             end
  1402.  
  1403.         elseif param == keys.enter then
  1404.             -- Enter
  1405.             if not bMenu and not bReadOnly then
  1406.                 deleteMarked()
  1407.  
  1408.                 -- Newline
  1409.                 local sLine = tLines[y]
  1410.                 local _,tabs=string.find(sLine,"^[\t]+")
  1411.                 if not tabs then
  1412.                     tabs=0
  1413.                 end
  1414.                 tLines[y] = string.sub(sLine,1,x-1)
  1415.                 table.insert( tLines, y+1, string.rep('\t',tabs)..string.sub(sLine,x) )
  1416.                 onUpdate()
  1417.                 setCursorMark( tabs + 1, y + 1 )
  1418.                 redrawText()
  1419.  
  1420.             elseif bMenu then
  1421.                 -- Menu selection
  1422.                 doMenuItem( nMenuItem )
  1423.  
  1424.             end
  1425.  
  1426.         elseif (param == keys.leftCtrl or param == keys.rightCtrl) and not param2 then
  1427.             -- Menu toggle
  1428.             bMenu = not bMenu
  1429.             if bMenu then
  1430.                 term.setCursorBlink( false )
  1431.             else
  1432.                 term.setCursorBlink( true )
  1433.             end
  1434.             redrawMenu()
  1435.  
  1436.    elseif (param == keys.rightAlt) then
  1437.        if bMenu then
  1438.            bMenu = false
  1439.            term.setCursorBlink( true )
  1440.            redrawMenu()
  1441.        end
  1442.  
  1443.         elseif param == 42 then
  1444.             holdingShift = true
  1445.         end
  1446.  
  1447.     elseif sEvent == 'key_up' then
  1448.         if param == 42 then
  1449.             holdingShift = false
  1450.         end
  1451.  
  1452.     elseif sEvent == "char" then
  1453.         if not bMenu and not bReadOnly then
  1454.             deleteMarked()
  1455.  
  1456.             -- Input text
  1457.             local sLine = tLines[y]
  1458.             tLines[y] = string.sub(sLine,1,x-1) .. param .. string.sub(sLine,x)
  1459.             onUpdate()
  1460.             setCursorMark( x + 1, y )
  1461.  
  1462.         elseif bMenu then
  1463.             -- Select menu items
  1464.             for n,sMenuItem in ipairs( tMenuItems ) do
  1465.                 if string.lower(string.sub(sMenuItem,1,1)) == string.lower(param) then
  1466.                     doMenuItem( n )
  1467.                     break
  1468.                 end
  1469.             end
  1470.         end
  1471.  
  1472.     elseif sEvent == "paste" then
  1473.         if not bMenu and not bReadOnly then
  1474.             -- Input text
  1475.             --[[local sLine = tLines[y]
  1476.             tLines[y] = string.sub(sLine,1,x-1) .. param .. string.sub(sLine,x)
  1477.             onUpdate()
  1478.             setCursorMark( x + string.len( param ), y )]]
  1479.  
  1480.             --[[deleteMarked()
  1481.  
  1482.             local newX, newY = x, y
  1483.  
  1484.             for i = 1, #param do
  1485.                 local char = param:sub(i, i)
  1486.  
  1487.                 if char == '\n' then
  1488.                     local rest = tLines[newY]:sub(newX)
  1489.                     tLines[newY] = tLines[newY]:sub(1, newX - 1)
  1490.  
  1491.                     table.insert(tLines, rest, newY + 1)
  1492.  
  1493.                     newY = newY + 1
  1494.                     newX = 1
  1495.                 else
  1496.                     local line = tLines[newY]
  1497.  
  1498.                     line = line:sub(1, newX - 1) .. char .. line:sub(newX)
  1499.  
  1500.                     tLines[newY] = line
  1501.                     newX = newX + 1
  1502.                 end
  1503.             end
  1504.  
  1505.             onUpdate()
  1506.             setCursorMark(newX, newY)]]
  1507.  
  1508.             local oldvClipboard = vClipboard
  1509.             vClipboard = param
  1510.             tMenuFuncs.VPaste()
  1511.             redrawMenu()
  1512.             vClipboard = oldvClipboard
  1513.         end
  1514.  
  1515.     elseif sEvent == "mouse_click" then
  1516.         local cursorSet = setCursorMark
  1517.  
  1518.         if holdingShift then
  1519.             cursorSet = setCursor
  1520.         end
  1521.  
  1522.         if not bMenu then
  1523.             if param == 1 then
  1524.                 -- Left click
  1525.                 local cx,cy = param2, param3
  1526.                 if cy < h then
  1527.                     local tx, ty = cx + scrollX, cy + scrollY
  1528.                     local newX, newY
  1529.  
  1530.                     if ty <= #tLines then
  1531.                         newY = math.min(#tLines, math.max(ty, 1))
  1532.                         tx = cxToPos(ty, tx)
  1533.                         newX = math.min(tLines[newY]:len() + 1, math.max(1, tx))
  1534.                     else
  1535.                         newY = #tLines
  1536.                         newX = #tLines[newY] + 1
  1537.                     end
  1538.  
  1539.                     cursorSet(newX, newY)
  1540.                 end
  1541.             end
  1542.         end
  1543.  
  1544.     elseif sEvent == "mouse_drag" then
  1545.         if not bMenu then
  1546.             if param == 1 then
  1547.                 -- Left click
  1548.                 local cx,cy = param2, param3
  1549.                 if cy < h then
  1550.                     local tx, ty = cx + scrollX, cy + scrollY
  1551.                     local newX, newY
  1552.  
  1553.                     if ty <= #tLines then
  1554.                         newY = math.min(#tLines, math.max(ty, 1))
  1555.                         tx = cxToPos(ty, tx)
  1556.                         newX = math.min(tLines[newY]:len() + 1, math.max(1, tx))
  1557.                     else
  1558.                         newY = #tLines
  1559.                         newX = #tLines[newY] + 1
  1560.                     end
  1561.  
  1562.                     setCursor(newX, newY)
  1563.                 end
  1564.             end
  1565.         end
  1566.  
  1567.     elseif sEvent == "mouse_scroll" then
  1568.         if not bMenu then
  1569.             if param == -1 then
  1570.                 -- Scroll up
  1571.                 if scrollY > 0 then
  1572.                     -- Move cursor up
  1573.                     scrollY = scrollY - 1
  1574.                     redrawText()
  1575.                 end
  1576.  
  1577.             elseif param == 1 then
  1578.                 -- Scroll down
  1579.                 local nMaxScroll = #tLines - (h-1)
  1580.                 if scrollY < nMaxScroll then
  1581.                     -- Move cursor down
  1582.                     scrollY = scrollY + 1
  1583.                     redrawText()
  1584.                 end
  1585.  
  1586.             end
  1587.         end
  1588.  
  1589.     elseif sEvent == "term_resize" then
  1590.         w,h = term.getSize()
  1591.         setCursor( x, y )
  1592.         redrawMenu()
  1593.         redrawText()
  1594.  
  1595.     end
  1596. end
  1597.  
  1598. -- Cleanup
  1599. term.clear()
  1600. term.setCursorBlink( false )
  1601. term.setCursorPos( 1, 1 )
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement