tomtrein

Untitled

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