ZNZNCOOP

edit

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