FoxWorn3365

edit

Aug 3rd, 2021 (edited)
619
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. -- Get file to edit
  2. local tArgs = { ... }
  3. if #tArgs == 0 then
  4.     print( "Usage: edit <path>" )
  5.     return
  6. end
  7.  
  8. -- Error checking
  9. local sPath = shell.resolve( tArgs[1] )
  10. local bReadOnly = fs.isReadOnly( sPath )
  11. if fs.exists( sPath ) and fs.isDir( sPath ) then
  12.     print( "Cannot edit a directory." )
  13.     return
  14. end
  15.  
  16. local x,y = 1,1
  17. local w,h = term.getSize()
  18. local scrollX, scrollY = 0,0
  19.  
  20. local tLines = {}
  21. local bRunning = true
  22.  
  23. -- Colours
  24. local highlightColour, keywordColour, commentColour, textColour, bgColour
  25. if term.isColour() then
  26.     bgColour = colours.black
  27.     textColour = colours.white
  28.     highlightColour = colours.yellow
  29.     keywordColour = colours.yellow
  30.     commentColour = colours.lime
  31.     stringColour = colours.red
  32.     osColor = colours.orange
  33.     rednetColor = colours.red
  34.     termColor = colours.lightBlue
  35.     peripheralColor = colours.green
  36.     aColor = colours.cyan
  37. else
  38.     bgColour = colours.black
  39.     textColour = colours.white
  40.     highlightColour = colours.white
  41.     keywordColour = colours.white
  42.     commentColour = colours.white
  43.     stringColour = colours.white
  44. end
  45.  
  46. -- Menus
  47. local bMenu = false
  48. local nMenuItem = 1
  49. local tMenuItems = {"Save", "Exit", "Print"}
  50. local sStatus = "Press Ctrl to access menu"
  51.  
  52. local function load(_sPath)
  53.     tLines = {}
  54.     if fs.exists( _sPath ) then
  55.         local file = io.open( _sPath, "r" )
  56.         local sLine = file:read()
  57.         while sLine do
  58.             table.insert( tLines, sLine )
  59.             sLine = file:read()
  60.         end
  61.         file:close()
  62.     end
  63.    
  64.     if #tLines == 0 then
  65.         table.insert( tLines, "" )
  66.     end
  67. end
  68.  
  69. local function save( _sPath )
  70.     -- Create intervening folder
  71.     local sDir = sPath:sub(1, sPath:len() - fs.getName(sPath):len() )
  72.     if not fs.exists( sDir ) then
  73.         fs.makeDir( sDir )
  74.     end
  75.  
  76.     -- Save
  77.     local file = nil
  78.     local function innerSave()
  79.         file = fs.open( _sPath, "w" )
  80.         if file then
  81.             for n, sLine in ipairs( tLines ) do
  82.                 file.write( sLine .. "\n" )
  83.             end
  84.         else
  85.             error( "Failed to open ".._sPath )
  86.         end
  87.     end
  88.    
  89.     local ok = pcall( innerSave )
  90.     if file then
  91.         file.close()
  92.     end
  93.     return ok
  94. end
  95.  
  96. local tKeywords = {
  97.     ["and"] = true,
  98.     ["break"] = true,
  99.     ["do"] = true,
  100.     ["else"] = true,
  101.     ["elseif"] = true,
  102.     ["end"] = true,
  103.     ["false"] = true,
  104.     ["for"] = true,
  105.     ["function"] = true,
  106.     ["if"] = true,
  107.     ["in"] = true,
  108.     ["local"] = true,
  109.     ["nil"] = true,
  110.     ["not"] = true,
  111.     ["or"] = true,
  112.     ["repeat"] = true,
  113.     ["return"] = true,
  114.     ["then"] = true,
  115.     ["true"] = true,
  116.     ["until"]= true,
  117.     ["while"] = true,
  118. }
  119.  
  120. local function tryWrite( sLine, regex, colour )
  121.     local match = string.match( sLine, regex )
  122.     if match then
  123.         if type(colour) == "number" then
  124.             term.setTextColour( colour )
  125.         else
  126.             term.setTextColour( colour(match) )
  127.         end
  128.         term.write( match )
  129.         term.setTextColour( textColour )
  130.         return string.sub( sLine, string.len(match) + 1 )
  131.     end
  132.     return nil
  133. end
  134.  
  135. local function writeHighlighted( sLine )
  136.     while string.len(sLine) > 0 do 
  137.         sLine =
  138.             tryWrite( sLine, "^%-%-%[%[.-%]%]", commentColour ) or
  139.             tryWrite( sLine, "^%-%-.*", commentColour ) or
  140.             tryWrite( sLine, "os", osColor ) or
  141.             tryWrite( sLine, "paintutils", osColor ) or
  142.             tryWrite( sLine, "shell", osColor) or
  143.             tryWrite( sLine, "term", termColor ) or
  144.             tryWrite( sLine, "peripheral", peripheralColor ) or
  145.             tryWrite( sLine, "rednet", rednetColor ) or
  146.             tryWrite( sLine, "print", aColor ) or
  147.             tryWrite( sLine, "^\".-[^\\]\"", stringColour ) or
  148.             tryWrite( sLine, "^\'.-[^\\]\'", stringColour ) or
  149.             tryWrite( sLine, "^%[%[.-%]%]", stringColour ) or
  150.             tryWrite( sLine, "^[%w_]+", function( match )
  151.                 if tKeywords[ match ] then
  152.                     return keywordColour
  153.                 end
  154.                 return textColour
  155.             end ) or
  156.             tryWrite( sLine, "^[^%w_]", textColour )
  157.     end
  158. end
  159.  
  160. local function redrawText()
  161.     for y=1,h-1 do
  162.         term.setCursorPos( 1 - scrollX, y )
  163.         term.clearLine()
  164.  
  165.         local sLine = tLines[ y + scrollY ]
  166.         if sLine ~= nil then
  167.             writeHighlighted( sLine )
  168.         end
  169.     end
  170.     term.setCursorPos( x - scrollX, y - scrollY )
  171. end
  172.  
  173. local function redrawLine(_nY)
  174.     local sLine = tLines[_nY]
  175.     term.setCursorPos( 1 - scrollX, _nY - scrollY )
  176.     term.clearLine()
  177.     writeHighlighted( sLine )
  178.     term.setCursorPos( x - scrollX, _nY - scrollY )
  179. end
  180.  
  181. local function setLeftStatus()
  182. end
  183.  
  184. local function redrawMenu()
  185.     term.setCursorPos( 1, h )
  186.     term.clearLine()
  187.  
  188.     local sLeft, sRight
  189.     local nLeftColour, nLeftHighlight1, nLeftHighlight2
  190.     if bMenu then
  191.         local sMenu = ""
  192.         for n,sItem in ipairs( tMenuItems ) do
  193.             if n == nMenuItem then
  194.                 nLeftHighlight1 = sMenu:len() + 1
  195.                 nLeftHighlight2 = sMenu:len() + sItem:len() + 2
  196.             end
  197.             sMenu = sMenu.." "..sItem.." "
  198.         end
  199.         sLeft = sMenu
  200.         nLeftColour = textColour
  201.     else
  202.         sLeft = sStatus
  203.         nLeftColour = highlightColour
  204.     end
  205.    
  206.     -- Left goes last so that it can overwrite the line numbers.
  207.     sRight = "Ln "..y
  208.     term.setTextColour( highlightColour )
  209.     term.setCursorPos( w-sRight:len() + 1, h )
  210.     term.write(sRight)
  211.  
  212.     sRight = tostring(y)
  213.     term.setTextColour( textColour )
  214.     term.setCursorPos( w-sRight:len() + 1, h )
  215.     term.write(sRight)
  216.  
  217.     if sLeft then
  218.         term.setCursorPos( 1, h )
  219.         term.setTextColour( nLeftColour )
  220.         term.write(sLeft)      
  221.         if nLeftHighlight1 then
  222.             term.setTextColour( highlightColour )
  223.             term.setCursorPos( nLeftHighlight1, h )
  224.             term.write( "[" )
  225.             term.setCursorPos( nLeftHighlight2, h )
  226.             term.write( "]" )
  227.         end
  228.         term.setTextColour( textColour )
  229.     end
  230.    
  231.     -- Cursor highlights selection
  232.     term.setCursorPos( x - scrollX, y - scrollY )
  233. end
  234.  
  235. local tMenuFuncs = {
  236.     Save=function()
  237.         if bReadOnly then
  238.             sStatus = "Access denied"
  239.         else
  240.             local ok, err = save( sPath )
  241.             if ok then
  242.                 sStatus="Saved to "..sPath
  243.             else
  244.                 sStatus="Error saving to "..sPath
  245.             end
  246.         end
  247.         redrawMenu()
  248.     end,
  249.     Print=function()
  250.         local sPrinterSide = nil
  251.         for n,sSide in ipairs(rs.getSides()) do
  252.             if peripheral.isPresent(sSide) and peripheral.getType(sSide) == "printer" then
  253.                 sPrinterSide = sSide
  254.                 break
  255.             end
  256.         end
  257.        
  258.         if not sPrinterSide then
  259.             sStatus = "No printer attached"
  260.             return
  261.         end
  262.  
  263.         local nPage = 0
  264.         local sName = fs.getName( sPath )
  265.         local printer = peripheral.wrap(sPrinterSide)
  266.         if printer.getInkLevel() < 1 then
  267.             sStatus = "Printer out of ink"
  268.             return
  269.         elseif printer.getPaperLevel() < 1 then
  270.             sStatus = "Printer out of paper"
  271.             return
  272.         end
  273.        
  274.         local terminal = {
  275.             getCursorPos = printer.getCursorPos,
  276.             setCursorPos = printer.setCursorPos,
  277.             getSize = printer.getPageSize,
  278.             write = printer.write,
  279.         }
  280.         terminal.scroll = function()
  281.             if nPage == 1 then
  282.                 printer.setPageTitle( sName.." (page "..nPage..")" )           
  283.             end
  284.            
  285.             while not printer.newPage() do
  286.                 if printer.getInkLevel() < 1 then
  287.                     sStatus = "Printer out of ink, please refill"
  288.                 elseif printer.getPaperLevel() < 1 then
  289.                     sStatus = "Printer out of paper, please refill"
  290.                 else
  291.                     sStatus = "Printer output tray full, please empty"
  292.                 end
  293.    
  294.                 term.restore()
  295.                 redrawMenu()
  296.                 term.redirect( terminal )
  297.                
  298.                 local timer = os.startTimer(0.5)
  299.                 sleep(0.5)
  300.             end
  301.  
  302.             nPage = nPage + 1
  303.             if nPage == 1 then
  304.                 printer.setPageTitle( sName )
  305.             else
  306.                 printer.setPageTitle( sName.." (page "..nPage..")" )
  307.             end
  308.         end
  309.        
  310.         bMenu = false
  311.         term.redirect( terminal )
  312.         local ok, error = pcall( function()
  313.             term.scroll()
  314.             for n, sLine in ipairs( tLines ) do
  315.                 print( sLine )
  316.             end
  317.         end )
  318.         term.restore()
  319.         if not ok then
  320.             print( error )
  321.         end
  322.        
  323.         while not printer.endPage() do
  324.             sStatus = "Printer output tray full, please empty"
  325.             redrawMenu()
  326.             sleep( 0.5 )
  327.         end
  328.         bMenu = true
  329.            
  330.         if nPage > 1 then
  331.             sStatus = "Printed "..nPage.." Pages"
  332.         else
  333.             sStatus = "Printed 1 Page"
  334.         end
  335.         redrawMenu()
  336.     end,
  337.     Exit=function()
  338.         bRunning = false
  339.     end
  340. }
  341.  
  342. local function doMenuItem( _n )
  343.     tMenuFuncs[tMenuItems[_n]]()
  344.     if bMenu then
  345.         bMenu = false
  346.         term.setCursorBlink( true )
  347.     end
  348.     redrawMenu()
  349. end
  350.  
  351. local function setCursor( x, y )
  352.     local screenX = x - scrollX
  353.     local screenY = y - scrollY
  354.    
  355.     local bRedraw = false
  356.     if screenX < 1 then
  357.         scrollX = x - 1
  358.         screenX = 1
  359.         bRedraw = true
  360.     elseif screenX > w then
  361.         scrollX = x - w
  362.         screenX = w
  363.         bRedraw = true
  364.     end
  365.    
  366.     if screenY < 1 then
  367.         scrollY = y - 1
  368.         screenY = 1
  369.         bRedraw = true
  370.     elseif screenY > h-1 then
  371.         scrollY = y - (h-1)
  372.         screenY = h-1
  373.         bRedraw = true
  374.     end
  375.    
  376.     if bRedraw then
  377.         redrawText()
  378.     end
  379.     term.setCursorPos( screenX, screenY )
  380.    
  381.     -- Statusbar now pertains to menu, it would probably be safe to redraw the menu on every key event.
  382.     redrawMenu()
  383. end
  384.  
  385. -- Actual program functionality begins
  386. load(sPath)
  387.  
  388. term.setBackgroundColour( bgColour )
  389. term.clear()
  390. term.setCursorPos(x,y)
  391. term.setCursorBlink( true )
  392.  
  393. redrawText()
  394. redrawMenu()
  395.  
  396. -- Handle input
  397. while bRunning do
  398.     local sEvent, param, param2, param3 = os.pullEvent()
  399.     if sEvent == "key" then
  400.         if param == keys.up then
  401.             -- Up
  402.             if not bMenu then
  403.                 if y > 1 then
  404.                     -- Move cursor up
  405.                     y = y - 1
  406.                     x = math.min( x, string.len( tLines[y] ) + 1 )
  407.                     setCursor( x, y )
  408.                 end
  409.             end
  410.         elseif param == keys.down then
  411.             -- Down
  412.             if not bMenu then
  413.                 -- Move cursor down
  414.                 if y < #tLines then
  415.                     y = y + 1
  416.                     x = math.min( x, string.len( tLines[y] ) + 1 )
  417.                     setCursor( x, y )
  418.                 end
  419.             end
  420.         elseif param == keys.tab then
  421.             -- Tab
  422.             if not bMenu then
  423.                 local sLine = tLines[y]
  424.  
  425.                 -- Indent line
  426.                 -- IN CASE OF INSERT TAB IN PLACE:
  427.                 -- tLines[y] = string.sub(sLine,1,x-1) .. "  " .. string.sub(sLine,x)
  428.                 tLines[y]="  "..tLines[y]
  429.                 x = x + 2
  430.                 setCursor( x, y )
  431.                 redrawLine(y)
  432.             end
  433.         elseif param == keys.pageUp then
  434.             -- Page Up
  435.             if not bMenu then
  436.                 -- Move up a page
  437.                 local sx,sy=term.getSize()
  438.                 y=y-sy-1
  439.                 if y<1 then y=1 end
  440.                 x = math.min( x, string.len( tLines[y] ) + 1 )
  441.                 setCursor( x, y )
  442.             end
  443.         elseif param == keys.pageDown then
  444.             -- Page Down
  445.             if not bMenu then
  446.                 -- Move down a page
  447.                 local sx,sy=term.getSize()
  448.                 if y<#tLines-sy-1 then
  449.                     y = y+sy-1
  450.                 else
  451.                     y = #tLines
  452.                 end
  453.                 x = math.min( x, string.len( tLines[y] ) + 1 )
  454.                 setCursor( x, y )
  455.             end
  456.         elseif param == keys.home then
  457.             -- Home
  458.             if not bMenu then
  459.                 -- Move cursor to the beginning
  460.                 x=1
  461.                 setCursor(x,y)
  462.             end
  463.         elseif param == keys["end"] then
  464.             -- End
  465.             if not bMenu then
  466.                 -- Move cursor to the end
  467.                 x = string.len( tLines[y] ) + 1
  468.                 setCursor(x,y)
  469.             end
  470.         elseif param == keys.left then
  471.             -- Left
  472.             if not bMenu then
  473.                 if x > 1 then
  474.                     -- Move cursor left
  475.                     x = x - 1
  476.                 elseif x==1 and y>1 then
  477.                     x = string.len( tLines[y-1] ) + 1
  478.                     y = y - 1
  479.                 end
  480.                 setCursor( x, y )
  481.             else
  482.                 -- Move menu left
  483.                 nMenuItem = nMenuItem - 1
  484.                 if nMenuItem < 1 then
  485.                     nMenuItem = #tMenuItems
  486.                 end
  487.                 redrawMenu()
  488.             end
  489.         elseif param == keys.right then
  490.             -- Right
  491.             if not bMenu then
  492.                 if x < string.len( tLines[y] ) + 1 then
  493.                     -- Move cursor right
  494.                     x = x + 1
  495.                 elseif x==string.len( tLines[y] ) + 1 and y<#tLines then
  496.                     x = 1
  497.                     y = y + 1
  498.                 end
  499.                 setCursor( x, y )
  500.             else
  501.                 -- Move menu right
  502.                 nMenuItem = nMenuItem + 1
  503.                 if nMenuItem > #tMenuItems then
  504.                     nMenuItem = 1
  505.                 end
  506.                 redrawMenu()
  507.             end
  508.         elseif param == keys.delete then
  509.             -- Delete
  510.             if not bMenu then
  511.                 if  x < string.len( tLines[y] ) + 1 then
  512.                     local sLine = tLines[y]
  513.                     tLines[y] = string.sub(sLine,1,x-1) .. string.sub(sLine,x+1)
  514.                     redrawLine(y)
  515.                 elseif y<#tLines then
  516.                     tLines[y] = tLines[y] .. tLines[y+1]
  517.                     table.remove( tLines, y+1 )
  518.                     redrawText()
  519.                     redrawMenu()
  520.                 end
  521.             end
  522.         elseif param == keys.backspace then
  523.             -- Backspace
  524.             if not bMenu then
  525.                 if x > 1 then
  526.                     -- Remove character
  527.                     local sLine = tLines[y]
  528.                     tLines[y] = string.sub(sLine,1,x-2) .. string.sub(sLine,x)
  529.                     redrawLine(y)
  530.            
  531.                     x = x - 1
  532.                     setCursor( x, y )
  533.                 elseif y > 1 then
  534.                     -- Remove newline
  535.                     local sPrevLen = string.len( tLines[y-1] )
  536.                     tLines[y-1] = tLines[y-1] .. tLines[y]
  537.                     table.remove( tLines, y )
  538.                     redrawText()
  539.                
  540.                     x = sPrevLen + 1
  541.                     y = y - 1
  542.                     setCursor( x, y )
  543.                 end
  544.             end
  545.         elseif param == keys.enter then
  546.             -- Enter
  547.             if not bMenu then
  548.                 -- Newline
  549.                 local sLine = tLines[y]
  550.                 local _,spaces=string.find(sLine,"^[ ]+")
  551.                 if not spaces then
  552.                     spaces=0
  553.                 end
  554.                 tLines[y] = string.sub(sLine,1,x-1)
  555.                 table.insert( tLines, y+1, string.rep(' ',spaces)..string.sub(sLine,x) )
  556.                 redrawText()
  557.            
  558.                 x = spaces+1
  559.                 y = y + 1
  560.                 setCursor( x, y )
  561.             else
  562.                 -- Menu selection
  563.                 doMenuItem( nMenuItem )
  564.             end
  565.         elseif param == keys.leftCtrl or param == keys.rightCtrl then
  566.             -- Menu toggle
  567.             bMenu = not bMenu
  568.             if bMenu then
  569.                 term.setCursorBlink( false )
  570.                 nMenuItem = 1
  571.             else
  572.                 term.setCursorBlink( true )
  573.             end
  574.             redrawMenu()
  575.         end
  576.        
  577.     elseif sEvent == "char" then
  578.         if not bMenu then
  579.             -- Input text
  580.             local sLine = tLines[y]
  581.             tLines[y] = string.sub(sLine,1,x-1) .. param .. string.sub(sLine,x)
  582.             redrawLine(y)
  583.        
  584.             x = x + string.len( param )
  585.             setCursor( x, y )
  586.         else
  587.             -- Select menu items
  588.             for n,sMenuItem in ipairs( tMenuItems ) do
  589.                 if string.lower(string.sub(sMenuItem,1,1)) == string.lower(param) then
  590.                     doMenuItem( n )
  591.                     break
  592.                 end
  593.             end
  594.         end
  595.        
  596.     elseif sEvent == "mouse_click" then
  597.         if not bMenu then
  598.             if param == 1 then
  599.                 -- Left click
  600.                 local cx,cy = param2, param3
  601.                 if cy < h then
  602.                     y = math.min( math.max( scrollY + cy, 1 ), #tLines )
  603.                     x = math.min( math.max( scrollX + cx, 1 ), string.len( tLines[y] ) + 1 )
  604.                     setCursor( x, y )
  605.                 end
  606.             end
  607.         end
  608.        
  609.     elseif sEvent == "mouse_scroll" then
  610.         if not bMenu then
  611.             if param == -1 then
  612.                 -- Scroll up
  613.                 if scrollY > 0 then
  614.                     -- Move cursor up
  615.                     scrollY = scrollY - 1
  616.                     redrawText()
  617.                 end
  618.            
  619.             elseif param == 1 then
  620.                 -- Scroll down
  621.                 local nMaxScroll = #tLines - (h-1)
  622.                 if scrollY < nMaxScroll then
  623.                     -- Move cursor down
  624.                     scrollY = scrollY + 1
  625.                     redrawText()
  626.                 end
  627.                
  628.             end
  629.         end
  630.     end
  631. end
  632.  
  633. -- Cleanup
  634. term.clear()
  635. term.setCursorBlink( false )
  636. term.setCursorPos( 1, 1 )
RAW Paste Data